ZCTF-2017 比赛总结

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

posted @ 2017-02-28 19:10  Ox9A82  阅读(1686)  评论(3编辑  收藏  举报