首页
社区
课程
招聘
[原创] 签到题: 乱世鬼雄 wp
2019-9-14 13:49 2112

[原创] 签到题: 乱世鬼雄 wp

2019-9-14 13:49
2112

判胜条件

  1)若攻击方找出特定用户名(“KCTF”,不含引号)的序列号,经KCTF系统自动确认,将认定攻击方获胜;

【公开用户名及序列号】

用户名:5D78C3FDF21998AC

序列号:F3A0FD8D8DE1FEB889808A8FF2D7FDA2

// 该用户名为:SHA256(ZhonyaRing.exe)的前64bit的hex

// SHA256(ZhonyaRing.exe) = 0x5D78C3FDF21998AC6DBBD26611738A71F85D95B5719DEC088B6BC933084EFBE4


主函数: sub_4019D0

将用户名hex编码之后,与序列号进行异或

题目给出的用户名和序列号异或之后,得到的是

[esp+64]=[0019FE90 "其实我更喜欢孙坚"]=C6 E4 CA B5 CE D2 B8 FC CF B2 BB B6 CB EF BC E1

算是小彩蛋吧


通过IDA反编译出的伪代码来思考一下流程

 // 读取输入 
 printf_sub_401910("【请输入您的用户名与序列号】\n");
  printf_sub_401910("请输入用户名:");
  read_sub_401950("%16s", &username_xmmword_42130C, 17);
  v0 = strlen((const char *)&username_xmmword_42130C);
  sub_4029C0((__m128i *)((char *)&username_xmmword_42130C + v0), 0, 16 - v0);
  printf_sub_401910("请输入序列号:");
  v32 = 0;
  v30 = 0i64;
  v31 = 0i64;
  v33 = 0i64;
  v34 = 0i64;
  v35 = 0;
  serial_num_xmmword_4212F8 = 0i64;
  read_sub_401950("%33s", &v30, 33);
  ......  // 判断序列号是否合法,相关流程略去
  if ( v6 )
  {
    printf_sub_401910(" * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n");
    printf_sub_401910("【请输入合法序列号!】\n\n");       // 【请输入合法序列号!】
  }
  else
  {
    v22 = 0;
    v23 = 0;
    v24 = 0x67452301;
    v25 = 0xEFCDAB89;
    // 用户名和序列号异或得到v28
    v28 = _mm_xor_si128((__m128i)username_xmmword_42130C, (__m128i)serial_num_xmmword_4212F8); 
    v26 = 0x98BADCFE;
    v27 = 0x10325476;
    v29 = 0i64;
    // 对v28进行处理,最终处理为v17
    sub_401000((int)&v28, &v22, 0x10u);
    v7 = (v22 >> 3) & 0x3F;
    v8 = 120 - v7;
    v9 = 56 - v7;
    v10 = v7 < 56;
    v11 = (char *)&v22 + 1;
    if ( !v10 )
      v9 = v8;
    v12 = 0;
    do
    {
      v13 = *(v11 - 1);
      v11 += 4;
      v28.m128i_i8[v12] = v13;
      v28.m128i_i8[v12 + 1] = *(v11 - 4);
      v28.m128i_i8[v12 + 2] = *(v11 - 3);
      v28.m128i_i8[v12 + 3] = *(v11 - 2);
      v12 += 4;
    }
    while ( v12 < 8 );
    sub_401000((int)&unk_4208C0, &v22, v9);
    sub_401000((int)&v28, &v22, 8u);
    v14 = (char *)&v24 + 1;
    v15 = 0;
    do
    {
      v16 = *(v14 - 1);
      v14 += 4;
      *((_BYTE *)&v29 + v15) = v16;
      *((_BYTE *)&v29 + v15 + 1) = *(v14 - 4);
      *((_BYTE *)&v29 + v15 + 2) = *(v14 - 3);
      *((_BYTE *)&v29 + v15 + 3) = *(v14 - 2);
      v15 += 4;
    }
    while ( v15 < 0x10 );
    v17 = &v29;
    // 这里注意v18为固定值
    v18 = &byte_4208B0;
    v19 = 12;
    while ( *(_DWORD *)v17 == *(_DWORD *)v18 )
    {
      v17 = (__int128 *)((char *)v17 + 4);
      v18 += 4;
      v10 = v19 < 4;
      v19 -= 4;
      if ( v10 )
      {
        v20 = "【验证正确!】\n\n";                    // 【验证正确!】
        goto LABEL_22;
      }
    }
    v20 = "【验证错误!】\n\n";                        // 【验证错误!】
LABEL_22:
    printf_sub_401910(" * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n");
    printf_sub_401910(v20);
  }
  sub_40507E("\npause\n");
  return 0;

获取输入username,serial_num

v28 = username ^ serial_num

v17 = somechange(v28)

v18 = DAE52310067195714BA2CEE2332BB86680

if v17 == v18:

    成功

可以看到,不管输入是什么,v28必须是一个定值,才能使得最终的v17等于v18,而我们已经有了一组用户名密码,那就很容易得到v28,也就是那个小彩蛋

写代码获取'KCTF'的序列号

# coding:utf8

import re

v28 = 0xE1BCEFCBB6BBB2CFFCB8D2CEB5CAE4C6

username = 'KCTF'
reverse_hex_username = username[::-1].encode('hex')
username_num = int(reverse_hex_username, 16)

serial_num = v28 ^ username_num

tmp = hex(serial_num).upper()[2:-1]

# 调一下实际顺序
tt = re.findall(r'.{2}', tmp)
serial_str = ''
for t in tt[::-1]:
    serial_str += t
print serial_str

# 8DA79EF3CED2B8FCCFB2BBB6CBEFBCE1


[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界

收藏
点赞1
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回