Codegate 2017 Qual-babypwn-writeup
分析
基本功能
题目提供了一个32位的程序。参数传递用栈来进行。用gdb载入后看一下保护措施,如下:
用IDA打开进行分析。文件实现了一个socket服务。其真正的服务函数如下:
整体上看,实现了三个功能,第一个是读入(sub_8048907)输入的数据并输出来(sub_8048907)。第二个功能是Reverse Echo,好像没啥用。第三个功能是退出。
在Echo功能的sub_8048907(&v2, 0x64u);
中:
将读入的字符通过recv()函数拷贝到数组v2中,读入的字符长度可以达到0x64即100个字节。而数组v2所在的位置为 bp-34h ,0x34 = 52。所以很明显这里存在栈溢出。但因为开了Canary保护,因此如果要利用栈溢出,就需要泄露Canary值或者其他技术。
接下去看输出函数sub_80488B1(&v2);
中:
将数组v2的内容发送出去,发送数据的长度由strlen()指定。
泄露canary
接下来我们考虑如何泄露Canary值。Canary值的第一个字节总是\x00
,加上是小端序。数组v2在一开始通过memset(&v2, 0, 0x28u);
进行初始化。所以结合两者情况,栈的分布约莫下;
当我们输入的字符个数少于0x28时,比如aaa
,则v2中的第四个字符是\x00
,则strlen(v2)就为3。如下:
最后返回输出为字符串“aaa”。
但若我们输入的字符个数等于0x28时,由于后面的数据是canary值。此时:
对于数组v2而言,canary的第一个字节\x00
成了它的结束标志。在strlen时会把canary值得长度加上,在最后返回输出时将canary的值打印出来。从而完成对canary的泄露。
泄露出canary后就该考虑如何进行栈溢出利用。程序中提供了system函数。但若要getshell,我们还需要/bin/sh
字符串,及其他一些操作。
泄露libc
为得到/bin/sh
字符串的地址,我们可以去泄露出libc版本。
考虑到有send(fd, a1, v2, 0)函数,我们只要让fd为4(默认值),a1为libc库函数的got地址,设置v2为4,第四个为0,就能够将libc库函数的地址打印出来。通过泄露几个libc库函数的地址就能得到libc版本,并利用偏移计算出/bin/sh
字符串的地址。
假如我要泄露setsockopt函数的地址。可以构造payload如下:
其中注意第二行使用了前面得到的canary值。然后我们加上了12个a
,这样才能将返回地址覆盖为send_sym_addr的地址。根据32位程序的栈布局,接下来是send()函数调用完后的返回地址,为进一步利用,这里选择回到有漏洞的服务(8048A71)处。再接下来依次是send函数的四个参数。
在发送完payload后,我们还需要在程序选项中输入一次3
,选择功能3. Exit\n
,这样程序才能执行到ret,即被我们覆写了的返回地址。所以需要发送第二段payload:
getshell
在成功获得libc版本后,现在已经有了system函数,和/bin/sh
字符串,但还不能获得shell。因为程序本身是一个socket服务器,所以它的默认文件描述符不是标准输入输出流0或1,而是4,这也是前面调用send函数时第一个参数为4的原因。我们可以使用dup2函数来复制文件描述符,重定向输入输出流。
dup2函数的原型如下:
所以对应的,在getshell之前,我们要把原本的文件描述符重定向到标准输入输出流。对应payload为:
exp
|
|