首页
论坛
课程
招聘
[原创]看雪.安恒2020 KCTF春季赛第二题 子鼠开天 WP
2020-4-16 23:15 6181

[原创]看雪.安恒2020 KCTF春季赛第二题 子鼠开天 WP

2020-4-16 23:15
6181

看雪.安恒2020 KCTF春季赛第二题 子鼠开天 WP

刷了下手机看已经有人一血了。立马打开电脑开撸。
先看到题目里有sn.txt,先看了下:原来是新规则,提供了一组用户名及对应序列号,试运行下,是个控制台程序:

Enter your name: B1AC71D22D82EBB1
Enter your sn: 1788bdf0f45ff24515cfb9313f6519039c24c635ee518afc320b915ecdbf1613
Congratulations! You did it!

 

先静态分析下,主程序代码比较明了:

  name = 0;
  sn = 0;
  memset(&v7, 0, 0x60u);
  v8 = 0;
  v9 = 0;
  memset(&v11, 0, 0xC4u);
  v12 = 0;
  v13 = 0;
  v3 = time(0);
  sub_411AD8(v3);
  print_411A90((int)aEnterYourName);
  scanf(aS, &name);
  v4 = strlen(&name) + 1;
  if ( v4 - 1 < 3 || v4 - 1 > 20 )
  {
    print_411A90((int)aBadName);
    result = -1;
  }
  else
  {
    print_411A90((int)aEnterYourSn);
    scanf(aS, &sn);
    if ( strlen(&sn) == 64 )
    {
      check_401380((int)&name, v4 - 1, (int)&sn, 64);
      result = 0;
    }
    else
    {
      print_411A90((int)aBadSn);
      result = -1;
    }
  }
  return result;

输入长度限制跳过,直接看check_401380函数。其伪代码如下,:

     if ( name_length >= 3 && name_length <= 20 && sn_length == 64 )
  {
    if ( unhex_401000((_WORD *)sn, 64, (int)&sn_unhex) != 32
      || (aes_4010F0((int)&sn_unhex, 32, (int)&sn_de, (int)key_4190D0, 128, 0), rsa_401210((int)&sn_de, 32, (int)m),m[0])
      || m[1] != 2
      || m[15] )
    {
      print_411A90((int)aBadSn);
    }
    else
    {
      hash_401190((const void *)name, name_length, (int)&hash);
      if ( !memcmp(&hash, &m[16], 0x10u) )
        print_411A90((int)aCongratulation);
    }
  }
}

校验的主要流程如下:

  1. 64字节序列号unhex成32字节
  2. AES解密32字节的处理后的序列号
  3. 解密后的结果进行RSA解密,并校验结果个别部分
  4. 对用户名进行hash计算,得到16字节hash
  5. 进行最后校验,即RSA的解密结果后16字节与hash比较

AES密钥是常量,RSA的N为256bits,可分解,用户名hash可以直接得到,似乎条件全了,可以由任意用户名求对应的序列号了。

 

在最后的求解过程中还遇到了点问题,因为rsa计算结果前16字节只校验了三个字节,那不是多解了,而且预设的序列号怎么求呢。想到题目提供的序列号是能过前面的check的,所以直接把它的rsa计算结果的前16字节直接拿来用试试,提交了下还对了。

 

晚上回来又把hash部分看了下:

signed int __cdecl hash_401190(const void *a1, unsigned int a2, int a3)
{
  char v4; // [esp+8h] [ebp-DCh]
  int v5; // [esp+18h] [ebp-CCh]
  char v6; // [esp+1Ch] [ebp-C8h]

  qmemcpy(&v6, a1, a2);
  *(int *)((char *)&v5 + a2 + 4) = g_suffix1_41D038;
  sha256_md5_4010B0((int)&v6, a2 + 4, (int)&v4);
  v5 = g_suffix2_41D030;
  sha256_md5_4010B0((int)&v4, 20, a3);
  return 16;
}

解题脚本为:

  key = [0x48, 0x0B, 0x62, 0xC3, 0xAC, 0xD6, 0xC8, 0xA3, 0x6B, 0x18, 0xD9, 0xE9, 0x06, 0xCD, 0x90, 0xD2]
  key = ''.join(map(chr,key))
  name = 'KCTF'
  c = md5(sha512(md5(sha512(name+'DEEDBEEF'.decode('hex')).digest()).digest()+'B979379E'.decode('hex')).digest()).hexdigest()
  c = (0x00025D343CED2E5A3CD5FE94CEA15700<<128)+int(c,16)
  n = 0x69823028577465ab3991df045146f91d556dee8870845d8ee1cd3cf77e4a0c39
  p = 201522792635114097998567775554303915819
  q = 236811285547763449711675622888914229291  
  e = 65537
  d = invert(e,(p-1)*(q-1))
  m = powmod(c,d,n)
  m = hex(m)[2:].rjust(64,'0').decode('hex')
  ci = AES.new(key,AES.MODE_ECB)
  flag = ci.encrypt(m).encode('hex').upper()
  print flag

结果为:6ED8BC1F04D0C360567FB579398265FEEC8B48DC4B804904FEB1AB538C823270


看雪侠者千人榜,看看你上榜了吗?

收藏
点赞0
打赏
分享
最新回复 (3)
雪    币: 221
活跃值: 活跃值 (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
homily 活跃值 2020-5-7 11:25
2
0
写的很简洁,但是这个静态分析用的是ida嘛,需要如何设置和操作。谢谢老板。
雪    币: 12005
活跃值: 活跃值 (238)
能力值: ( LV15,RANK:2427 )
在线值:
发帖
回帖
粉丝
poyoten 活跃值 22 2020-5-13 11:50
3
0
homily 写的很简洁,但是这个静态分析用的是ida嘛,需要如何设置和操作。谢谢老板。
是IDA,好象不用特殊设置吧。。。
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
git_81232jnifree 活跃值 2020-7-15 11:53
4
0
你好 想请教下:
1.check_401380  中有个判断 if  (aes(xx),ras(yy))  两个函数放在元组里面 意思 两个函数 返回0值  这个区块才为否吗? 
2. 你是如何判断 每个参数是干什么的呢 。。
谢谢了。
游客
登录 | 注册 方可回帖
返回