ZCTF-2017 比賽總結

Ox9A82發表於2017-02-28

這次ZCTF辦的還是相當不錯的,至少對於Pwn來說是能夠讓人學習到一些東西。
第一天做的不是很順利,一直卡在一道題上不動。第二天隊友很給力,自己的思路也開闊起來了。

關於賽題的優點

我覺得這次的Pwn300-class是一道比較有意思的題,整數溢位並不難找。比賽過程中可以很快的發現這個漏洞,但是接下來的利用比較頭疼,我一直到比賽結束都未能想到是透過setjmp這個函式進行利用的。
這是我第一次見到setjmp這個函式,透過writeup我瞭解了一下這個函式是以一個緩衝區來儲存跳轉的目的地址的,這一點有點像執行緒切換的上下文context。當時我直接把它當成goto也沒有詳加了解就略過了。
此外這道題還有一個點比較有意思,就是利用atoi函式的一個特性:

引數nptr字串,如果第一個非空格字元存在,是數字或者正負號則開始做型別轉換,==之後檢測到非數字(包括結束符 \0) 字元時停止轉換==,返回整型數。否則,返回零,

當遇到非數字字元時會停止轉換,這點也是我沒有意識到的,利用這一點可以使用atoi的棧空間進行gadgets的佈局。


此外透過sandbox這道題學習了一波linux的父-子程式除錯機制。因為我是搞Windows底層出身的,對於Linux的各種機制不是很熟悉,這次學習了一下。

ptrace 的使用流程一般是這樣的:父程式 fork() 出子程式,子程式中執行我們所想要 trace 的程式,在子程式呼叫 exec() 之前,子程式需要先呼叫一次ptrace,以 PTRACE_TRACEME 為引數。這個呼叫是為了告訴核心,當前程式已經正在被traced,當子程式執行 execve() 之後,子程式會進入暫停狀態,把控制權轉給它的父程式(SIG_CHLD訊號), 而父程式在fork()之後,就呼叫 wait()等待子程式停下來,當 wait() 返回後,父程式就可以去檢視子程式的暫存器或者對子程式做其它的事情了。
當系統呼叫發生時,核心會把當前的%eax中的內容(即系統呼叫的編號)儲存到子程式的使用者態程式碼段中(USER SEGMENT or USER CODE),我們可以像上面的例子那樣透過呼叫Ptrace(傳入PTRACE_PEEKUSER作為第一個引數)來讀取這個%eax的值,當我們做完這些檢查資料的事情之後,透過呼叫ptrace(PTRACE_CONT),可以讓子程式重新恢復執行。

這道題基本上就是這樣的流程
fork出的子程式首先呼叫PTRACE_TRACEME向父程式宣告,然後透過execl加上argv路徑執行沙盒中的程式。
而父程式則是監視子程式的呼叫,一旦超出限制就會結束程式。


還有就是Pwn200-login,比賽第一天的時候我和隊友一直在往爆破上面想,現在想來也是比較弱智的。。因為第一不能確定是否是fork的程式,第二是有alarm怎麼可能爆破的出來。後來晚上晨升牛說可以往字串漏洞上搞。自己試了一下發現的確可以,搞出了任意地址寫,但是沒能找出可以leak的地方,然後晨升牛已經拿到flag了。。ORZ解題真是太快了。透過這道題學到的就是格式化函式可以透過分段格式化進行利用,這個以前也是沒有遇到過的。

最後就是題量還是比較足的,考察點很多。

一些不足

因為很快自己也要給XCTF出題,所以這裡記錄一下。
第一是型別還是比較單一的,基本上都是NX+CANARY的情形,到自己出題時一定要注意一下出一些其它保護的繞過考察,比如地址無關。
第二是感覺題目還是為了出題而出題,這一點老外的比賽做的比較好,希望輪到自己時可以改進。

其它

這次比賽下來感覺自己的水平還是與dalao們有一些差距,一些思路難以第一時間反應過來,幸好搞Pwn的隊友們相當給力,尤其是晨升牛各種秒題ORZ...,成績還是相當不錯,Nu1L這次第三,與第一名只有一兩道題的差距。這次比賽自己的產出不是很多,比較慚愧,希望下次能夠為隊伍做更大的貢獻,也希望Nu1L下次可以拿到第一。