CorCTF 2024 Rev DigestMe
字数 1430 2025-08-19 12:41:22

CorCTF 2024 DigestMe 逆向分析完整解析

题目概述

本题是CorCTF 2024中的一个逆向题目,名为"DigestMe"。题目描述了一位名为FizzBuzz101的开发者在编写一个秘密编译器时电脑被Crowdstrike攻击,恢复密钥被放在他自己编写的一个哈希器中。挑战者需要逆向分析这个哈希器来获取恢复密钥。

初步分析

文件特征

  • 程序是一个非常大的C代码编译而成
  • IDA反编译提示函数过大(0x1090到0xED97F,约90万行汇编)
  • 代码分为两部分:
    1. 开头的普通处理逻辑
    2. 大量重复的操作序列

初始逆向技巧

  1. Patch技巧:将程序中间某处patch成ret,阻断IDA对后续逻辑的分析,以便使用F5查看简化逻辑
  2. 输入验证分析
    • 输入必须以"corctf{"开头,以"}"结尾
    • 输入长度至少18个字符(从s[7]~s[17])
    • 特定约束关系:
      s[8] == s[17]
      s[9] == s[11]
      s[7] == s[16] + 1
      s[14] == s[16] + 4
      
    • 循环边界表明输入长度很可能是19字节

深入逆向分析

内存操作模式

程序对一个大内存空间(称为tmp或v3)进行大量操作,主要分为四种类型:

  1. 与操作:两个32字节连续内存空间的与处理
  2. 或操作:两个32字节连续内存空间的或处理
  3. 异或操作:两个32字节连续内存空间的异或处理
  4. 混合操作:与/或/异或处理,同时混入0B40h和0B41h进行操作

加法运算识别

通过分析汇编代码,发现以下模式:

mov cl, [rax+87h]
xor cl, [rax+7]     ; a[af] = a[87]^a[7]
mov [rax+0A7h], cl

mov cl, [rax+87h]
and cl, [rax+7]     ; a[B40] = a[87]&a[7]
mov [rax+0B40h], cl

mov cl, [rax+86h]
xor cl, [rax+6]     ; a[b41] = a[86]^a[6]
mov [rax+0B41h], cl

mov cl, [rax+0B41h]
xor cl, [rax+0B40h] ; a[ae] = a[b40]^a[b41]
mov [rax+0A6h], cl

这实际上是模拟加法运算:

  • a[87]^a[7]:当前位的和
  • a[87]&a[7]:进位位
  • 将进位影响下一位的运算

数据排列方式

  • 单个数据按小端序排列
  • 4个数字也按小端序排序
  • 示例:
    0x1000000: [0 0 0 0 1 0 0 1] [1 0 0 0 1 0 1 0]  # a[0] = 0x9, a[1] = 0x8a
    0x1000008: [0 0 0 0 1 0 0 0] [1 0 0 0 1 0 0 0]  # a[2] = 0x8, a[3] = 0x88
    组合后: a = 0x88088a09
    

循环位移操作

发现代码中存在循环右移操作:

mov cl, [rax+98h]
or cl, [rax+118h]
mov [rax+0CCh], cl

实际操作为:

def rotate_right(num, shift_amount):
    shift_amount = shift_amount % 32
    return (num >> shift_amount) | (num << (32 - shift_amount)) & 0xFFFFFFFF

其中shift_amount由被操作数和操作数的偏移计算得出:

def reverse_origin_offset(offset):
    return (offset//8)*8 + (8 - (offset%8))

算法识别

MD5特征值

在dump出的数据中发现MD5的魔数:

  • 0xd76aa478
  • 0xe8c7b756
  • 其他MD5特征常量

MD5变换函数对比

程序逻辑与MD5的md5_transform函数高度相似:

static void md5_transform(const unsigned char block[64]) {
    int i, j;
    UINT4 a,b,c,d,tmp;
    const UINT4 *x = (UINT4 *) block;
    
    a = state[0];
    b = state[1];
    c = state[2];
    d = state[3];
    
    /* Round 1 */
    for (i = 0; i < 16; i++) {
        tmp = a + F(b, c, d) + le32_to_cpu(x[i]) + T[i];
        tmp = ROTATE_LEFT(tmp, s1[i & 3]);
        tmp += b;
        a = d; d = c; c = b; b = tmp;
    }
    /* 类似结构处理Round 2-4 */
    
    state[0] += a;
    state[1] += b;
    state[2] += c;
    state[3] += d;
}

最终验证

程序最后比较两个特定的哈希值:

cmp dword ptr [rsp+4C8h+var_4A8+8], 19C603BAh  ; tmp[2] == 0xba03c619
cmp dword ptr [rsp+4C8h+var_4A8+0Ch], 14353CE4h ; tmp[3] == 0xe43c3514

解题方法

约束条件总结

  1. 输入格式:corctf{...},长度19字节
  2. 有效内容长度:11字节(扣除固定部分)
  3. 特定约束:
    • flag[8] == flag[17]
    • flag[9] == flag[11]
    • flag[7] == flag[16] + 1
    • flag[14] == flag[16] + 4

爆破策略

由于Z3求解器无法在合理时间内解决(约1e12种可能性),采用CUDA加速爆破:

  1. 修改CUDA MD5爆破工具

    • 调整初始化逻辑以匹配题目要求
    • 修改MD5计算函数以包含特定填充规则
  2. 关键修改点

    // 设置映射关系
    char mapping_index[8] = {0,1,2,3,5,6,8};
    
    // 应用约束条件
    threadTextWord[9] = threadTextWord[0] - 1;
    threadTextWord[7] = threadTextWord[9] + 4;
    threadTextWord[10] = threadTextWord[1];
    threadTextWord[4] = threadTextWord[2];
    
    // 修改MD5填充
    vals[i / 4] |= 0x80 << ((i % 4) * 8);
    vals[56 / 4] |= 0x58 << ((56 % 4) * 8);
    
  3. 目标哈希

    • 查找产生特定MD5部分哈希(0xba03c619, 0xe43c3514)的输入

最终结果

经过约3小时的CUDA爆破,得到有效输入:

cPv3v8VfWbP

完整flag:

corctf{youtu.be/dQw4w9WgXcQ}

总结

  1. 逆向技巧

    • 对超大函数使用分段分析
    • 识别重复模式并自动化处理
    • 通过对比调试验证算法理解
  2. 算法识别

    • 注意特征常量和数据结构
    • 对比已知算法(如MD5)的结构
  3. 解题策略

    • 当符号执行不可行时,考虑约束爆破
    • 利用GPU加速大规模计算
  4. 工具使用

    • IDA Python脚本自动化分析
    • CUDA编程实现高性能计算

本题展示了现代CTF逆向题目的典型特点:需要结合逆向工程、算法识别和高效计算技术才能解决。

CorCTF 2024 DigestMe 逆向分析完整解析 题目概述 本题是CorCTF 2024中的一个逆向题目,名为"DigestMe"。题目描述了一位名为FizzBuzz101的开发者在编写一个秘密编译器时电脑被Crowdstrike攻击,恢复密钥被放在他自己编写的一个哈希器中。挑战者需要逆向分析这个哈希器来获取恢复密钥。 初步分析 文件特征 程序是一个非常大的C代码编译而成 IDA反编译提示函数过大(0x1090到0xED97F,约90万行汇编) 代码分为两部分: 开头的普通处理逻辑 大量重复的操作序列 初始逆向技巧 Patch技巧 :将程序中间某处patch成ret,阻断IDA对后续逻辑的分析,以便使用F5查看简化逻辑 输入验证分析 : 输入必须以"corctf{"开头,以"}"结尾 输入长度至少18个字符(从s[ 7]~s[ 17 ]) 特定约束关系: 循环边界表明输入长度很可能是19字节 深入逆向分析 内存操作模式 程序对一个大内存空间(称为tmp或v3)进行大量操作,主要分为四种类型: 与操作 :两个32字节连续内存空间的与处理 或操作 :两个32字节连续内存空间的或处理 异或操作 :两个32字节连续内存空间的异或处理 混合操作 :与/或/异或处理,同时混入0B40h和0B41h进行操作 加法运算识别 通过分析汇编代码,发现以下模式: 这实际上是模拟加法运算: a[ 87]^a[ 7 ]:当前位的和 a[ 87]&a[ 7 ]:进位位 将进位影响下一位的运算 数据排列方式 单个数据按小端序排列 4个数字也按小端序排序 示例: 循环位移操作 发现代码中存在循环右移操作: 实际操作为: 其中 shift_amount 由被操作数和操作数的偏移计算得出: 算法识别 MD5特征值 在dump出的数据中发现MD5的魔数: 0xd76aa478 0xe8c7b756 其他MD5特征常量 MD5变换函数对比 程序逻辑与MD5的 md5_transform 函数高度相似: 最终验证 程序最后比较两个特定的哈希值: 解题方法 约束条件总结 输入格式: corctf{...} ,长度19字节 有效内容长度:11字节(扣除固定部分) 特定约束: flag[ 8] == flag[ 17 ] flag[ 9] == flag[ 11 ] flag[ 7] == flag[ 16 ] + 1 flag[ 14] == flag[ 16 ] + 4 爆破策略 由于Z3求解器无法在合理时间内解决(约1e12种可能性),采用CUDA加速爆破: 修改CUDA MD5爆破工具 : 调整初始化逻辑以匹配题目要求 修改MD5计算函数以包含特定填充规则 关键修改点 : 目标哈希 : 查找产生特定MD5部分哈希(0xba03c619, 0xe43c3514)的输入 最终结果 经过约3小时的CUDA爆破,得到有效输入: 完整flag: 总结 逆向技巧 : 对超大函数使用分段分析 识别重复模式并自动化处理 通过对比调试验证算法理解 算法识别 : 注意特征常量和数据结构 对比已知算法(如MD5)的结构 解题策略 : 当符号执行不可行时,考虑约束爆破 利用GPU加速大规模计算 工具使用 : IDA Python脚本自动化分析 CUDA编程实现高性能计算 本题展示了现代CTF逆向题目的典型特点:需要结合逆向工程、算法识别和高效计算技术才能解决。