CTF缓冲区溢出Exploit问题:如何避免触发地雷并获取Flag?
绕过Mine检查+缓冲区溢出拿Flag的实操思路
1. 先搞清楚Mine的检查规则
你得从给定的C代码里揪出Mine相关的逻辑——之前用反向字符串失败,大概率是搞反了检查要求:程序可能需要输入的对应段和原Mine字符串完全一致,而非逆序,或者你算错了要覆盖的位置。
举个常见的代码场景:
char mine[] = "ctfmine12345678"; // 假设是16字节固定串 // 检查逻辑示例 if (strcmp(buffer + 80, mine) != 0) { // 从缓冲区第80位开始匹配mine puts("Boom! Mine triggered"); exit(1); }
这种情况下必须在输入的对应位置填原串,而非逆序。
2. 重新确认栈布局
用GDB仔细梳理栈结构:
- 输入缓冲区的起始地址、Mine在栈上的位置、返回地址的位置。你说触发段错误的偏移是104,说明从缓冲区开头到返回地址前一个字节共104字节,Mine大概率在缓冲区和返回地址之间。
- 可以输入已知字符串(比如104个'A'加4个'B'),然后用
x/200x $esp(32位)或x/200x $rsp(64位)查看栈内容,确认Mine字段被覆盖的位置,精准算出偏移量。
3. 构造正确的Payload
核心构造逻辑:
- 填充垃圾字符(比如'A')到Mine字段的起始位置,长度为缓冲区到Mine开头的偏移量。
- 原封不动填入程序定义的Mine字符串,长度必须完全匹配,才能通过检查。
- 如果Mine和返回地址之间存在栈帧基址,用垃圾字符(比如'B')填充对应字节数(32位占4字节,64位占8字节)。
- 最后将返回地址替换为Win函数的内存地址(用GDB执行
p win即可获取,比如32位的0x08048567)。
32位程序Payload示例:
假设:
- 缓冲区到Mine开头偏移为80字节
- Mine字符串为
"ctfmine12345678"(16字节) - 栈帧基址占4字节
- Win函数地址为
0x08048567
用Python构造:
from pwn import * payload = b'A'*80 # 填充至Mine起始位置 payload += b'ctfmine12345678' # 填入原Mine串绕过检查 payload += b'B'*4 # 填充栈帧基址 payload += p32(0x08048567) # 写入Win函数地址(小端序打包)
常见坑点排查:
- Mine长度错误:比如Mine是16字节却只填了15个字符,检查直接失败;通过代码里的
sizeof(mine)确认长度,注意字符串末尾的\0是否被纳入检查。 - 偏移计算错误:通过GDB查看栈内实际覆盖情况,对比输入的已知字符串,修正偏移量。
- 字节序问题:64位程序中Win函数地址需用
p64()打包为小端序(x86架构均为小端)。
4. 验证Payload
用GDB加载程序,输入构造好的Payload,确认是否绕过Mine检查并成功跳转至Win函数。若失败,检查是否开启额外保护(CTF题通常关闭ASLR;NX保护不影响合法Win函数的执行)。
5. 获取Flag
Payload执行成功后,Win函数会读取flag.txt并输出Flag内容。
内容的提问来源于stack exchange,提问作者anonymous
相关产品推荐
相关产品推荐

