祥云杯2021-re部分wp

本文最后更新于:2021年8月27日 下午

Dizzy

通过sublime 进行replace 加减操作和行逆序操作,然后exec执行跑出flag。

1
2
3
4
5
6
7
8
9
byte_43841C = [ord("'"),ord("<"),-29,-4,46,65,7,94,98,-49,-24,-14,-110,0x80,-30,54,-76,-78,103,119,15,-10,13,-74,-19,28,101,-118,7,83,-90,102]
with open('code.txt','r') as f:
code = f.readlines()
for i in code:
exec(i.strip())
flag = ""
for i in range(len(byte_43841C)):
flag += chr(byte_43841C[i] & 0xff)
print(flag)

勒索解密

首先根据BMP文件头爆破time常数,然后进行解密。

image-20210823111128774

刚开始自己使用rsa和aes进行解密,发现解不出来,rsa每次都在变,没有仔细分析什么原因,后来直接使用wincryptAPI进行解密,rsa只有0x80,感觉影响不大,直接解密AES得到图片。

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
#include <tchar.h>
#include <stdio.h>
#include <windows.h>
#include <wincrypt.h>
#include <conio.h>
#include<stdint.h>
#include<time.h>
#include <stdlib.h>


// Link with the Advapi32.lib file.
#pragma comment (lib, "crypt32.lib")

int main() {
FILE *stream1, *stream2;
char *p;
stream1 = fopen("C:\\Users\\s1lenc3\\Desktop\\fff.txt", "wb");
stream2 = fopen("C:\\Users\\s1lenc3\\Desktop\\flag.bmp.ctf_crypter", "rb");
fseek(stream2, 0, SEEK_END); /* 定位到文件末尾 */
int flen = ftell(stream2) + 1 - 0x80;
printf("%d\n", flen);

p = (char *)malloc(flen); /* 根据文件大小动态分配内存空间 */
if (p == NULL)
{
fclose(stream2);
return 0;
}
fseek(stream2, 0, SEEK_SET); /* 定位到文件开头 */
fread(p, flen, 1, stream2); /* 一次性读取全部文件内容 */
HCRYPTPROV phProv[21] = { 0 };
HCRYPTHASH phHash = 0;
//time = 611a1105
//int pbData[4] = { 0x0ec62fb2, 0x4b54d44f, 0x6120a543, 0x8eb1e721 };
int pbData[4] = { 0x0ec62fb2, 0x4b54d44f, 0x611a1105, 0x8eb1e721 };
BYTE pbData2[4];
DWORD pdwDataLen = 16;
BYTE v11[4];
char in[64] = { 0 };
char out1[32] = { 0 };
char out2[32] = { 0 };
char v2; // bl
BYTE *v4; // esi
struct _CERT_PUBLIC_KEY_INFO *v5;
DWORD pcbStructInfo;
DWORD pcbBinary;
DWORD v8 = 16;
memcpy(in, "123456789", 9);
//memcpy(out, "\x82\x23\x4B\x7C\xCC\x17\x28\x3D\x2D\xC8\x79\x23\xF9\xA5\x40\x2F\x6D\x3B\x7F\x28\x7F\x08\xC8\x91\x0E\x69\xC0\xDA\x22\xCE\x2D\xF5", 32);
//\xB2\x02\xF8\x09\x6A\x8B\x3F\x25\x94\xED\xE7\xB1\xC9\xFC\x3A\xA7\xC6\x78\x5F\x43\x36\xB6\xD7\x43\xDD\xB8\x0C\x13\x60\xAC\x60\xD0
//int r_size = fread(out2, 1, 32, stream2);
//printf("%s\n", out2);
//memcpy(out1, out2, 32);
memset(phProv, 0, sizeof(phProv));
if (CryptAcquireContextA(phProv, 0, "Microsoft Enhanced RSA and AES Cryptographic Provider", 0x18u, 0xF0000000))
{
phHash = 0;
if (CryptCreateHash(*phProv, 0x800Cu, 0, 0, &phHash))
{
//pbData[2] = i;
if (CryptHashData(phHash, (const BYTE *)&pbData, 0x10, 0))
{
CryptDeriveKey(*phProv, 0x660E, phHash, 0, (HCRYPTKEY *)(phProv + 1)); // CALG_AES_128
//printf("%d\n", i);
/*
v2 = 0;
pcbBinary = 0;
if (!CryptStringToBinaryA(
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCJ7DFnM7uJiQYyozOgYTJs6oT9nRadxeyYux9/q/+hRcdKolSwRio0TOmpvmNrRttsyOPx01"
"V8Cami2KonF2xqEzAg0OcDh6K1gzzBLxqI6XBipi4gJ/24OaXYFFr7CHCxBXeQDVjbPa53Kn2bOwknMT6+MuzNMoN4bFMa/p7QJQIDAQAB",
0xD8,
1,
0,
&pcbBinary,
0,
0))
return 0;
v4 = (BYTE *)malloc(pcbBinary);
if (!CryptStringToBinaryA(
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCJ7DFnM7uJiQYyozOgYTJs6oT9nRadxeyYux9/q/+hRcdKolSwRio0TOmpvmNrRttsyOPx01"
"V8Cami2KonF2xqEzAg0OcDh6K1gzzBLxqI6XBipi4gJ/24OaXYFFr7CHCxBXeQDVjbPa53Kn2bOwknMT6+MuzNMoN4bFMa/p7QJQIDAQAB",
0,
1,
v4,
&pcbBinary,
0,
0))
return 0;
pcbStructInfo = 0;
if (!CryptDecodeObjectEx(0x10001, (LPCSTR)8, v4, pcbBinary, 0, 0, 0, &pcbStructInfo))
{
return 0;
}
v5 = (struct _CERT_PUBLIC_KEY_INFO *)malloc(pcbStructInfo);
if (CryptDecodeObjectEx(0x10001, (LPCSTR)8, v4, pcbBinary, 0, 0, v5, &pcbStructInfo))
{
CryptImportPublicKeyInfo(*phProv, 0x10001, v5, &phProv[2]);
}
CryptEncrypt(phProv[2], 0, 1, 0, (BYTE *)pbData, &v8, 0x80);
*/
CryptSetKeyParam(phProv[1], 4, pbData2, 0);
*(DWORD *)v11 = 1;
CryptSetKeyParam(phProv[1], 3u, v11, 0);
int j = 0;
while (j <= flen - 1) {
if (j + 32 == flen - 1) {
memcpy(out1, p + j, 32);
}
else {
memcpy(out1, p + j, 16);
}
//CryptEncrypt(phProv[1], 0, 1, 0, out, &pdwDataLen, 32);
if (j + 32 == flen - 1) {
CryptDecrypt(phProv[1], 0, 1, 0, out1, &pdwDataLen);
fwrite(out1, 1, 32, stream1);
j += 32;
}
else {
CryptDecrypt(phProv[1], 0, 0, 0, out1, &pdwDataLen);
fwrite(out1, 1, 16, stream1);
j += 16;
}
//fwrite(out1, 1, 32, stream1);
//if (memcmp(out, "\x42\x4d\xbe\x67", 4) == 0) {
//printf("12321");
// printf("%x\n", i);
//}
}
}
}
}
}

image-20210823100552950

LightningSystem

给了一个网站,题目里有一个sal文件,使用网站中下载的工具Logic即可打开。

也不是很懂,做过类似的杂项题,我就是瞎设置,看能不能提取出字符串。

image-20210826141517611

最后恢复出了通讯数据:

image-20210826142310250

直接以arm架构反编译hex文件,分析代码。

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
if ( MEMORY[0x20000004] == 0xEF4015 )
{
sub_8000AF0(v0, 0, 512);
v2.opcode = (int)&v1; // op
v2.data = (int)&v0[v0[0] + 2]; // data
v2.pc = 0; // pc
while ( 1 )
{
switch ( *(_BYTE *)(v2.opcode + v2.pc) )
{
case 0:
sub_8000168((int)&v2); // pc++
break;
case 1: // output
sub_8000170((int)&v2, *(unsigned __int8 *)(v2.opcode + v2.pc + 1));
break;
case 2: // input
sub_8000196((int)&v2, *(unsigned __int8 *)(v2.opcode + v2.pc + 1));
break;
case 3: // mov
sub_80001C0((int)&v2, *(unsigned __int8 *)(v2.opcode + v2.pc + 1), *(_BYTE *)(v2.opcode + v2.pc + 2));
break;
case 4: // cmp
sub_80001CC(
(int)&v2,
*(unsigned __int8 *)(v2.opcode + v2.pc + 1),
*(unsigned __int8 *)(v2.opcode + v2.pc + 2),
*(char *)(v2.opcode + v2.pc + 3));
break;
case 5: // add
sub_80001EC((int)&v2, *(unsigned __int8 *)(v2.opcode + v2.pc + 1), *(_BYTE *)(v2.opcode + v2.pc + 2));
break;
case 6: // ror
sub_8000200((int)&v2, *(unsigned __int8 *)(v2.opcode + v2.pc + 1), *(char *)(v2.opcode + v2.pc + 2));
break;
case 7: // setValue
sub_800024E(
(int)&v2,
*(unsigned __int8 *)(v2.opcode + v2.pc + 1),
*(unsigned __int8 *)(v2.opcode + v2.pc + 2));
break;
case 8: // add
sub_800026A(
(int)&v2,
*(unsigned __int8 *)(v2.opcode + v2.pc + 1),
*(unsigned __int8 *)(v2.opcode + v2.pc + 2));
break;
case 9: // mov
sub_800029A(
(int)&v2,
*(unsigned __int8 *)(v2.opcode + v2.pc + 1),
*(unsigned __int8 *)(v2.opcode + v2.pc + 2));
break;
case 0xA: // mul
sub_80002AC((int)&v2, *(unsigned __int8 *)(v2.opcode + v2.pc + 1), *(_BYTE *)(v2.opcode + v2.pc + 2));
break;
case 0xB: // sub
sub_80002C0(
(int)&v2,
*(unsigned __int8 *)(v2.opcode + v2.pc + 1),
*(unsigned __int8 *)(v2.opcode + v2.pc + 2));
break;
case 0xC: // shl
sub_80002F2((int)&v2, *(unsigned __int8 *)(v2.opcode + v2.pc + 1), *(char *)(v2.opcode + v2.pc + 2));
break;
case 0xD: // xor
sub_8000328(
(int)&v2,
*(unsigned __int8 *)(v2.opcode + v2.pc + 1),
*(unsigned __int8 *)(v2.opcode + v2.pc + 2));
break;
case 0xE: // mul
sub_8000350(
(int)&v2,
*(unsigned __int8 *)(v2.opcode + v2.pc + 1),
*(unsigned __int8 *)(v2.opcode + v2.pc + 2));
break;
case 0xF: // mov
sub_800037C(
(int)&v2,
*(unsigned __int8 *)(v2.opcode + v2.pc + 1),
*(unsigned __int8 *)(v2.opcode + v2.pc + 2));
break;
case 0x10: // setValue
sub_800039E(
(int)&v2,
*(unsigned __int8 *)(v2.opcode + v2.pc + 1),
*(unsigned __int8 *)(v2.opcode + v2.pc + 2));
break;
default:
while ( 1 )
;
}
}
}c

发现了一个判断0xEF4015的地方。

发现是一个vm,分析opcode,还原从sal文件中提取出来的指令。

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
import ctypes
a = [0, ord('M')] #2c 2d
b = [0, 0] #2e 2f
c = 0
d = [0, 0] #34 35
f = [0, 0] #32 33
e = [0, 0] #30 31
result = []
#flag{hwbfkuaewbvlibfewaijbvjlwebcwydhisjk}
inp = "123456789123456789123456789123456789123456"
for i in range(42):
a0 = ((a[0] << 8) | a[1]) & 0xffff
a0 = ((a0 >> 9) | (a0 << (16 - 9))) & 0xffff
a[0] = a0 >> 8
a[1] = a0 & 0xff
b = [0, ord(inp[i])]
b0 = (a[1] + b[1]) & 0xffff
a[1] = b0 & 0xff
a[0] += b[0] + (b0 >> 8)
print(a, b)
for i in range(21):
d[0] = (i * 2 + 2)
b = [0, ord(inp[i*2])]
b0 = b[1] - 0x20
b[1] -= 0x20
b[0] -= -((b0 >> 8) & 0xff)
d[0] += 1
e = [0, ord(inp[i*2+1])]
e0 = e[1] - 0x20
e[1] -= 0x20
e[0] -= -((e0 >> 8) & 0xff)
e1 = ((e[0] << 8) | e[1]) & 0xffff
e2 = (e1 << -(ctypes.c_int8(0xf9).value)) & 0xffff
e[0] = (e2 >> 8) & 0xff
e[1] = e2 & 0xff
f = [0, i]
f0 = (((f[0] << 8) | f[1]) ^ 0x4d) & 0xffff
f[0] = (f0 >> 8) & 0xff
f[1] = f0 & 0xff
f0 = (((f[0] << 8) | f[1]) * 7) &0xffff
f[0] = (f0 >> 8) & 0xff
f[1] = f0 & 0xff
f0 = (f[1] + a[1]) & 0xffff
f[1] = f0 & 0xff
f[0] += (a[0] + (f0 >> 8)) & 0xff
f0 = (f[1] + b[1]) & 0xffff
f[1] = f0 & 0xff
f[0] += (b[0] + (f0 >> 8)) & 0xff
f0 = (f[1] + e[1]) & 0xffff
f[1] = f0 & 0xff
f[0] += (e[0] + (f0 >> 8))
f[0] = f[0] & 0xff
result.append(hex(f[0]))
result.append(hex(f[1]))
print(result)

还原出来才知道,中间大部分是在操作byte转word,其实运算挺简单的。

因为数组a不知道,所以要爆破,猜测答案是flag{}形式,爆破可得到数组a,然后解出flag。

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
import ctypes
i = 0
a = [234, 6] #2c 2d
b = [0, 0] #2e 2f
c = 0
d = [0, 0] #34 35
f = [0, 0] #32 33
e = [0, 0] #30 31
cmmmp = [0x12,0x67,0x0F,0xDB,0xF6,0x0A,0x0F,0x39,0xF6,0xC9,0xF5,0xC1,0xF2,0xA3,0x0D,0xD0,0xF5,0x01,0x0C,0x6F,0x0E,0x39,0xF2,0x80,0xF5,0xE4,0x0C,0xD7,0xF8,0x68,0x0C,0x96,0xF5,0xA5,0x0F,0x9F,0x0F,0x31,0xF9,0x2E,0x1B,0x07]
flag = ""
for i in range(21):
br = 0
for x in range(256):
for j in range(256):
#a = [x, j]
d[0] = (i * 2 + 2)
b = [0, x]
b0 = b[1] - 0x20
b[1] -= 0x20
b[0] -= -((b0 >> 8) & 0xff)
d[0] += 1
e = [0, j]
e0 = e[1] - 0x20
e[1] -= 0x20
e[0] -= -((e0 >> 8) & 0xff)
e1 = ((e[0] << 8) | e[1]) & 0xffff
e2 = (e1 << -(ctypes.c_int8(0xf9).value)) & 0xffff
e[0] = (e2 >> 8) & 0xff
e[1] = e2 & 0xff
f = [0, i]
f0 = (((f[0] << 8) | f[1]) ^ 0x4d) & 0xffff
f[0] = (f0 >> 8) & 0xff
f[1] = f0 & 0xff
f0 = (((f[0] << 8) | f[1]) * 7) & 0xffff
f[0] = (f0 >> 8) & 0xff
f[1] = f0 & 0xff
f0 = (f[1] + a[1]) & 0xffff
f[1] = f0 & 0xff
f[0] += (a[0] + (f0 >> 8)) & 0xff
f0 = (f[1] + b[1]) & 0xffff
f[1] = f0 & 0xff
f[0] += (b[0] + (f0 >> 8)) & 0xff
f0 = (f[1] + e[1]) & 0xffff
f[1] = f0 & 0xff
f[0] += (e[0] + (f0 >> 8))
f[0] = f[0] & 0xff
if f[0] == cmmmp[i*2] and f[1] == cmmmp[i*2+1]:
flag += chr(x) + chr(j)
br = 1
break
if br == 1:
break
print(flag)

rev_apc

sys主要两个地方:

提取一个dll文件,

image-20210827163806101

通讯数据加密:

image-20210827164021315

1
2
3
4
5
6
7
8
9
f = open("a.dump", "rb")
a = [0xde, 0xad, 0xbe, 0xef]
s = f.read()
print(s)
ss = b""
for i in range(len(s)):
ss += chr(s[i] ^ a[i % 4]).encode("latin")
fn = open("inject.dll", "wb")
fn.write(ss)

dump并解密dll文件,进行分析:

image-20210827164312005

rand伪随机数,可以自己写C代码生成,各平台伪随机数可能不一样,要在windows上生成:

将初始化后的key与flag.txt的内容与驱动进行通讯加密:

image-20210827164526520

我们先去找到加密方式,得到初始数据:

image-20210827111842748

然后进行加密:

image-20210827111919948

后经分析,好像key和这个字符串没有关系。。。。

分析sys文件中的几个通讯加密函数,写脚本,z3求解。

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
from z3 import *
import ctypes

key = []
s1 = [0xA5, 0xCF, 0xCD, 0xD6, 0xC5, 0xC3, 0xB1, 0xC5, 0xD2, 0xD9, 0xD7, 0xC7, 0xD6, 0xCD, 0xD4, 0xD8, 0xC3, 0xBB, 0xCD, 0xD8, 0xCC, 0xC3, 0xB0, 0xC5, 0xD8, 0xC9, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00]
for i in range(32):
s = 0
for j in range(i+1):
s ^= s1[j]
key.append(s)
print(key)
#key = [0xA5, 0x6A, 0xA7, 0x71, 0xB4, 0x77, 0xC6, 0x03, 0xD1, 0x08, 0xDF, 0x18, 0xCE, 0x03, 0xD7, 0x0F,0xCC, 0x77, 0xBA, 0x62, 0xAE, 0x6D, 0xDD, 0x18, 0xC0, 0x09, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5]
item = [5, 5, 4, 4, 5, 4, 0, 0, 4, 2, 5, 5, 1, 3, 1, 5, 1, 2, 3, 0, 3, 0, 2, 3, 4, 4, 3, 2, 2, 5, 5, 0]
cmp = [0x57, 0xc5, 0x38, 0x1b, 0x3a, 0xa8, 0x34, 0x2f, 0x39, 0x97, 0xc6, 0xe4, 0x04, 0x2f, 0x8f, 0xee, 0x5e, 0x51, 0x80, 0x67, 0x24, 0xc9, 0x6f, 0x48, 0x5b, 0x7f, 0xbd, 0xc7, 0xb0, 0xc2, 0xc2, 0xeb]
def _22000b():
for i in range(32):
key[i] = (key[i] + 16) & 0xff
inp[i] ^= key[i]
def _22000f():
for i in range(32):
key[i] = (key[i] - 80) & 0xff
tmp = ((key[i] << 4) & 0xf0) | ((key[i] >> 4) & 0x0f)
inp[i] ^= tmp
def _220013():
for i in range(32):
inp[i] ^= key[i]
def _220017():
for i in range(32):
key[i] = (key[i] - 80) & 0xff
for j in range(16):
inp[j*2] ^= (key[j*2] << 4) & 0xff
inp[j*2+1] ^= (key[j*2] >> 4) & 0x0f
def _22001b():
#三个for循环 抵消
for j in range(32):
inp[j] ^= key[j]
def _22001f():
for i in range(32):
if ctypes.c_uint8(key[i] - 33).value > 46:
if ctypes.c_uint8(key[i] - 81).value > 46:
if key[i] > 0x80:
key[i] -= 48
inp[i] = ((inp[i] - key[i]) & 0xff)
else:
key[i] -= 48
inp[i] = (inp[i] ^ (key[i] >> 4)) & 0xff
else:
key[i] = (key[i] - 80) & 0xff
inp[i] = (inp[i] + key[i]) & 0xff
s = Solver()
inp = [BitVec("x%s" % i, 32) for i in range(32)]
for i in range(32):
if item[i] == 0:
_22000b()
if item[i] == 1:
_22000f()
if item[i] == 2:
_220013()
if item[i] == 3:
_220017()
if item[i] == 4:
_22001b()
if item[i] == 5:
_22001f()
for i in range(32):
s.add(inp[i] & 0xff == cmp[i])
x = [BitVec("x%s" % i, 32) for i in range(32)]
if (s.check() == sat):
model = s.model()
print(model)
flag=""
for i in range(32):
if (model[x[i]] != None):
flag += chr(model[x[i]].as_long().real)
else:
flag += " "
print('"' + flag + '"')

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!