最近在学习 Pwn-stack-ROP 基础。 在 ctf-w iki 上面有讲解到: bamboofox 中的 ret2syscall 这道题。 不过我没有明白原文中的一些操作,很迷茫,所以就仔细去分析一下。 首先 file 和 checksec
有用的信息:0x0:ELF 32-bit LSB executable //32位的ELF文件0x1:NX: NX enabled //开启了NX保护,不能采用跳板入栈执行代码了,因为不可执行,所以栈溢出我们采用ROP技术。然后我进行程序功能分析:
一个输入点,和之前的题一样,然后使用IDA32来分析分析:
和前ctf-wiki前面的题一样,gets()栈溢出,不过我们这次不能像以前一样利用自己写在栈里面的代码获取 shell 了,因为上面已经提到的NX保护措施,那我们就用ROP。所以我们对付这个程序就使用系统调用来获取shell,正常情况下,是这样的:execve("/bin/sh",NULL,NULL)按照ctf-wiki中的详细叙述是这样的:这个程序是32位的,所以我们需要让:0x0:系统调用号即eax应该为0xb0x1:第一个参数即ebx应该指向/bin/sh的地址,其实执行sh的地址也可以0x2:第二个参数即ecx应该为00x3:第三个参数edx应该为0后面我就不太明白为什么要那样去写exp了,比较迷惑,所以:打开了我以前画过的堆栈变化图以及我以前写的小程序片段(Win7/vc6.0环境):
在 C语言 的程序的函数调用的时候,栈会有一个平衡的概念,我称之为:堆栈平衡。而在vc6.0中默认使用的__cdcel就是典型的外平栈。如果这个程序在call完了之后add esp,number 来进行 堆栈平衡 的话,就是__cdcel调用方式。
但是我在IDA和gdb进行反汇编之后在main函数中并没有发现类似于:add esp,number这样去平衡堆栈的汇编指令,那我只能认为这里使用的是__stdcall,也就是我称之为“内平栈”,那我们要证实这一点,需要去gdb里面找到证据:
Bingo,这里我也彻底明白了内外平栈和函数调用的一个小关系。那么这个gets()函数在ret之后,esp指向的就应该是原esp+0x4,而我们控制ret地址也能将其指向其他的地址去继续执行。等等…我刚才研究了那么久的内外平栈,我ret了之后和他们没有关系了啊!(震惊没事,继续。这里引用一句名言“在Pwn的时候,你的脑子就要像CPU和内存一样执行下面的代码并预知结果 ——鲁迅”再看一遍我们需要的目标0x0:系统调用号即eax应该为0xb0x1:第一个参数即ebx应该指向/bin/sh的地址,其实执行sh的地址也可以0x2:第二个参数即ecx应该为00x3:第三个参数edx应该为0那我们去找需要控制eax的gadgets:
0x080bb196是pop_eax_ret的gadgets,将这个地址放到ret_addr中,跳过去,那么pop的值就是ret+0x4,我们写上0xb,而pop_eax_ret执行完之后,会ret到当前esp中存放的值(解析为地址)去,所以我们直接在ret+0x8放入下个gadgets的地址。我们需要改变ebx,ecx,edx,如法炮制:
幸运的是,0x0806eb90 : pop edx ; pop ecx ; pop ebx ; ret可以直接操作三个pop,都正好是我们需要的,但是我们一定要注意我们放参数的顺序。edx,ecx,ebx应该这样。对应的参数是:0,0,/bin/sh的地址那么我们现在的Payload是这样了:
我们需要找到字符串为/bin/sh的gadgets
然后我们需要遵从 linux 中系统调用的结束中断:
让最后是int 0x80:
刚刚好,0x08049421 : int 0x80有了。那么程序在我们脑子里面就是这样:
应该这就能有shell了,我的exp学习了ctf-wiki中的写法:
然后:
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。