Command Line
放入IDA分析伪代码:
1 | int __cdecl main(int argc, const char **argv, const char **envp) |
可以知道该程序输出了v4的地址,然后我们使用checksec查看程序是否存在RWX段:
发现是存在RWX段的,然后在IDA中调试程序,使用Ctrl+s,查看printf打印出地址,发现地址所在栈是RWX的。因此很容易想到直接栈溢出然后劫持RIP,运行一段shellcode即可。因为v4距离RBP差16字节,所以返回地址(shellcode在栈中的地址)为程序打印出来的地址加上32(插入shellcode)字节的位置。exp如下:
1 | from pwn import * |
apprentice_www
首先checksec查看这个文件,发现没有RWX段。放入IDA,分析伪代码:
1 | int __cdecl main(int argc, const char **argv, const char **envp) |
main函数里面很简单,调用了alarm函数反调试,同时调用了setup和butterflySwag函数。然后查看这两个函数
1 | //setup() |
看到setup函数后,发现调用了mprotect函数,setup函数的作用就是将0x8048000~0x804a000段都改为RWX段。于是有一个模糊思路,就是栈溢出劫持eip然后在RWX段上执行shellcode。
1 | int butterflySwag() |
可以看到v1所在地址被1字节的v2赋值,为了分析的更清晰,于是查看其汇编代码:
分析到080485D2处的时候,我们可以看到该处dl寄存器的值赋值给了eax所存储的地址处。其中edx的值是v2,eax的值是v1。那么我们想到,可以利用这段代码,将想要修改的地址修改成我们想要的东西。如果要输入一段shellcode,我们可以使用scanf来进行输入,所以我们注意到080485D9处的jnz指令,只要合理修改jnz的操作数,就可以直接跳到0804859D也就是第一个scanf前,然后输入shellcode。因为jnz的操作数是8位带符号数,所以我们计算出080485D9-0804859D = ffc2,所以只需要将jnz指令后的操作数改为c2就可以了。然后因为分析代码可知,我们将v1用来存储地址,v2用来存放将会在地址上赋值的内容。所以shellcode只能每次输入一个字节。所以需要不断跳到scanf直到输入完整的shellcode。然后再修改jnz指令,跑完程序。exp如下:
1 | #!/usr/bin/python |