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 byteold rbp ,到达返回地址处,覆盖上 buffer_addr ,结束

本地结果

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

image-20241015093658872

远程结果

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

image-20241015093143492

rop 实践 1

试验过程

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

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

先使用 pop rdish_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 函数对 gbufferread 操作提供了一片可操作的缓冲区,由此联想到 sbof2,我们可以尝试往 gbuffer 里填入 rop 链,然后让 func 返回地址覆盖为 gbuffer 地址

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

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

进入 func后,先填充缓冲区,覆盖 old rbpgbuffer 地址,覆盖返回地址为 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