-
-
[原创] 签到题: 乱世鬼雄 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世界
赞赏
他的文章
看原图