首页
社区
课程
招聘
[原创]2020KCTF春季赛 第二题 子鼠开天 WP
发表于: 2020-4-17 12:11 3807

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

2020-4-17 12:11
3807

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

直接把程序拉到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了。
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,伪代码如下
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了。
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实现

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

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