1. 程式人生 > >BSides Delhi CTF 2018部分pwn題題解

BSides Delhi CTF 2018部分pwn題題解

這個是一個比較基礎的國際賽,做完之後的感覺就是其中有些題目很有價值,可以順便補充一些訊號機制、uaf使用的知識。

canary

這個題目比較簡單,就是一個普通的stack smash並沒有什麼特別的,這裡直接上解題思路了

解題思路

因為開啟了canary,而且flag檔案是載入到了bss段之中,所以可以利用_stackchk_failed函式進行一個flag的洩漏,洩漏方式就是覆蓋arg引數,這個函式就會打印出我們想要的flag了(原始碼的分析可以參考ctfwiki,這裡我就不做過多的分析了)

exp:

    from pwn import*
    p = process('./canary')
    context.log_level="debug"
    flag = 0x06010A0
    p.recv()
    payload = 'a'*0x178 + p64(flag)
    p.sendline(payload)
    p.interactive()

easypeasy

這是一道利用linux下訊號機制的題目

linux下訊號機制記錄

SIGHUP 1 A 終端掛起或者控制程序終止
SIGINT 2 A 鍵盤中斷(如break鍵被按下)
SIGQUIT 3 C 鍵盤的退出鍵被按下
SIGILL 4 C 非法指令
SIGABRT 6 C 由abort(3)發出的退出指令
SIGFPE 8 C 浮點異常
SIGKILL 9 AEF Kill訊號
SIGSEGV 11 C 無效的記憶體引用
SIGPIPE 13 A 管道破裂: 寫一個沒有讀埠的管道
SIGALRM 14 A 由alarm(2)發出的訊號
SIGTERM 15 A 終止訊號
SIGUSR1 30,10,16 A 使用者自定義訊號1
SIGUSR2 31,12,17 A 使用者自定義訊號2
SIGCHLD 20,17,18 B 子程序結束訊號
SIGCONT 19,18,25 程序繼續(曾被停止的程序)
SIGSTOP 17,19,23 DEF 終止程序
SIGTSTP 18,20,24 D 控制終端(tty)上按下停止鍵
SIGTTIN 21,21,26 D 後臺程序企圖從控制終端讀
SIGTTOU 22,22,27 D 後臺程序企圖從控制終端寫

這道題要用的就是sigalrm這個機制

signal函式

singal()函式宣告 void (signal(int sig, void (func)(int)))(int) ,第一個引數為要處理的訊號,第二個引數為處理方法

程式功能分析

main函式

其中有一個alarm,設定的時間是30秒,這在後面會用到 

child函式

這個函式的第一步先建立啦一個signal訊號函式,在有14訊號的時候就會對其進行返回,並且呼叫hander函式。然後在迴圈中進行賦值,賦給的值會放在bbs段上,如果滿足validatesyscallobj(v0)就會呼叫raise函式給程式返回一個14的訊號,從而呼叫signal函式。接下來我們看一下:validatesyscall

obj(v0)函式和hander函式 

validatesyscallobj函式

可以大概看一眼程式,發現當我們輸入的eax值為: 1,2,3,60時就會退出迴圈,然後進行一個raise函式

hander函式

有一個看起來像是系統呼叫的東西再點進去看看 這裡會把我們的輸入當作引數分別放進暫存器當中,然後執行一個系統呼叫,這裡我們可以利用這個特點,向rax寫入59(sys_execve函式的系統呼叫值),然後佈局一下引數,就可以執行我們的getshell函式啦。

解題思路

一、先佈局bss段的引數,第一個為59(sys_execve函式的系統呼叫值),第一個引數就可以是我們'/bin/sh'這個引數的地址
二、然後等30秒,就會執行alarm然後呼叫hander函式接著坐等shell啦。

exp:

from pwn import *
 context.log_level = 'debug'
 P = process("./easypeasy")
 def set_registers(rax, rdi, rsi,    rdx, rcx, r8, r9):
     p.sendafter('RAX: ', str(rax) + '\n')
     p.sendafter('RDI: ', str(rdi) + '\n')
     p.sendafter('RSI: ', str(rsi) + '\n')
     p.sendafter('RDX: ', str(rdx) + '\n')
     p.sendafter('RCX: ', str(rcx) + '\n')
     p.sendafter('R8: ', str(r8) + '\n')
     p.sendafter('R9: ', str(r9) + '\n')

set_registers(59, 
0x6010A0 + 0x20,0x0,0x0, u64('/bin/   sh\x00'),0,0)

data_bank

題目的名字叫做databank,是一個比較簡單的國際賽的題但是利用這個題可以複習一下uaf關於洩漏地址和改寫mallochook的知識。

程式功能分析

這裡沒有對程式進行去符號的處理還是很舒服的 可以大概知道,有add,edit,delete等常規的操作下面進行一一進行分析

add函式

這裡是讓我們自己輸入index(順序序列),然後自己決定大小,然後對我們的輸入的size有一個check,然後是輸入資料,其中get_inp就只是一個自定義的輸入函式,其中沒有什麼特別這裡就不截圖出來了

edit函式

這是一個對堆內容在次進行編輯的一個函式,其中可能存在uaf的漏洞

delete函式

是一個正常的刪除函式,有一個對Double free的檢查所以並沒有辦法進行Double free但是可以看見也沒有對index的指標進行清空所以存在uaf的漏洞。

view函式

迴圈堆進行輸入

exit函式

正常的退出函式

保護檢視

能開的保護基本是全上了

思路分析

先講幾個主要的保護繞過

pie繞過

首先我們申請一個small bin大小的堆塊,然後free掉,其會自己加入至unsortedbin中,fdnext和fdback都會指向libc,這個時候我們再申請一個合適大小的堆塊再view,就可以打印出地址了。(剛入啃的小白可以自己gdb除錯一下)

RELRO繞過

這個保護導致我們不能成功對got表進行一個寫的操作,但是我們可以利用對mallochook進行一個程式流的控制(ps:mallochook 是一個 libc 上的函式指標,呼叫 malloc 時如果該指標不為空則執行它指向的函式,可以通過寫 malloc_hook 來 getshell)

完整的利用過程

一、先進行資訊洩漏,這個題目比較坑需要申請兩個samll bin然後free掉才能有上圖的效果,但是不論如何可以洩漏就可以啦
二、尋找到malloc_hook位置之上可以利用的一個位置,需要繞過fastbin對size的一個檢查,讀者們可以參考一下2017-0ctf-babyheap對這個的繞過,這裡我就不多寫了。
三、OneGadget的寫入

總結

國際賽裡還是有很多對入坑不久的人很友善的比賽的,不是所有比賽都像hitcon,secon一樣的。。