L3HCTF 2025

TemporalParadox(350Pt 38/167)

Solve

  1. 去花后,f5即可反汇编
    image-5
  2. 可以看到在特定的时间戳会输出不同的内容,patch一下运行就去,会的得到quary与其hash值,其中salt不变,t为当前时间戳
    image-6
    image-7 image-8 image-9
  3. 动调分析一下,得知sub_140001963()为makequary函数,进入分析r,a,b...的值如何计算,发现与sub_1400014D5()函数相关,该函数中的dword_14000B040变量动调可知为t.
    image-10
    __int64 sub_1400014D5()
    {
      unsigned int v1; // [rsp+Ch] [rbp-4h]
    
      v1 = (((dword_14000B040 << 13) ^ (unsigned int)dword_14000B040) >> 17) ^ (dword_14000B040 << 13) ^ dword_14000B040;
      dword_14000B040 = (32 * v1) ^ v1;
      return dword_14000B040 & 0x7FFFFFFF;
    }
    
  4. 根据makequary函数,爆破2中时间戳即可
    #include <iostream>  
    #include <cstdint>  
    #include "md5.h"  
    #include <cstring>  
      
    using namespace std;  
      
    //n1751990400 > 1751990400 && n1751990400 <= 1752052051  
    uint32_t t;  
      
    int __cdecl userrand() {  
        unsigned int v1; // [rsp+Ch] [rbp-4h]  
      
        v1 = (((t << 13) ^ (unsigned int) t) >> 17) ^ (t << 13) ^ t;  
        t = (32 * v1) ^ v1;  
        return t & 0x7FFFFFFF;  
    }  
      
    void makeQuery(char *query, uint32_t t) {  
        uint32_t a = 0;  
        uint32_t b = 0;  
        uint32_t x = 0;  
        uint32_t y = 0;  
        for (int i = 0; i < userrand(); ++i) {  
            a = userrand();  
            b = userrand();  
            x = userrand();  
            y = userrand();  
        }  
        uint32_t r = userrand();  
        sprintf(query, "salt=tlkyeueq7fej8vtzitt26yl24kswrgm5&t=%d&r=%d&a=%d&b=%d&x=%d&y=%d", t, r, a, b, x, y);  
    }  
      
      
    int main() {  
        string target = "8a2fc1e9e2830c37f8a7f51572a640aa";  
        for (int i = 1751990400; i < 1752052051; ++i) {  
            t = i;  
            char query[120];  
            string hash;  
            makeQuery(query, i);  
            MD5 md5(query);  
            md5.getDigest();  
            hash = md5.toStr();  
            if (hash == target) {  
                cout <<"Find "<< query;  
            }  
        }  
    }
    
    // Find salt=tlkyeueq7fej8vtzitt26yl24kswrgm5&t=1751994277&r=101356418&a=1388848462&b=441975230&x=1469980073&y=290308156
    //sha1 5cbbe37231ca99bd009f7eb67f49a98caae2bb0f
    
  5. 故flag为:
    L3HCTF{5cbbe37231ca99bd009f7eb67f49a98caae2bb0f}
    

What I have learned

  1. ida中x64的_fastcall调用约定
    image-2
    在实际调用时,貌似没有用到rdi与esi,例如下图是求rdi的size但实际返回值确实rcx的size
    image-4
    实际上在windows文档中
    整数参数在寄存器 RCX、RDX、R8 和 R9 中传递。 浮点数参数在 XMM0L、XMM1L、XMM2L 和 XMM3L 中传递。
    image-3|607x482
    而 x86 模式下 __fastcall 调用约定指定尽可能在寄存器中传递函数的自变量。此调用约定仅适用于 x86 体系结构。以下列表显示此调用约定的实现。

    元素 实现
    参数传递顺序 在自变量列表中按从左到右的顺序找到的前两个 DWORD 或更小自变量将在 ECXEDX 寄存器中传递;所有其他自变量在栈上从右向左传递。

    x86存在多种调用约定,常见的有cdecl (C规范) / stdcall(WinAPI默认) / fastcall 函数调用约定。
    x64的调用约定只有一种fastcall,windows与linux略有不同
    详细见 https://www.cnblogs.com/shines77/p/3788514.html

  2. windows中c调用md5加密:https://github.com/JieweiWei/md5
    CMakeLists中add_executable()中添加MD5.cpp
    image-11|684x312

  3. md5加密的标志

    v250[23] = 0;
    v250[19] = 0x67452301;
    v250[20] = 0xEFCDAB89;
    v250[21] = 0x98BADCFE;
    v250[22] = 0x10325476;
    

    image-2

posted @ 2025-08-18 17:13  Un1corn  阅读(19)  评论(0)    收藏  举报