看雪·深信服 2021 KCTF 春季赛 | 第四题设计思路及解析
2021-05-15 19:00:11 Author: mp.weixin.qq.com(查看原文) 阅读量:163 收藏

KCTF 看雪学院

跟随武林少侠“飞停”,我们一起来到第四关《英雄救美》,共有31支战队完成目标,成功营救「美女」。

金左手率先完成挑战,仅用时7582秒。辣鸡战队紧随其后,完成目标。本题目仅用时一天即挑战完成。

大家依然战斗力满满!接下来我们一起来看看本题的成功“秘诀”吧!

出题团队简介

由3位CR38同期学员组成,共同学习和提高二进制安全技术为目的,创建了WeTeam战队。

赛题设计思路

本题要求输入key字符串,正确弹出MessageBox,错误的key则不会弹出MessageBox。

本题中输入的key是9X9数独游戏(数独.png)的唯一解,此key会进行md5加密,得到的hash值会解密一段shellcode。错误的key则无法获得shellcode。

详细说明

9x9的数独存放在一个全局的二维数组中,破解者输入一串密钥。然后根据这个密钥转换为在这个数独中应该填写的数字,判断其行是否合法、列是否合法以及粗线宫是否合法。如果合法则计算其md5,然后aes解密shellcode。解密正确的话则会正常执行shellcode,从而弹出input correct的消息框,否则就没有这个消息框,自动退出程序了。

找到数独游戏图,然后得到唯一解。

正确的key

:u$YBPf2pa]Dt4#QM^H4ic'j0`w2y{d-Zzo2%/n_s@+2<UW)e4AR;F.4=-qEkvC2

数独游戏图

赛题解析

本赛题解析由看雪论坛 poyoten 给出:

试运行

此题是一个控制台程序,随便输入后,没有错误信息提示。

分析

程序的主业务流程全在主函数中,伪代码如下:
printf("\t\t\t看雪CTF大赛\r\n");printf("\t\t祝愿看雪CTF大赛越办越好\r\n");printf("Serial: ");scanf_s("%s", &input, 81);length = strlen(&input);if ( length <= 64 && check_group_401240(length, &input, v15) == 1 && check_sudoku_401000(v15, length - 9) == 1 ){  _mm_storeu_si128((__m128i *)&hash, (__m128i)0i64);  memset(&ctx, 0, 0x58u);  v14 = 0;  v13 = 0;  ctx = 0x67452301;  v10 = 0xEFCDAB89;  v11 = 0x98BADCFE;  v12 = 0x10325476;  md5_update_4014E0((int)&input, (int)&ctx, length);  md5_final_4015B0((int)&hash, (__m128i *)&ctx);  subkey_401ED0(v4, (unsigned __int8 *)&hash);  v8 = (void (*)(void))VirtualAlloc(0, 0x620u, 0x1000u, 0x40u);  v5 = (__m128i *)v8;  v6 = 0x62;  do  {    _mm_storeu_si128(v5, _mm_loadu_si128((__m128i *)((char *)v5 + &unk_4181A0 - (_UNKNOWN *)v8)));    AES_de_4028B0((int)v15, (unsigned __int8 *)v5);    ++v5;    --v6;  }  while ( v6 );  v8();}return 0;

结构比较简单明了。先大致看了下,if的三个条件应该是校验条件,下面似乎是校验无关。后详细看了下if中的两个函数,才明白:程序的校验实际上是分两部分,一是数独部分,二是AES解密代码并显示出正常的对话框。
 
函数check_group_401240是将输入通过一个字符表转换成一串0-9的数字。
了解了这个,再看函数check_sudoku_401000就很容易明白其功能了:将0-9数字依次填充到9*9矩阵的0值位上,并使用数独的规则进行数独求解成功是否的校验。

本来有长度要求再加上数独校验,就能出唯一解了,就无需后面的部分了。不知道作者是想增加点难度还是出于其它考虑,函数check_group_401240的转换并不能由数独解反算出唯一输入,所以就有了后面的校验部分。
 
后面部分的校验主要是将原始输入取md5的hash作为密钥,对大小为0x610大小的加密代码进行AES解密,成功解密则调用这部分解密代码,猜测应该是提示输入正确。
 
具体看下函数check_group_401240,其伪代码如下:
_mm_storeu_si128((__m128i *)table, _mm_load_si128((const __m128i *)&xmmword_416280));  pos = 0;  _mm_storeu_si128((__m128i *)&table[16], _mm_load_si128((const __m128i *)&xmmword_4162A0));  idx1 = 0;  v11 = a1;  v10 = a2;  out = a3;  table[80] = 'q';  _mm_storeu_si128((__m128i *)&table[32], _mm_load_si128((const __m128i *)&xmmword_416270));  _mm_storeu_si128((__m128i *)&table[48], _mm_load_si128((const __m128i *)&xmmword_416290));  _mm_storeu_si128((__m128i *)&table[64], _mm_load_si128((const __m128i *)&xmmword_416260));  if ( a1 <= 0 )    return 1;  v5 = 0;  while ( 1 )  {    ch_l = a2[idx1];    if ( ch_l > 0x30 && ch_l <= 0x39 )      break;    idx2 = v5;    if ( v5 >= 0x51 )      return 0;    while ( ch_l != table[idx2] )    {      if ( (unsigned int)++idx2 >= 0x51 )        return 0;    }    v9 = idx2 % 9 + 1;    if ( v9 == -1 )      return 0;    *out = v9;    a2 = v10;    ++pos;    ++out;    a1 = v11;LABEL_13:    if ( ++idx1 >= a1 )      return 1;  }  if ( pos + ch_l == 0x39 )  {    pos = 0;    v5 += 9;    goto LABEL_13;  }  return -1;

此函数通过搜索81个元素的字符表,并进行计算后将输入转换成0-9。具体的遍历输入的过程如下:先检查输入字符是否是数字字符,如果是且与某个位置计数相加为0x39,则位置计数清零,字符表查询范围减少9个字符,否则则结束遍历,失败返回。
如输入字符不是数字字符,则搜表得到该字符在表中位置值,经过模9加1计算后记录,作为数独的求解结果。这里在求解的时候要猜下作者意图,不然这部分的反解结果就太多了。根据对程序的意图理解,再结合数独的一些知识,可以猜测,输入中的数字字符是为了将输入分成9组,每组对应数独的一行;还可以猜测到,81个元素的字符表也是分成9组,每组9个字符,第i组的输入字符在出现在第i组的字符表中。

求解

已知的数独如下:
0   4   0   7   0   0   0   0   09   2   0   0   0   0   6   0   78   3   0   0   0   5   4   0   00   1   0   0   0   3   0   0   00   0   0   2   0   1   0   0   00   0   0   5   0   0   0   4   00   0   4   9   0   0   0   7   13   0   5   0   0   0   0   9   40   0   0   0   0   8   0   6   0
为求解数独,随便搜了个在线的求解器,结果如下:
得到55个数字,有了这些数据,再加上上面部分的两个猜测,就可以直接反解输入了。代码如下:
table = "$BPV:ubfYp}]DtN>aT^MGmJQ#*Hr`O'wjic0!hdy{oZz-@n+?&%s_/g<e[W)XUxRFSLRA;.l=CEkvK-(q"idx = [[5,6,1,9,2,3,8],[1,8,3,4,5],[7,6,2,1,9],        [7,8,4,6,9,2,5],[4,5,3,9,7,8,6],[6,9,2,8,7,1,3],        [2,8,5,6,3],[6,1,7,2,8],[1,7,9,3,4,5,2]]length = 64l = [0]*lengthpos = 0for i in range(9):  n = len(idx[i])     for j in range(n):    l[pos+j] = table[i*9+idx[i][j]-1]   l[pos+n] = chr(0x39-n)    print chr(0x39-n) ,  pos += n+1  print ''.join(l[:pos]) print ''.join(l)

反解得到:u$YBPf2pa]Dt4#QM^H4ic'j0`w2y{d-Zzo2%/n_s@+2<UW)e4AR;F.4=-qEkvC2。最后的字符2有没有,对于数独验证没有影响,最后试了下,加上2后面的AES解密才正确。

往期解析

1. 看雪·深信服 2021 KCTF 春季赛 | 第二题设计思路及解析

2. 看雪·深信服 2021 KCTF 春季赛 | 第三题设计思路及解析

主办方

看雪CTF(简称KCTF)是圈内知名度最高的技术竞技之一,从原CrackMe攻防大赛中发展而来,采取线上PK的方式,规则设置严格周全,题目涵盖Windows、Android、iOS、Pwn、智能设备、Web等众多领域。
看雪CTF比赛历史悠久、影响广泛。自2007年以来,看雪已经举办十多个比赛,与包括金山、360、腾讯、阿里等在内的各大公司共同合作举办赛事。比赛吸引了国内一大批安全人士的广泛关注,历年来CTF中人才辈出,汇聚了来自国内众多安全人才,高手对决,精彩异常,成为安全圈的一次比赛盛宴,突出了看雪论坛复合型人才多的优势,成为企业挑选人才的重要途径,在社会安全事业发展中产生了巨大的影响力。
合作伙伴
深信服科技股份有限公司成立于2000年,是一家专注于企业级安全、云计算及基础架构的产品和服务供应商,致力于让用户的IT更简单、更安全、更有价值。目前深信服在全球设有50余个分支机构,员工规模超过7000名。

第五题正在火热进行中,

👆还在等什么,快来参赛吧!

- End -
公众号ID:ikanxue
官方微博:看雪安全
商务合作:[email protected]

球分享

球点赞

球在看

“阅读原文一起来充电吧!

文章来源: http://mp.weixin.qq.com/s?__biz=MjM5NTc2MDYxMw==&mid=2458384940&idx=1&sn=d515b735bd1e247a162047f5747310a9&chksm=b180caa686f743b071af0797f15065509c9bbb859b085b5cbe12acfa7ebd6dd00f6597a4e523#rd
如有侵权请联系:admin#unsafe.sh