2020KCTF春季赛 第二题 子鼠开天 WP
2020-04-19 06:47:08 Author: bbs.pediy.com(查看原文) 阅读量:233 收藏

[原创]2020KCTF春季赛 第二题 子鼠开天 WP

1天前 44

[原创]2020KCTF春季赛 第二题 子鼠开天 WP

文章里分析的是初版,也就是有多解的版本。

直接把程序拉到IDA,分析main函数,伪代码如下

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v3; // eax
  unsigned int namelen; // kr04_4
  int result; // eax
  char name[97]; // [esp+8h] [ebp-12Ch]
  __int16 v7; // [esp+69h] [ebp-CBh]
  char v8; // [esp+6Bh] [ebp-C9h]
  char sn[197]; // [esp+6Ch] [ebp-C8h]
  __int16 v10; // [esp+131h] [ebp-3h]
  char v11; // [esp+133h] [ebp-1h]

  name[0] = 0;
  sn[0] = 0;
  memset(&name[1], 0, 0x60u);
  v7 = 0;
  v8 = 0;
  memset(&sn[1], 0, 0xC4u);
  v10 = 0;
  v11 = 0;
  v3 = time(0);
  sub_411AD8(v3);
  printf(aEnterYourName);
  scanf(Format, name);
  namelen = strlen(name) + 1;
  if ( namelen - 1 < 3 || namelen - 1 > 0x14 )  // 判断name的长度
  {
    printf(aBadName);
    result = -1;
  }
  else
  {
    printf(aEnterYourSn);
    scanf(Format, sn);
    if ( strlen(sn) == 64 )                     // sn长度是否为64
    {
      checksn((int)name, namelen - 1, (int)sn, 64);
      result = 0;
    }
    else
    {
      printf(aBadSn);
      result = -1;
    }
  }
  return result;
}

关键函数为checksn,伪代码如下

void __cdecl checksn(int name, unsigned int namelen, int sn, int snlen)
{
  int hash[4]; // [esp+4h] [ebp-70h]
  char deresult[32]; // [esp+14h] [ebp-60h]
  char v6; // [esp+34h] [ebp-40h]
  char aesdecrypt; // [esp+54h] [ebp-20h]

  if ( namelen >= 3 && namelen <= 0x14 && snlen == 64 )
  {
    if ( hexstrtodata((_WORD *)sn, 64, (int)&v6) != 32
      || (aes((int)&v6, 32, (int)&aesdecrypt, (int)&key, 128, 0),
          RSA_decrypt((int)&aesdecrypt, 32, (int)deresult),
          deresult[0])                          // aes+rsa
      || deresult[1] != 2
      || deresult[15] )
    {
      printf(aBadSn);
    }
    else
    {
      gethash((const void *)name, namelen, (int)hash);
      if ( !memcmp(hash, &deresult[16], 0x10u) )// 比较后0x10字节是否相同
        printf(aCongratulation);
    }
  }
}

sn先把hex字符串转成数据,再用AES和RSA解密,需要注意的是解密后的结果是0x20字节,最后比较的字节数只有0x10。

所以需要把解密结果的前0x10字节跟"KCTF"的hash拼接,再加密就可以得到flag了。

aes函数的最后一个参数是判断加解密的标志,改1就是加密。然后从RSA_decrypt函数里提取N和E,分解N得到P Q,算出D就可以了。

RSA的部分,用python实现

rsa_e = 0x10001
rsa_d = 0x390A684CB713378FFD5CCE8C4000B5D6A2BB9F29B63D395E6BE6E9DD941527BD
rsa_mod = 0x69823028577465AB3991DF045146F91D556DEE8870845D8EE1CD3CF77E4A0C39
result = pow(0x00025D343CED2E5A3CD5FE94CEA1570014AF58AD4D76D59D8D2171FFB4CA2231,
             rsa_d, rsa_mod)
print hex(result)

00025D343CED2E5A3CD5FE94CEA15700 是前0x10字节

14AF58AD4D76D59D8D2171FFB4CA2231 是"KCTF"的hash

把得到的结果再AES加密就可以了。

flag:6ED8BC1F04D0C360567FB579398265FEEC8B48DC4B804904FEB1AB538C823270

由于初版程序只判断了dereuslt的[0] [1] [15],所以其他位置可以随便填充数据,出现多解。

[求职]想求职找工作,请来看雪招聘投递简历!


文章来源: https://bbs.pediy.com/thread-258932.htm
如有侵权请联系:admin#unsafe.sh