这篇文章单独记录 Attack Lab。目标是理解栈溢出、返回地址、代码注入和 ROP,不把它和 Bomb Lab 混在一起。

0. 实验对象

Attack Lab 常见文件:

1
2
3
4
5
6
cookie.txt
ctarget
rtarget
farm.c
hex2raw
README.txt

含义:

  • ctarget:用于代码注入攻击
  • rtarget:用于返回导向编程,也就是 ROP
  • cookie.txt:验证用的十六进制数字
  • farm.c:ROP 可以利用的 gadget 来源
  • hex2raw:把十六进制文本转成真实字节输入

1. 最小工作流

1
2
./hex2raw < exploit.txt > exploit.raw
./ctarget -q -i exploit.raw

或者:

1
./hex2raw < exploit.txt | ./ctarget -q

含义:

  • exploit.txt:手写的十六进制攻击字符串
  • hex2raw:把文本转成原始字节
  • ctarget / rtarget:读取攻击输入

2. Level 1:覆盖返回地址

核心目标:

1
让 getbuf 返回时不要回到原来的位置,而是跳到 touch1

关键观察:

1
2
3
4
5
6
getbuf:
sub $0x28,%rsp
mov %rsp,%rdi
call Gets
add $0x28,%rsp
ret

0x28 是 40 字节。也就是说,输入超过 40 字节后,就会覆盖返回地址。

栈的大致形状:

1
2
3
4
高地址
返回地址
buffer 40 字节
低地址

如果把返回地址覆盖成 touch1 的地址,ret 就会跳到 touch1

touch2 需要一个参数:

1
2
3
4
5
6
void touch2(unsigned val)
{
if (val == cookie) {
validate(2);
}
}

x86-64 Linux 里,第 1 个参数放在 %rdi

所以攻击目标变成:

1
2
先把 cookie 放进 %rdi
再跳到 touch2

典型注入代码:

1
2
3
movq $cookie, %rdi
pushq $touch2
ret

ret 的本质:

1
2
3
从栈顶弹出 8 字节
把这个值当成下一条指令地址
跳过去执行

4. ROP 入门

ROP 是 Return-oriented Programming。

核心思想:

1
不注入新代码,而是利用程序里已有的小片段代码。

这些小片段叫 gadget,通常以 ret 结尾。

例如某段字节中可以截出:

1
2
movq %rax, %rdi
ret

就可以用它把 %rax 的值转移到 %rdi,再继续跳到下一个 gadget。

5. 复盘重点

Attack Lab 真正要训练的是:

  • 栈向低地址增长
  • ret 如何改变控制流
  • 返回地址为什么能被覆盖
  • 参数为什么要放进 %rdi
  • 小端序如何影响地址写法
  • 代码注入和 ROP 的区别