seccon-quals-2023

I played Seccon Quals with PIG SEKAI this weekend, and we finished 7th. This time, I solved a reverse challenge, xuyao, and surprisingly got the first blood. Here’s my writeup for it.

Challenge Info

xuyao

(176 pt)

author:ptr-yudai

X86-64 Unbreakable Yet Another Obfuscation

xuyao.tar.gz 16233233cbca9895ab3573e781c62c402b13a0d9

Untitled

Solution

This program’s main function just gets input, does some padding, encrypts(SECCON CTF 2023! as the key), and compares the result with embed bytes(enc below).

Untitled

Inside the encrypt function, three tables are used, one of which is AES Sbox. It successfully misled me to think of the function as a modification of the AES algorithm. But as I debugged this function, I saw the key and the data were encrypted like a wheel moving forward, reminding me of the SM4 algorithm.

After carefully analyzing and debugging, I confirmed this is an SM4 algorithm with custom table and rotate operations.

The key was transformed with rol 11 and ror 7(rol 25), but the original goes rol 13 and rol 23.

Untitled

The input was transformed with rol 3,rol 14,rol 15, and rol 9. Meanwhile, the original one goes rol 2,rol 10,rol 18 androl 24.

Untitled

We can now solve this chall. Just find an SM4 decrypt code, replace the three tables, and change the rotate numbers.

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
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
#include <stdio.h>
#include <string.h>
#include <time.h>

#define SM4_ENCRYPT 1
#define SM4_DECRYPT 0

typedef struct {
int mode; /*!< encrypt/decrypt */
unsigned long sk[32]; /*!< SM4 subkeys */
} sm4_context;

void sm4_setkey_enc(sm4_context *ctx, unsigned char key[16]);

void sm4_setkey_dec(sm4_context *ctx, unsigned char key[16]);

void sm4_crypt_ecb(sm4_context *ctx, int mode, int length, unsigned char *input,
unsigned char *output);

void sm4_crypt_cbc(sm4_context *ctx, int mode, int length, unsigned char iv[16],
unsigned char *input, unsigned char *output);

#ifndef GET_ULONG_BE
#define GET_ULONG_BE(n, b, i) \
{ \
(n) = ((unsigned long)(b)[(i)] << 24) | \
((unsigned long)(b)[(i) + 1] << 16) | \
((unsigned long)(b)[(i) + 2] << 8) | ((unsigned long)(b)[(i) + 3]); \
}
#endif
#ifndef PUT_ULONG_BE
#define PUT_ULONG_BE(n, b, i) \
{ \
(b)[(i)] = (unsigned char)((n) >> 24); \
(b)[(i) + 1] = (unsigned char)((n) >> 16); \
(b)[(i) + 2] = (unsigned char)((n) >> 8); \
(b)[(i) + 3] = (unsigned char)((n)); \
}
#endif

#define SHL(x, n) (((x)&0xFFFFFFFF) << n)
#define ROTL(x, n) (SHL((x), n) | ((x) >> (32 - n)))
#define SWAP(a, b) \
{ \
unsigned long t = a; \
a = b; \
b = t; \
t = 0; \
}

static const unsigned char SboxTable[16][16] = {
0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B,
0xFE, 0xD7, 0xAB, 0x76, 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0,
0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 0xB7, 0xFD, 0x93, 0x26,
0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2,
0xEB, 0x27, 0xB2, 0x75, 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0,
0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, 0x53, 0xD1, 0x00, 0xED,
0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F,
0x50, 0x3C, 0x9F, 0xA8, 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5,
0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 0xCD, 0x0C, 0x13, 0xEC,
0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14,
0xDE, 0x5E, 0x0B, 0xDB, 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C,
0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 0xE7, 0xC8, 0x37, 0x6D,
0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F,
0x4B, 0xBD, 0x8B, 0x8A, 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E,
0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, 0xE1, 0xF8, 0x98, 0x11,
0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F,
0xB0, 0x54, 0xBB, 0x16};

static const unsigned long FK[4] = {0xFF324600, 0x4F9A25B8, 0x3CC7477C,
0x0C0B9ECD};

static const unsigned long CK[32] = {
0xEC656287, 0xD9A22031, 0x01C7BCA8, 0xABE7033B, 0x313FE5DC, 0x940FFAD0,
0x176EDEB8, 0x7C61B20E, 0x9EAD452F, 0x80E2C15B, 0xBA500D7B, 0xA2C0449F,
0xBC0E774F, 0x3E393763, 0x43D46B3F, 0x2ADEF404, 0xCA884B87, 0x3C953C45,
0x7CDBDE63, 0x6E995945, 0xB6CF3655, 0x8D60396A, 0x9A496B38, 0x9D87D81B,
0x36FEDBC9, 0x79882953, 0x10611E15, 0x0030AB3E, 0x12503487, 0x187E21FF,
0x6D85127E, 0xDF42C76C,
};

static unsigned char sm4Sbox(unsigned char inch) {
unsigned char *pTable = (unsigned char *)SboxTable;
unsigned char retVal = (unsigned char)(pTable[inch]);
return retVal;
}

static unsigned long sm4Lt(unsigned long ka) {
unsigned long bb = 0;
unsigned long c = 0;
unsigned char a[4];
unsigned char b[4];
PUT_ULONG_BE(ka, a, 0)
b[0] = sm4Sbox(a[0]);
b[1] = sm4Sbox(a[1]);
b[2] = sm4Sbox(a[2]);
b[3] = sm4Sbox(a[3]);
GET_ULONG_BE(bb, b, 0)
c = bb ^ (ROTL(bb, 3)) ^ (ROTL(bb, 14)) ^ (ROTL(bb, 15)) ^ (ROTL(bb, 9));
return c;
}

static unsigned long sm4F(unsigned long x0, unsigned long x1, unsigned long x2,
unsigned long x3, unsigned long rk) {
return (x0 ^ sm4Lt(x1 ^ x2 ^ x3 ^ rk));
}

static unsigned long sm4CalciRK(unsigned long ka) {
unsigned long bb = 0;
unsigned long rk = 0;
unsigned char a[4];
unsigned char b[4];
PUT_ULONG_BE(ka, a, 0)
b[0] = sm4Sbox(a[0]);
b[1] = sm4Sbox(a[1]);
b[2] = sm4Sbox(a[2]);
b[3] = sm4Sbox(a[3]);
GET_ULONG_BE(bb, b, 0)
rk = bb ^ (ROTL(bb, 11)) ^ (ROTL(bb, 25));
return rk;
}
static void sm4_setkey(unsigned long SK[32], unsigned char key[16]) {
unsigned long MK[4];
unsigned long k[36];
unsigned long i = 0;

GET_ULONG_BE(MK[0], key, 0);
GET_ULONG_BE(MK[1], key, 4);
GET_ULONG_BE(MK[2], key, 8);
GET_ULONG_BE(MK[3], key, 12);
k[0] = MK[0] ^ FK[0];
k[1] = MK[1] ^ FK[1];
k[2] = MK[2] ^ FK[2];
k[3] = MK[3] ^ FK[3];
for (; i < 32; i++) {
k[i + 4] = k[i] ^ (sm4CalciRK(k[i + 1] ^ k[i + 2] ^ k[i + 3] ^ CK[i]));
SK[i] = k[i + 4];
}
}

static void sm4_one_round(unsigned long sk[32], unsigned char input[16],
unsigned char output[16]) {
unsigned long i = 0;
unsigned long ulbuf[36];

memset(ulbuf, 0, sizeof(ulbuf));
GET_ULONG_BE(ulbuf[0], input, 0)
GET_ULONG_BE(ulbuf[1], input, 4)
GET_ULONG_BE(ulbuf[2], input, 8)
GET_ULONG_BE(ulbuf[3], input, 12)
while (i < 32) {
ulbuf[i + 4] =
sm4F(ulbuf[i], ulbuf[i + 1], ulbuf[i + 2], ulbuf[i + 3], sk[i]);
i++;
}
PUT_ULONG_BE(ulbuf[35], output, 0);
PUT_ULONG_BE(ulbuf[34], output, 4);
PUT_ULONG_BE(ulbuf[33], output, 8);
PUT_ULONG_BE(ulbuf[32], output, 12);
}

void sm4_setkey_enc(sm4_context *ctx, unsigned char key[16]) {
ctx->mode = SM4_ENCRYPT;
sm4_setkey(ctx->sk, key);
}

void sm4_setkey_dec(sm4_context *ctx, unsigned char key[16]) {
int i;
ctx->mode = SM4_DECRYPT;
sm4_setkey(ctx->sk, key);
for (i = 0; i < 16; i++) {
SWAP(ctx->sk[i], ctx->sk[31 - i]);
}
}

void sm4_crypt_ecb(sm4_context *ctx, int mode, int length, unsigned char *input,
unsigned char *output) {
while (length > 0) {
sm4_one_round(ctx->sk, input, output);
input += 16;
output += 16;
length -= 16;
}
}

void sm4_crypt_cbc(sm4_context *ctx, int mode, int length, unsigned char iv[16],
unsigned char *input, unsigned char *output) {
int i;
unsigned char temp[16];

if (mode == SM4_ENCRYPT) {
while (length > 0) {
for (i = 0; i < 16; i++)
output[i] = (unsigned char)(input[i] ^ iv[i]);

sm4_one_round(ctx->sk, output, output);
memcpy(iv, output, 16);

input += 16;
output += 16;
length -= 16;
}
} else /* SM4_DECRYPT */
{
while (length > 0) {
memcpy(temp, input, 16);
sm4_one_round(ctx->sk, input, output);

for (i = 0; i < 16; i++)
output[i] = (unsigned char)(output[i] ^ iv[i]);

memcpy(iv, temp, 16);

input += 16;
output += 16;
length -= 16;
}
}
}

int main() {
unsigned char key[16] = "SECCON CTF 2023!";
unsigned char input[112] = {
0xFE, 0x60, 0xA8, 0xC0, 0x3B, 0xFE, 0xBC, 0x66, 0xFC, 0x9A, 0x9B, 0x31,
0x9A, 0xD8, 0x03, 0xBB, 0xA9, 0xE1, 0x56, 0xFC, 0xFC, 0x11, 0x9F, 0x89,
0x5F, 0x4D, 0x9F, 0xE0, 0x9F, 0xAE, 0x2A, 0xCF, 0x5E, 0x73, 0xCB, 0xEC,
0x3F, 0xFF, 0xB9, 0xD1, 0x99, 0x44, 0x1B, 0x9A, 0x79, 0x79, 0xEC, 0xD1,
0xB4, 0xFD, 0xEA, 0x2B, 0xE2, 0xF1, 0x1A, 0x70, 0x76, 0x3C, 0x2E, 0x7F,
0x3F, 0x3B, 0x7B, 0x66, 0xA3, 0x4B, 0x1B, 0x5C, 0x0F, 0xBE, 0xDD, 0x98,
0x5A, 0x5B, 0xD0, 0x0A, 0x3D, 0x7E, 0x2C, 0x10, 0x56, 0x2A, 0x10, 0x87,
0x5D, 0xD9, 0xB9, 0x7F, 0x3E, 0x2E, 0x86, 0xB7, 0x17, 0x04, 0xDF, 0xB1,
0x27, 0xC4, 0x47, 0xE2, 0xD9, 0x7A, 0x9A, 0x48, 0x7C, 0xDB, 0xC6, 0x1D,
0x3C, 0x00, 0xA3, 0x21};

unsigned char output[112];
sm4_context ctx;
unsigned long i;

// sm4_setkey_enc(&ctx, key);
// sm4_crypt_ecb(&ctx, 1, 64, input, output);
// for (i = 0; i < 64; i++)
// printf("%02x ", output[i]);
// printf("\n");

sm4_setkey_dec(&ctx, key);
sm4_crypt_ecb(&ctx, 0, 112, input, output);
for (i = 0; i < 112; i++)
printf("%c", output[i]);
printf("\n");
return 0;
}
balsn-ctf-2023 hitcon-quals-2023

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×