這次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下次可以拿到第一。