首页
社区
课程
招聘
第六题 至暗时刻
2023-9-15 11:22 9433

第六题 至暗时刻

xym 活跃值
4
2023-9-15 11:22
9433
1
2
3
4
5
下载下来的exe短小精悍,ida打开基本就可以看清楚了,没有找到明显字符串,估计是加密了。调试跟踪一会就发现主程序逻辑在sub_140001630函数内,并成功找到了解密函数DecryStr_1400013B0。
读入的key前期并没有任何处理,只是前后分别拼接了一个字符串3201382652D139C0E22132DF1BC2212EA0991650A229B36436823D0B13D51E6677116575313142309154604431859253431473963507533496829080645035455771774602058076430276921790210013736267644383505517280构造成了一个很长的字符串。本来以前是大数,但是看第二个字符串只有0-9,又不太一致。最后还在前段加了一个kctf作为标记位。
后面的函数调用采用了直接使用系统调用号的方法,导致与系统挂钩。但在我的win7虚拟机中,NtAllocateVirtualMemory_140002BBA一直调用失败,只好把对应操作手工实现了一遍,浪费了很多时间。
由于后面操作一直不成功,只能采用静态分析的方式,发现程序只是申请了长度为5500的空间,把kctf开头的字符串写到起始位置,把unk_140008050开始的2347个字节的代码写入偏移为500的地方,然后NtQueueApcThread_140002E4E启动线程执行该代码,通过比较返回是否为“110”还是“120”来判断是否成功。
因此dump该代码段,重新构造exe执行该代码,发现该shellcode将代码中的所有0x17替换为0x00后,实现了一个数独矩阵的检测。sub_140001AA3检测数独是否成立。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
char __fastcall sub_140001AA3(__int64 a1)
{
  unsigned int v2; // ebx
  int v3; // ebx
  int v4; // edi
 
  v2 = 0;
  while ( (unsigned __int8)sub_14000193B(a1, v2) && (unsigned __int8)sub_1400019A7(a1, v2) )// 确保行和列不重复
  {
    if ( (int)++v2 >= 9 )
    {
      v3 = 0;
LABEL_6:
      v4 = 0;
      while ( (unsigned __int8)sub_140001A13(a1, (unsigned int)v3, (unsigned int)v4) )
      {
        v4 += 3;
        if ( v4 >= 9 )
        {
          v3 += 3;
          if ( v3 < 9 )
            goto LABEL_6;
          return 1;
        }
      }
      return 0;
    }
  }
  return 0;
}
1
sub_14000193B检测每行,sub_1400019A7检测每列,sub_140001A13检测93*3的方阵。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
char __fastcall sub_14000193B(__int64 a1, unsigned int a2)
{
  int v2; // ebx
  signed int v5; // eax
  __int128 v7[2]; // [rsp+20h] [rbp-38h] BYREF
  int v8; // [rsp+40h] [rbp-18h]
 
  memset(v7, 0, sizeof(v7));
  v8 = 0;
  v2 = 0;
  while ( 1 )
  {
    v5 = GetXY_14000163B(a1, a2, (unsigned int)v2) - 1;
    if ( (unsigned int)v5 > 8 || *((_DWORD *)v7 + v5) )
      break;
    ++v2;
    *((_DWORD *)v7 + v5) = 1;
    if ( v2 >= 9 )
      return 1;
  }
  return 0;
}
1
其中调用了GetXY_14000163B获取对应矩阵(X,Y)处对应的数字。由于该函数检测不严谨,对大小写的处理不恰当,导致了多解的出现。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
if ( (unsigned __int8)(v19 - '0') > 9u )
{
  if ( (unsigned __int8)(v19 - 'A') > 0x19u )
  {
    if ( (unsigned __int8)(v19 - 'a') > 0x19u )
      break;
    v18 = v19 - 87;
    v17 = 0;
  }
  else
  {
    v18 = v19 - 55;
  }
}
else
{
  v18 = v19 - '0';
}
1
根据程序逻辑,Key前面的字符串是已经放置的21个数字,后面的字符串指示了剩下60个数字的填写顺序。解出已经填写的矩阵如下。
1
2
3
4
5
6
7
8
9
10
11
------------------------------
  0  1  2   3  4  5   6  7  8
0 8            
1     3  6       
2   7      9    2
3   5        7                 
4          4 5  7
5        1        3
6     1           6 8 
7     8  5        1
8   9          4
1
2
该矩阵是网上一个比较经典的数独矩阵,很容易就可以搜索出相应的答案。注意到前后下标的转换关系,按照前面字符串的书写规则得到flag为:11230A2CD3C31CA32E0D707D38E0743531F80F726C1D133B3A914E2F034B1D63BB17F34428E2A31B038C25E0FA2BF2301053752062AA16E20A2FC1971730E90823D01A724B0CA19B0652811541480B80943AE27E13122C30C120
按照规则构造的一个多解为:11230A2CD3C31CA32ED7a07D38E0743531F80F726C1D133B3A914E2F034B1D63BB17F34428E2A31B038C25E0FA2BF2301053752062AA16E20A2FC1971730E90823D01A724B0CA19B0652811541480B80943AE27E13122C30C120

[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。

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