比赛结束快一个星期了,复现了一下这道题,借鉴了一下网上的wp发现大佬们写的都很简略,所以这里写一个详细的wp供小白们学习。
来自于csapp: int open(char *filename,int flags,mode_t mode)这里主要关注flags参数
这里我们将会用到的参数是O_TRUNC
大致分析一下可以发现程序需要我们输入选项,类似于一个堆的功能。然后如果我们输入666就会进入一个比较重要的函数,我这里将其改名成了important。
这个函数是让我们输入一个值,会作为文件secret中字符串进行md5加密的次数。然后再让我们输入一个字符串与加密的secret字符串进行对比如果成立那么就进入下一个函数,我这里把他命名为了exploit。
它会先打印出我们在important函数中输入的name(可以leak出canary),然后调用snprintf函数(tips:snprintf函数的返回值是我们输入的字符串的长度),然后下面有一个read函数,read的长度参数是由我们控制的(见上面tips的内容),这里我们就可以进行栈溢出。
大概的想法就是先进入important函数,再进入exploit函数利用栈溢出getshell
上面的小知识里讲了read函数的参数问题,这里看下文件的read参数flag处为553(这里有一个坑的一点,我之前一直不明白,ida是把O_WRONLY | O_TRUNC进行了抑或后的结果直接显示出来了513,不过可能看客大佬们的ida可能会显示011000这个表示的意思是一样的。)
因为次数是一个int类型可以包含负数,而在对比中第一次和其对比的是int类型而第二次其对比的是个unsignedint类型,只要我们输入-1那么和unsignedint进行对比时会转化为很大的一个数,程序会运行一段时间。这个时候我们开启第二段进程,读取已经被读取的文件secret的时候就会读到'\0'(文件被截断),然后我们再次输入'\0'的md5加密后的字符串就可以成功绕过进入下一个函数了。
第一步我们先泄漏处canary的值,具体就是利用第一个printf泄漏处canary,然后利用snprintf输入我们的长度(长度没有限制,只要够我们放我们的rop就可以了)。然后就是很常规的栈溢出,泄漏地址(给了我们libc文件)直接计算偏移,然后利用rop拿到shell
题目一路坐下来可以感觉pwn对计算机系统的了解程度还是很高的,不然都不知道md5可以这么绕过。