Skip to content

lab-01: 缓冲区溢出

:material-circle-edit-outline: 约 892 个字 :material-clock-time-two-outline: 预计阅读时间 3 分钟

俞仲炜 3220104929 241015

注:关于源代码文件名中最后一个字母,l 指攻击本地文件的,r 指远程攻击的

stack buffer overflow 实践

试验过程

反汇编 sbof2,发现栈帧大小为 0x110

image-20241022092018101

缓冲区大小为 0x100 ,从 [rbp-0x100] 开始

image-20241022090613324

我们需要将返回地址覆盖为缓冲区起始地址,以此为起点设计 payload

现在 payload 里放 shellcode 用于执行,再填充剩余的缓冲区,即 256 - len(shellcode)

再覆盖 8 byte 的 old rbp ,到达返回地址处,覆盖上 buffer_addr ,结束

本地结果

结果截图如下图,执行 ls 指令后,成功输出当前目录所有文件

image-20241015093658872

远程结果

与本地攻击思路一致,不同的是需先通过 remote() 进行连接,并发送学号

image-20241015093143492

rop 实践 1

试验过程

反汇编可知 func 栈帧大小为 0x50,我们可以通过类似 sbof2 的攻击方式覆盖掉返回地址,但是 target_code 函数里面的执行的是 ls,不是我们想要的

正好程序里的 gstr 存有我们要的字符串,于是 rop 链的思路就有了:

先使用 pop rdi 将 sh_addr 放入 rdi 寄存器,然后调用 system 函数,传入 rdi 中的参数,由此大功告成

发现使用 find_gadget(['pop rdi', 'ret']) 会失败,而将 ret 地址单独加入则没问题,从逻辑上似乎一致,只是多覆盖了 8 字节,查阅资料发现可能是 x86_64 对栈帧有 16 字节对齐的要求

栈的字节对齐,实际是指栈顶指针必须是16字节的整数倍。

https://www.cnblogs.com/tcctw/p/11333743.html

本地结果

结果截图如下图,执行 ls 指令后,成功输出当前目录所有文件

image-20241018181313124

远程结果

与本地攻击思路一致,不同的是需先通过 remote() 进行连接

话说为什么还是 ssec2023 hhhh

image-20241018181116442

rop 实践 2

试验过程

注意看,main 函数对 gbuffer 的 read 操作提供了一片可操作的缓冲区,由此联想到 sbof2,我们可以尝试往 gbuffer 里填入 rop 链,然后让 func 返回地址覆盖为 gbuffer 地址

而 func 内的 read 函数正好溢出 0x10,足够我们覆盖返回地址,使用栈迁移将栈指针指向 gbuffer

首先往 gbuffer 填充 rop 链,思路是先放入 "/bin/sh" 字符串,这样就能用 gbuff_addr 的地址调用这个字符串了,然后用 pop rdi 传入这个字符串,再连续两个 ret 以执行 system

进入 func后,先填充缓冲区,覆盖 old rbp 为 gbuffer 地址,覆盖返回地址为 leave, ret,首先 func 本身的 leave,ret 会将 rbp 指向 guffer,并执行我们覆盖的 leave,ret ,

接下来 leave 会使 rsp 指向 gbuffer,然后ret 指令开始执行 pop rdi,注意这里 rsp 上移并不会清除栈上的数据

本地结果

结果截图如下图,执行 ls 指令后,成功输出当前目录所有文件

image-20241022104759827

远程结果

image-20241022105105395

以下为个人一点点感想,可以忽略不看

本人是 CS 大三的,见培养方案专业选修课有这门课,感觉很好玩就选了,但由于没有 x86 的汇编知识(实际上 riscv 也不怎么会),感觉这门课和啃压缩饼干一样hhhh,课堂小测基本不会,靠课后一边看智云一边查资料现学才弄懂,真的如传闻中的一样硬核,不过弄懂后确实感觉挺好玩的hhh