首页
论坛
课程
招聘
[原创]迷失丛林 Writeup by or4nge
2021-11-17 02:07 7373

[原创]迷失丛林 Writeup by or4nge

2021-11-17 02:07
7373

迷失丛林 Writeup by or4nge

很容易定位到程序的输入

 

 

输入长度为32,需要通过 sub_4014A0, sub_401580 的验证

 

4014A0 较为简单,是个经典的hexstr转成char存到 4041F0 这个地址,最后的16是计算转换后的长度,所以输入就是 [0-9A-F]{32}

 

随后将输入的前八字节存入 404000 中,剩下的部分传参进 sub_401580

 

要想让该函数返回1,需要先通过一组if验证

1
if ( v21 == (char)169 && v22 == (char)0xAC && v23 == (char)0xA7 && v24 > 0xC8u)

看一下使用的变量,应该是对前八字节的输入进行的验证

 

 

结合动调发现大概就是根据404000数组,构成一个 <value, index> 的结构,两两存放到404420当中

 

分析了一下404000数组的作用和特征,发现这个数组应该是构成一个环状的结构(以当前数值作为索引寻找下一个数),猜测不能有重复的数字,否则可能会构成小循环之类的,用脚本验证了一下发现后面248个数字果然没有重复,于是将前八字节的取值可能锁定到了 0x1e, 0x28, 0x4b, 0x6d, 0x8c, 0xa3, 0xd2, 0xfb 中,总共有 $8!=40320$ 种可能,完全可以爆破

 

把ida代码复制下来改一改

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#include <stdio.h>
#include <stdint.h>
#include <algorithm>
#include <cstring>
 
unsigned char byte_404000[] = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA2, 0x9B,
  0xF4, 0xDF, 0xAC, 0x7C, 0xA1, 0xC6, 0x16, 0xD0, 0x0F, 0xDD,
  0xDC, 0x73, 0xC5, 0x6B, 0xD1, 0x96, 0x47, 0xC2, 0x26, 0x67,
  0x4E, 0x41, 0x82, 0x20, 0x56, 0x9A, 0x6E, 0x33, 0x92, 0x88,
  0x29, 0xB5, 0xB4, 0x71, 0xA9, 0xCE, 0xC3, 0x34, 0x50, 0x59,
  0xBF, 0x2D, 0x57, 0x22, 0xA6, 0x30, 0x04, 0xB2, 0xCD, 0x36,
  0xD5, 0x68, 0x4D, 0x5B, 0x45, 0x9E, 0x85, 0xCF, 0x9D, 0xCC,
  0x61, 0x78, 0x32, 0x76, 0x31, 0xE3, 0x80, 0xAD, 0x39, 0x4F,
  0xFA, 0x72, 0x83, 0x4C, 0x86, 0x60, 0xB7, 0xD7, 0x63, 0x0C,
  0x44, 0x35, 0xB3, 0x7B, 0x19, 0xD4, 0x69, 0x08, 0x0B, 0x1F,
  0x3D, 0x11, 0x79, 0xD3, 0xEE, 0x93, 0x42, 0xDE, 0x23, 0x3B,
  0x5D, 0x8D, 0xA5, 0x77, 0x5F, 0x58, 0xDB, 0x97, 0xF6, 0x7A,
  0x18, 0x52, 0x15, 0x74, 0x25, 0x62, 0x2C, 0x05, 0xE8, 0x0D,
  0x98, 0x2A, 0x43, 0xE2, 0xEF, 0x48, 0x87, 0x49, 0x1C, 0xCA,
  0x2B, 0xA7, 0x8A, 0x09, 0x81, 0xE7, 0x53, 0xAA, 0xFF, 0x6F,
  0x8E, 0x91, 0xF1, 0xF0, 0xA4, 0x46, 0x3A, 0x7D, 0x54, 0xEB,
  0x2F, 0xC1, 0xC0, 0x0E, 0xBD, 0xE1, 0x6C, 0x64, 0xBE, 0xE4,
  0x02, 0x3C, 0x5A, 0xA8, 0x9F, 0x37, 0xAF, 0xA0, 0x13, 0xED,
  0x1B, 0xEC, 0x8B, 0x3E, 0x7E, 0x27, 0x99, 0x75, 0xAB, 0xFE,
  0xD9, 0x3F, 0xF3, 0xEA, 0x70, 0xF7, 0x95, 0xBA, 0x1D, 0x40,
  0xB0, 0xF9, 0xE5, 0xF8, 0x06, 0xBC, 0xB6, 0x03, 0xC9, 0x10,
  0x9C, 0x2E, 0x89, 0x5C, 0x7F, 0xB1, 0x1A, 0xD6, 0x90, 0xAE,
  0xDA, 0xE6, 0x5E, 0xB9, 0x84, 0xE9, 0x55, 0xBB, 0xC7, 0x0A,
  0xE0, 0x66, 0xF2, 0xD8, 0xCB, 0x00, 0x12, 0xB8, 0x17, 0x94,
  0x6A, 0x4A, 0x01, 0x24, 0x14, 0x51, 0x07, 0x65, 0x21, 0xC8,
  0x38, 0xFD, 0x8F, 0xC4, 0xF5, 0xFC
};
 
unsigned char byte_404220[520];
 
unsigned char byte_404420[65537];
 
int dword_404100[] = {2, 4, 8, 0x10, 0x20, 0x40, 0x80, 0};
 
using namespace std;
 
int sub_401580(unsigned char *a2) {
  int v2; // ebp
  unsigned char *v3; // eax
  int *v4; // esi
  unsigned char *v5; // ecx
  int v6; // edi
  unsigned char *v7; // ecx
  int v8; // edx
  unsigned char *v9; // eax
  int v10; // ecx
  int v11; // esi
  int v12; // eax
  unsigned char v13; // dl
  int v14; // edi
  int v15; // eax
  int v16; // ecx
  int v17; // esi
  int i; // eax
  char v19; // dl
  unsigned char v21; // [esp+10h] [ebp-Ch]
  unsigned char v22; // [esp+11h] [ebp-Bh]
  unsigned char v23; // [esp+12h] [ebp-Ah]
  unsigned char v24; // [esp+13h] [ebp-9h]
  unsigned char *v25; // [esp+14h] [ebp-8h]
 
  v21 = 0;
  v22 = 0;
  v23 = 0;
  v24 = 0;
  v2 = 1;
  v25 = byte_404420;
  for (i = 0; i < 8; i++)
    byte_404000[i] = a2[i];
  do
  {
    byte_404220[0] = byte_404000[v2 - 1];
    byte_404220[1] = v2;
    v3 = byte_404220;
    v4 = dword_404100;
    v5 = &byte_404220[dword_404100[0]];
    do
    {
      v6 = *v4;                                 // 2, 4, 8, 10h, 20h, 40h, 80h
      if ( *v4 > 0 )
      {
        do
        {
          v7 = v5 + 1;
          *(v7 - 1) = byte_404000[*v3];
          *v7 = *v3 + 1;
          v5 = v7 + 1;
          ++v3;
          --v6;
        }
        while ( v6 );
      }
      ++v4;
    }
    while ( v4 < &(dword_404100[7]) );
    v8 = 256;
    do
    {
      ++v25[*v3++];
      --v8;
    }
    while ( v8 );
    ++v2;
    v25 += 256;
  }
  while ( v2 - 1 < 256 );
  v9 = &byte_404420[0x28];
  v10 = 256;
  do
  {
    if ( *(v9 - 40) )
      ++v21;
    if ( *(v9 - 26) )
      ++v22;
    if ( *v9 )
      ++v23;
    if ( v9[39] )
      ++v24;
    v9 += 256;
    --v10;
  }
  while ( v10 );
  if ( v21 == 0xA9 && v22 == 0xAC && v23 == 0xA7 && v24 > 0xC8u ){
    for (i = 0; i < 8; i++){
      printf("%hhX", a2[i]);
    }
  }
  return 0;
}
 
 
int main(){
  unsigned char flag[] = {0x1e, 0x28, 0x4b, 0x6d, 0x8c, 0xa3, 0xd2, 0xfb};
  do{
    memset(byte_404420, 0, 65536);
    sub_401580(flag);
  }while (next_permutation(flag, flag + 8));
  return 0;
}

转换一下得到前八字节 B4D682C8BF2DE13A

 

确定前八字节后,只需要关注和参数(后八字节)有关的部分了,中间全部动调跳过

 

 

这一部分程序相较来说就简单了不少,主要是根据404000开头的八个字节作为初始值,每个字节单独与输入的八个字节进行运算,根据末尾bit决定是+1还是找索引,最终目的是凑成 GoodJob~ 这个字符串(sub_4024C0 是个字符串比较)

 

可以使用搜索算法求解,但考虑到每个字节是单独运算的,常规爆破也只需要 0x800 的运算量,所以还是直接爆破了

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include <stdio.h>
 
unsigned char byte_414420[] = {0xC1, 0x9B, 0x7F, 0x58, 0x64, 0xD5, 0x77, 0x21};
 
unsigned char byte_404000[] = {
    0xC1, 0x9B, 0x7F, 0x58, 0x64, 0xD5, 0x77, 0x21, 0x74, 0xEB,
    0x14, 0xBF, 0xDF, 0x25, 0x5A, 0x37, 0x85, 0x2C, 0xAF, 0x8C,
    0xDA, 0x26, 0xE2, 0x7A, 0x87, 0x4C, 0x60, 0x99, 0x54, 0x3C,
    0x95, 0xC0, 0xB9, 0x0C, 0xBC, 0x0E, 0xE7, 0x2D, 0x86, 0xBE,
    0x67, 0xD3, 0xD8, 0xFC, 0x30, 0xB6, 0xC8, 0x57, 0x1E, 0x62,
    0x3E, 0xCE, 0xA0, 0xCD, 0xF5, 0xEE, 0xA7, 0xCF, 0x45, 0xFE,
    0xD0, 0x80, 0x05, 0xAD, 0x13, 0xF3, 0xB7, 0x6B, 0x22, 0x2B,
    0xBD, 0x69, 0x42, 0x4B, 0xA5, 0xEA, 0xA6, 0xD2, 0x6F, 0x4F,
    0x4E, 0x07, 0xE1, 0x36, 0x01, 0xB5, 0xAA, 0xB1, 0x94, 0x0B,
    0x35, 0x3A, 0xC7, 0x49, 0x53, 0x82, 0xC3, 0x7B, 0x32, 0xFF,
    0x19, 0xC4, 0xF1, 0xC9, 0xE8, 0xF7, 0x56, 0x15, 0xA3, 0x46,
    0x89, 0x43, 0x9D, 0x8F, 0x20, 0xEF, 0xBB, 0x2A, 0xCB, 0x09,
    0x93, 0x4A, 0x1C, 0xE3, 0x33, 0xD1, 0xE0, 0x1D, 0x72, 0x7C,
    0x27, 0xE9, 0x17, 0x28, 0x6D, 0x6A, 0xD9, 0x00, 0x9A, 0xE5,
    0x63, 0xDE, 0x23, 0x9F, 0x0D, 0x47, 0x3B, 0x65, 0x08, 0x84,
    0x6C, 0x1A, 0x88, 0x12, 0xA1, 0xA4, 0xB3, 0x18, 0x24, 0x1B,
    0xD7, 0x44, 0xDB, 0xAC, 0x6E, 0x7D, 0x51, 0x5E, 0xED, 0x50,
    0xD6, 0x11, 0x5B, 0x9C, 0xB4, 0x68, 0x3D, 0x2F, 0x03, 0x40,
    0xBA, 0x2E, 0xCA, 0x02, 0xE6, 0xA8, 0xEC, 0x83, 0x06, 0x5D,
    0xB8, 0x4D, 0x97, 0x66, 0xF0, 0xFB, 0x8A, 0x55, 0xAB, 0xB2,
    0x04, 0xFA, 0x0A, 0x31, 0x71, 0xCC, 0x8B, 0x73, 0xA9, 0x48,
    0x5C, 0xF9, 0x98, 0xE4, 0xC6, 0x34, 0xC5, 0x7E, 0x81, 0x75,
    0x90, 0x1F, 0x92, 0x3F, 0x9E, 0x10, 0x29, 0x52, 0x39, 0xF4,
    0x41, 0x78, 0x5F, 0x16, 0x79, 0xC2, 0xB0, 0xDD, 0xF2, 0x61,
    0x0F, 0x70, 0xD4, 0x91, 0xDC, 0xF6, 0xF8, 0xFD, 0x59, 0x38,
    0x8D, 0x96, 0xAE, 0x8E, 0x76, 0xA2
};
 
int calc(unsigned char a2, int i){
  int v17; // esi
  char v19; // dl
  v17 = 0;
    do
    {
        if ( v17 >= 8 )
        {
          if ( !i || i == 7 )
            --byte_414420[i];
        }
        else
        {
            if ( (a2 & 1) != 0 )
                v19 = byte_414420[i] + 1;
            else
                v19 = byte_404000[byte_414420[i]];
            byte_414420[i] = v19;
            a2 >>= 1;
        }
        ++v17;
    }
    while ( v17 < 9 );
    return byte_414420[i];
}
 
int main(){
    int i = 0;
    unsigned char a = 0;
    unsigned char b[] = "GoodJob~";
    for (int j = 0; j < 8; j++){
        for (i = 0; i < 0x100; i++){
            a = i & 0xff;
            for (int k = 0; k < 8; k++){
                byte_414420[k] = byte_404000[k];
            }
            calc(a, j);
            if (byte_414420[j] == b[j])
                printf("%d %x\n", j, a);
        }
    }
    return 0;
}

最后得到下半段验证码 D9B6AEF24A80CB22


【公告】看雪团队招聘安全工程师,将兴趣和工作融合在一起!看雪20年安全圈的口碑,助你快速成长!

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