首页
社区
课程
招聘
[原创]KCTF 2025 第3题 邪影显现wp
发表于: 2025-8-26 06:54 6172

[原创]KCTF 2025 第3题 邪影显现wp

2025-8-26 06:54
6172

放入ida分析主要验证函数, 函数开始就看到几个常数与"KCTF2025"字样, 搜索常数得知是md5:

结合KCTF2025md5_name与md5_name变量的位置看出是拼接出KCTF2025md5(name).
之后的逻辑比较长,调用了很多函数;
先从中间随便点进几个看看在做什么, 找到了一个比较有特征的函数:

在github上搜索MIRACL error from routine 找到了 548K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6E0K9i4u0S2j5$3I4Q4x3V1k6y4d9g2u0m8b7@1H3`.
对照发现该函数为MIRACL/source/mrcore.c中的mr_berror:

该库中的函数大量引用了mr_mip, 用ida File->Load File->Parse C header file加载库中定义了miracl结构的miracl.h来还原mr_mip的符号, 之后发现结构体成员位置不太对, 还需要对比添加一个padding:

MIRACL库中很多函数在入口处使用了MR_IN(x)x为唯一的数字, 长这样:

主要特征是MR_IN(x)对应mr_mip->trace[mr_mip->depth]=x, 于是在反编译代码中看到该特征对应搜索MR_IN(x)就能找到这是什么函数, 之后分析出验证函数中用了MIRACL库的部分流程如下:

做了一个指数为23的指数模逆.
验证函数之后又调用了许多其他未知的函数, 深入点进去找到了又一个特征点:

github上搜索"Integer: division by zero"找到了cryptopp. 这个库中的函数没有上一个库那么有特征, 但是根据其中调用了cpuid的一个函数能够找到DetectX86Features再找到SetFunctionPointers, 对比能够特定其中一些全局变量:

之后根据该信息可以找到RecursiveSquare:

然后可以找到调用了RecursiveSquareAsymmetricMultiply, 调用了AsymmetricMultiplyPositiveMultiply, 验证函数中使用的一个调用了PositiveMultiply的函数就是Multiply.
类似的从DivideByZero可以链式找到PositiveDivide, Integer::Divide, 以及验证函数中使用的Integer::Modulo函数, 分析出接下来它用cryptopp做了一个29的指数模逆.
之后其他的很多函数还是未知的, 点进去几个看看又找到了个新库libntl:

带着模逆运算的心理预期能够对比找到验证函数中调用的是ntl_gmulntl_gmodInvMod, 确认中间一段做了个37的指数模逆.
之后别的函数又是新的大数库, 在基本确认都在用某个库做指数模逆计算时,可以通过观察找到乘法函数与取模函数的输入输出,结合变量传递关系就可以找出某一段运算的指数, 分析出指数分别为[3,7,11,17,19,23,29,31,37];
对验证函数做逆运算即已知e与n计算x^e mod n的x, 是RSA算法;
从验证函数中找出模数n0x56f67550f16a00390dcf0b2715708e61c5b3f23101862fc1用factordb分解出p与q,计算d=invmod(e, (p-1)(q-1))
即可完成序列号的计算, 注意每轮之后最高位还需要-1:

...
v184 = 0;
memset(tmp_final, 0, sizeof(tmp_final));
memset(reverse_gcd, 0, sizeof(reverse_gcd));
a2[0] = 0x5075F656;
a2[1] = 0x39006AF1;
a2[2] = 0x270BCF0D;
a2[3] = 0x618E7015;
a2[4] = 0x31F2B3C5;
a2[5] = 0xC12F8601;
memset(&md5_name, 0, 0xF8u);
qmemcpy(KCTF2025md5_name, "KCTF2025", sizeof(KCTF2025md5_name));
v258 = 0;
*(_QWORD *)&v257.oword4C = 0xEFCDAB8967452301uLL;
*((_QWORD *)&v257.oword4C + 1) = 0x1032547698BADCFELL;
memset(&v257, 0, 12);
sub_41E530(&v257, name, strlen(name));
sub_41E660(&v257, &md5_name);                 // md5(name)
...
...
v184 = 0;
memset(tmp_final, 0, sizeof(tmp_final));
memset(reverse_gcd, 0, sizeof(reverse_gcd));
a2[0] = 0x5075F656;
a2[1] = 0x39006AF1;
a2[2] = 0x270BCF0D;
a2[3] = 0x618E7015;
a2[4] = 0x31F2B3C5;
a2[5] = 0xC12F8601;
memset(&md5_name, 0, 0xF8u);
qmemcpy(KCTF2025md5_name, "KCTF2025", sizeof(KCTF2025md5_name));
v258 = 0;
*(_QWORD *)&v257.oword4C = 0xEFCDAB8967452301uLL;
*((_QWORD *)&v257.oword4C + 1) = 0x1032547698BADCFELL;
memset(&v257, 0, 12);
sub_41E530(&v257, name, strlen(name));
sub_41E660(&v257, &md5_name);                 // md5(name)
...
void mr_berror(_MIPD_ int nerr)
/*  Big number error routine  */
#ifndef MR_STRIPPED_DOWN
int i;
#endif
 
#ifdef MR_OS_THREADS
    miracl *mr_mip=get_mip();
#endif
 
if (mr_mip->ERCON)
{
    mr_mip->ERNUM=nerr;
    return;
}
#ifndef MR_NO_STANDARD_IO
 
#ifndef MR_STRIPPED_DOWN
mputs((char *)"\nMIRACL error from routine ");
if (mr_mip->depth<MR_MAXDEPTH) mputs(names[mr_mip->trace[mr_mip->depth]]);
else                           mputs((char *)"???");
fputc('\n',stdout);
 
for (i=mr_mip->depth-1;i>=0;i--)
{
    mputs((char *)"              called from ");
    if (i<MR_MAXDEPTH) mputs(names[mr_mip->trace[i]]);
    else               mputs((char *)"???");
    fputc('\n',stdout);
}
 
switch (nerr)
{
case 1 :
mputs((char *)"Number base too big for representation\n");
break;
case 2 :
mputs((char *)"Division by zero attempted\n");
break;
case 3 :
mputs((char *)"Overflow - Number too big\n");
...
void mr_berror(_MIPD_ int nerr)
/*  Big number error routine  */
#ifndef MR_STRIPPED_DOWN
int i;
#endif
 
#ifdef MR_OS_THREADS
    miracl *mr_mip=get_mip();
#endif
 
if (mr_mip->ERCON)
{
    mr_mip->ERNUM=nerr;
    return;
}
#ifndef MR_NO_STANDARD_IO
 
#ifndef MR_STRIPPED_DOWN
mputs((char *)"\nMIRACL error from routine ");
if (mr_mip->depth<MR_MAXDEPTH) mputs(names[mr_mip->trace[mr_mip->depth]]);
else                           mputs((char *)"???");
fputc('\n',stdout);
 
for (i=mr_mip->depth-1;i>=0;i--)
{
    mputs((char *)"              called from ");
    if (i<MR_MAXDEPTH) mputs(names[mr_mip->trace[i]]);
    else               mputs((char *)"???");
    fputc('\n',stdout);
}
 
switch (nerr)
{
case 1 :
mputs((char *)"Number base too big for representation\n");
break;
case 2 :
mputs((char *)"Division by zero attempted\n");
break;
case 3 :
mputs((char *)"Overflow - Number too big\n");
...
char *__thiscall DivideByZero_407530(char *this)
{
  void *v2; // ecx
  void *Block[5]; // [esp+10h] [ebp-28h] BYREF
  unsigned int v5; // [esp+24h] [ebp-14h]
  int v6; // [esp+34h] [ebp-4h]
 
  Block[4] = 0;
  v5 = 15;
  LOBYTE(Block[0]) = 0;
  sub_416C40(Block, "Integer: division by zero", 0x19u);
  v6 = 0;
  *(_QWORD *)(this + 4) = 0LL;
  LOBYTE(v6) = 1;
  *(_DWORD *)this = &off_45BC60;
  *((_DWORD *)this + 3) = 6;
  sub_416DC0(Block);
  if ( v5 >= 0x10 )
  {
    v2 = Block[0];
    if ( v5 + 1 >= 0x1000 )
    {
      v2 = (void *)*((_DWORD *)Block[0] - 1);
      if ( (unsigned int)((char *)Block[0] - (char *)v2 - 4) > 0x1F )
        invalid_parameter_noinfo_noreturn();
    }
    sub_455F72(v2);
  }
  *(_DWORD *)this = &off_45BC60;
  return this;
}
char *__thiscall DivideByZero_407530(char *this)
{
  void *v2; // ecx
  void *Block[5]; // [esp+10h] [ebp-28h] BYREF
  unsigned int v5; // [esp+24h] [ebp-14h]
  int v6; // [esp+34h] [ebp-4h]
 
  Block[4] = 0;
  v5 = 15;
  LOBYTE(Block[0]) = 0;
  sub_416C40(Block, "Integer: division by zero", 0x19u);
  v6 = 0;
  *(_QWORD *)(this + 4) = 0LL;
  LOBYTE(v6) = 1;
  *(_DWORD *)this = &off_45BC60;
  *((_DWORD *)this + 3) = 6;
  sub_416DC0(Block);
  if ( v5 >= 0x10 )
  {
    v2 = Block[0];
    if ( v5 + 1 >= 0x1000 )
    {
      v2 = (void *)*((_DWORD *)Block[0] - 1);
      if ( (unsigned int)((char *)Block[0] - (char *)v2 - 4) > 0x1F )
        invalid_parameter_noinfo_noreturn();
    }
    sub_455F72(v2);
  }
  *(_DWORD *)this = &off_45BC60;
  return this;
}
void *__thiscall SetFunctionPointers(void *this)
{
  char v2; // al
  void *result; // eax
 
  if ( dword_464A74 )
    return this;
  v2 = g_x86DetectionDone;
  s_pMul[0] = (int)Baseline_Multiply2;
  s_pBot0 = (int)Baseline_MultiplyBottom2;
  s_pSqu0 = (int)Baseline_Square2;
  s_pTop0 = (int)Baseline_MultiplyTop2;
  s_pTop1 = (int)Baseline_MultiplyTop4;
  if ( !g_x86DetectionDone )
  {
    DetectX86Features();
    v2 = g_x86DetectionDone;
  }
  if ( !byte_464A71 )
  {
    dword_4652A8 = (int)sub_408040;
    dword_4652AC = (int)sub_4081D0;
    dword_4652CC = (int)sub_408FF0;
    dword_4652D0 = (int)sub_4090B0;
    dword_4652F0 = (int)sub_408850;
    dword_4652F4 = (int)sub_408A10;
    dword_465318 = (int)sub_409520;
    dword_464A74 = (int)sub_407C20;
    return this;
  }
  if ( !v2 )
    DetectX86Features();
  if ( g_isP4 )
  {
    s_pAdd = SSE2_Add;
    s_pSub = SSE2_Sub;
  }
  result = this;
  s_recursionLimit = 32;
...
}
void *__thiscall SetFunctionPointers(void *this)
{
  char v2; // al
  void *result; // eax
 
  if ( dword_464A74 )
    return this;
  v2 = g_x86DetectionDone;
  s_pMul[0] = (int)Baseline_Multiply2;
  s_pBot0 = (int)Baseline_MultiplyBottom2;
  s_pSqu0 = (int)Baseline_Square2;
  s_pTop0 = (int)Baseline_MultiplyTop2;
  s_pTop1 = (int)Baseline_MultiplyTop4;
  if ( !g_x86DetectionDone )
  {
    DetectX86Features();
    v2 = g_x86DetectionDone;
  }
  if ( !byte_464A71 )
  {
    dword_4652A8 = (int)sub_408040;
    dword_4652AC = (int)sub_4081D0;
    dword_4652CC = (int)sub_408FF0;
    dword_4652D0 = (int)sub_4090B0;
    dword_4652F0 = (int)sub_408850;
    dword_4652F4 = (int)sub_408A10;
    dword_465318 = (int)sub_409520;
    dword_464A74 = (int)sub_407C20;
    return this;

传播安全知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 1
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回