https://crackmes.one/crackme/5f4efbb133c5d4357b3b00a0
基本信息
| 项目 | 描述 |
|---|---|
| 文件 | date_of_birth |
| 类型 | ELF 64-bit LSB PIE executable, x86-64 |
| 链接 | dynamically linked |
| 编译器 | GCC 7.5.0 (Ubuntu 18.04) |
| 符号表 | stripped |
初步分析
strings 提取
1 | Welcome to Discard App -- a new way to get screwed up |
程序是一个虚构的 “Discard App”(Discord 谐音梗),要求输入生日来验证年龄。输入格式为 %m/%d/%Y(如 03/17/1898)。
导入函数
scanf— 读取用户输入strptime— 按%m/%d/%Y格式解析日期字符串mktime— 将struct tm转换为time_t时间戳time— 获取当前时间localtime— 将time_t转换回struct tmputs— 输出字符串
逆向分析
主函数流程 (0x710)
反编译后的伪代码:
1 | int main(int argc, char **argv) { |
关键设计:用 localtime 计算”年龄”
程序并未用常规方式(年份相减)计算年龄,而是:
- 计算
diff = time(NULL) - mktime(birth_date)(秒级时间差) - 对
diff调用localtime(),将其当作一个绝对时间戳来解析 - 从返回的
struct tm中提取tm_year、tm_mon、tm_mday - 用
tm_year - 70作为 “年龄”(因为tm_year是自 1900 年起的年数,减去 70 即以 1970 年/Unix 纪元为基准)
年龄验证的控制流
反汇编的核心比较逻辑:
1 | 0x7fb: lea 0x1(%r12),%eax ; eax = mday + 1 |
控制流图:
1 | 入口 |
漏洞:有符号字节溢出
所有通往 SUCCESS 的路径都要求某个值 大于其自身加一,这在正常情况下不可能。但程序使用 字节级比较(%al、%cl、%dl、%bpl、%r12b),这就引入了有符号整数溢出。
Path B2 的溢出利用
关键比较在 0x85c:
1 | lea 0x1(%rbx),%ecx ; ecx = age + 1 (32位运算) |
当 age = 127 (0x7F) 时:
| 变量 | 值 | 有符号字节解释 |
|---|---|---|
dl (age) |
0x7F |
+127 |
cl (age+1) |
0x80 |
-128 |
比较结果:cl (-128) > dl (127) → False! jg 不跳转。
cl (-128) >= dl (127) → False! jge 也不跳转。
于是 fall through 到 SUCCESS (0x862)!
触发条件
要到达 Path B2,还需要满足:
tm_mday >= 30(进入 Path B)tm_mon >= 11(即 12 月,进入 Path B2)tm_year - 70 = 127(触发字节溢出)
因此 localtime(diff) 必须返回:
| 字段 | 所需值 | 含义 |
|---|---|---|
tm_year |
197 | 年份 2097(1900+197) |
tm_mon |
11 | 12 月(0 索引) |
tm_mday |
>= 30 | 30 或 31 日 |
即时间差 diff 对应的绝对日期落在 2097 年 12 月 30-31 日。
求解
编写 C 程序暴力搜索满足条件的出生日期:
1 |
|
运行结果(2026-03-16):
1 | MATCH: 03/17/1898 -> age=127, mon=11, mday=31 |
注意:正确日期与运行时的当前时间有关,不同日期运行结果会不同。
Flag 生成函数 (0x9d0)
通过验证后,程序用日期信息构造 XOR 密钥来解密内置的编码字符串:
密钥构造
1 | ; 打包 tm 值到 rdi |
解密逻辑
1 | 0x9d0: mov %edi,%edx ; edx = packed_value |
密钥计算
对于 mday=31, mon=11, age=127:
1 | packed = 0x001F0B7F |
编码数据
函数中硬编码了以下数据(小端序排列):
1 | 0x10: 3e 05 0d 04 19 1f 1e 05 |
每个字节 XOR 0x6B:
1 | data = [0x3e,0x05,0x0d,0x04,0x19,0x1f,0x1e,0x05, |
运行结果
1 | $ echo "03/17/1898" | ./date_of_birth |
Flag: Unfortunately this app has absolutely no functionality
总结
| 要素 | 详情 |
|---|---|
| 漏洞类型 | 有符号字节溢出(Signed Byte Overflow) |
| 触发条件 | tm_year - 70 = 127 (0x7F),使 (age+1) 的低字节溢出为 0x80 (-128) |
| 所需输入 | 约 1898 年的出生日期(精确值取决于运行时间) |
| 解密方式 | 单字节 XOR,密钥由 tm_mday、tm_mon、tm_year 异或派生 |





