Skip to content

lab-02_ 格式化字符串漏洞

:material-circle-edit-outline: 约 690 个字 :fontawesome-solid-code: 9 行代码 :material-clock-time-two-outline: 预计阅读时间 2 分钟

[!ABSTRACT]

俞仲炜 3220104929 241117

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

FSB1

[!QUOTE]

请阅读 fsb1.c 的内容,在本地和远程服务上完成攻击(要求 getshell)。远程服务暴露在:

  • ip:8.154.20.109,port:10300

思路

首先通过 payload = b"ABCD.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p" 得到以下信息

ABCD.0x7ffcb329c020.0x80.0x7fa7e3665a61.0x20.(nil).0x7fa7e374e4e0.

0xbeaf.0x2e70252e44434241.0x70252e70252e7025.0x252e70252e70252e

由此确认 content 的偏移量为 8

参考 example.py 的思路,确定 payload 还需要填充 2 个 byte,进而可以确认两个 hn 的偏移量分别为 1112

address_of_var 12
address_of_var + 2 11
$hnA c%12 10
7667 hn%1 9
%11$ %17c 8(content)
beaf 7(x)

为检测 x 是否被正确修改,在 fsb1.c 中增加下面两条数据

if (x != 0xbeaf) {
    printf("debugging:");   // add
    printf("%x",x);         // add
    vuln_code();
}

下图中可看到 x 确实是 114514

image-20241117141028114

本地结果

成功拿 shell,执行 ls

image-20241117141055037

远程结果

image-20241117141810151

FSB2

[!QUOTE]

请阅读 fsb2.c 的内容,在本地和远程服务上完成攻击(要求 getshell)。远程服务暴露在: - ip:8.154.20.109,port:10301

[!TIP]

  • 攻击步骤: 1. 通过泄露 libc 函数来确定 libc 加载的虚拟地址,并通过计算拿到 system 的地址; 2. 覆盖 printf 的 GOT 表为 system; 3. 调用 printf 以触发 system 从而 getshell。
  • 你可以通过学习 pwntools 中 fmtstr 库 的相关 API 来简化攻击流程。

首先检查程序

image-20241118084356104

64 位,Partial RELRO 表明 GOT 可写,没有 Stack Canary,NX enabled 表明不能往 stack 注入代码来攻击,No PIE 则程序加载基址固定,等等

首先查看栈情况,输入 ABCD.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p\n 得到:

ABCD.0x7ffe776fbad0.0x100.0x7f356ec26a61.(nil).0x7f356ed2d380.0x2e70252e44434241.0x70252e70252e7025.0x252e70252e70252e.0x2e70252e70252e70.0x70252e70252e7025.0xa.(nil)

可见 buffer 偏移量为 6

我们希望找到 libc 里的 system 地址,但是我们只能获取 offset,基地址会改变

不过程序里使用 printf,我们可以通过 GOT 泄露其地址,减去其 offset,就解决了

payload = b""
payload += b"VVVV"
payload += b"%7$s"         # buffer 偏移量是 6,地址放第二个参数位置 
payload += p64(printf_got) # 防止被 0 截断 printf,地址后放

[!BUG] 32 位与 64 位的区别

上课一直在讲 32 位,作业环境是 64 位,如果没有扎实的基础就会遇到问题

像这里我一开始是先加的 p64 的 printf_got,然后没有填充字节就放入 %7$s ,导致偷偷填充的 0 截断了 payload,没有执行到 %7$s

得到了 printf_addr 就简单了,很容易算出 system_addr

然后使用 fmtstr_payload 自动构造覆盖 GOT 表的 payload,让下一次 printf 执行 system,并输入 /bin/sh\0,拿 shell

[!BUG]

我在写完代码后本地一直跑不通 ,最后发现是自己用 ELF 解析时,傻傻用了仓库提供的 libc.so,与我本地的版本不一样 T-T

本地结果

成功拿 shell,执行 ls

image-20241118115159907

远程结果

远程的 libc.so 使用仓库提供的 libc.so 版本

image-20241118115854943