浙江省省赛2024决赛wp

Re

Re2

upx魔改

然后直接base64变表

Re1

Rc4得到真正的key

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
def rc4(data, key):
S = list(range(256))
j = 0
out = []

for i in range(256):
j = (j + S[i] + key[i % len(key)]) % 256
S[i], S[j] = S[j], S[i]

i = j = 0
for char in data:
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i]
out.append(char ^ S[(S[i] + S[j]) % 256])

return out


data = b'ban_debug!'
key = b'keykey'
decrypted = rc4(data, key)
print(decrypted)

#[105, 13, 90, 178, 64, 234, 25, 63, 47, 106]

crypto2魔改rc4

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
def rc4(data, key):
S = list(range(256))
j = 0
out = []

for i in range(256):
j = (j + S[i] + key[i % len(key)]) % 256
S[i], S[j] = S[j], S[i]

i = j = 0
for char in data:
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i]
char+=S[(S[i] + S[j]) % 256]
char%=256
out.append(char)

return bytes(out)


data = bytes([ 0x4E, 0x47, 0x38, 0x47, 0x62, 0x0A, 0x79, 0x6A, 0x03, 0x66,
0xC0, 0x69, 0x8D, 0x1C, 0x84, 0x0F, 0x54, 0x4A, 0x3B, 0x08,
0xE3, 0x30, 0x4F, 0xB9, 0x6C, 0xAB, 0x36, 0x24, 0x52, 0x81,
0xCF])
key = bytes([105, 13, 90, 178, 64, 234, 25, 63, 47, 106])
decrypted = rc4(data, key)
print(decrypted)

#b'flag{1237-12938-9372-1923-4u92}'

Re3-1

题目提示debug,一开始tls得到1.exe

v4像key,后面是分组加密

一眼aes

但是怎么解密都不对,回去看re3.exe

得到标准aes的s盒

pangbai师傅的思路:用frida尝试去hook,因为不会被反调试检测

先运行Reverse3.exe再执行frida -l .\hook.js -n 1.exe

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
var inter=setInterval(function () {
var sgame = Process.findModuleByName("1.exe");
if(sgame==null){
console.log("无");
return;
}


clearInterval(inter);
console.log(""+sgame.base.add(0x001EC9 ));
Interceptor.attach(sgame.base.add(0x001EC9 ), {
onEnter: function (args) {
var rax=this.context.rax;
console.log("" +rax);
// 检查密文有没有被修改
console.log(hexdump(ptr(rax),{length: 50,ansi:true}));


}
})

Interceptor.attach(sgame.base.add(0x001E2C ), {
onEnter: function (args) {

console.log("input flag");
// 检查输入 flag 的时候有没有被修改
console.log(hexdump(ptr(this.context.rdx),{length: 16,ansi:true}));

}
})

Interceptor.attach(sgame.base.add(0x1380), {
onEnter: function (args) {
var rdx=this.context.rdx;
// 检查 key ,sbox , 进入函数的 flag 有没有被修改
console.log("key" );
console.log(hexdump(ptr(rdx),{length: 16,ansi:true}));
console.log("flag:" );
console.log(hexdump(ptr(this.context.rcx),{length: 16,ansi:true}));
console.log("sbox:" );
console.log(hexdump(ptr(sgame.base.add(0x5160)),{length: 256,ansi:true}));
}
})
} , 1)

input flag有变化说明进入aes加密的明文有偏移,总共33次调用sub_140001380,对应3组密文,所以密文长度为48

输入0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&’()*+,-./:;<=>?@[\]^_得到新的映射表

修改后的密文

最终脚本

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
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
void AddRoundKey(unsigned char *plaintext, unsigned char * CipherKey)/* 轮密钥加 */
{
for (int j = 0; j < 16; j++) plaintext[j] = plaintext[j] ^ CipherKey[j];
}
void SubBytes(unsigned char *plaintext, unsigned char *plaintextencrypt, int count)/*S 盒置换 */
{
unsigned int row, column;
unsigned char Sbox[16][16] = {
/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
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

};// 填充 Sbox 矩阵
for (int i = 0; i < count; i++)
{
row = (plaintext[i] & 0xF0) >> 4;
column = plaintext[i] & 0x0F;
plaintextencrypt[i] = Sbox[row][column];
}
}
void SubBytesRe(unsigned char *plaintext, unsigned char *plaintextencrypt, int count)/*S 盒逆置换 */
{
unsigned int row, column;
unsigned char Sbox[16][16] = {
82, 9, 106, 213, 48, 54, 165, 56, 191, 64, 163, 158, 129, 243, 215, 251, 124, 227, 57, 130, 155, 47, 255, 135, 52, 142, 67, 68, 196, 222, 233, 203, 84, 123, 148, 50, 166, 194, 35, 61, 238, 76, 149, 11, 66, 250, 195, 78, 8, 46, 161, 102, 40, 217, 36, 178, 118, 91, 162, 73, 109, 139, 209, 37, 114, 248, 246, 100, 134, 104, 152, 22, 212, 164, 92, 204, 93, 101, 182, 146, 108, 112, 72, 80, 253, 237, 185, 218, 94, 21, 70, 87, 167, 141, 157, 132, 144, 216, 171, 0, 140, 188, 211, 10, 247, 228, 88, 5, 184, 179, 69, 6, 208, 44, 30, 143, 202, 63, 15, 2, 193, 175, 189, 3, 1, 19, 138, 107, 58, 145, 17, 65, 79, 103, 220, 234, 151, 242, 207, 206, 240, 180, 230, 115, 150, 172, 116, 34, 231, 173, 53, 133, 226, 249, 55, 232, 28, 117, 223, 110, 71, 241, 26, 113, 29, 41, 197, 137, 111, 183, 98, 14, 170, 24, 190, 27, 252, 86, 62, 75, 198, 210, 121, 32, 154, 219, 192, 254, 120, 205, 90, 244, 31, 221, 168, 51, 136, 7, 199, 49, 177, 18, 16, 89, 39, 128, 236, 95, 96, 81, 127, 169, 25, 181, 74, 13, 45, 229, 122, 159, 147, 201, 156, 239, 160, 224, 59, 77, 174, 42, 245, 176, 200, 235, 187, 60, 131, 83, 153, 97, 23, 43, 4, 126, 186, 119, 214, 38, 225, 105, 20, 99, 85, 33, 12, 125 }; // 填充 Sbox 矩阵
for (int i = 0; i < count; i++)
{
row = (plaintext[i] & 0xF0) >> 4;
column = plaintext[i] & 0x0F;
plaintextencrypt[i] = Sbox[row][column];
}
}
void ShiftRowsRe(unsigned char *plaintextencrypt)/* 行移位的逆 */
{
unsigned char temp = 0;
for (int i = 0; i < 4; i++)// 第 i 行
{
for (int j = 0; j < 4 - i; j++)// 第 j 次左移
{
temp = plaintextencrypt[i];
for (int k = 0; k < 4; k++)
plaintextencrypt[i + 4 * k] = plaintextencrypt[i + 4 * (k + 1)];
plaintextencrypt[i + 12] = temp;
}
}
}
void ShiftRows(unsigned char *plaintextencrypt)/* 行移位 */
{
unsigned char temp = 0;
for (int i = 0; i < 4; i++)// 第 i 行
{
for (int j = 0; j < i; j++)// 第 j 次左移
{
temp = plaintextencrypt[i];
for (int k = 0; k < 4; k++)
plaintextencrypt[i + 4 * k] = plaintextencrypt[i + 4 * (k + 1)];
plaintextencrypt[i + 12] = temp;
}
}
}
unsigned char Mult2(unsigned char num)/* 列混淆 */
{
unsigned char temp = num << 1;
if ((num >> 7) & 0x01)
temp = temp ^ 27;
return temp;
}
unsigned char Mult3(unsigned char num)
{
return Mult2(num) ^ num;
}
void MixColumns(unsigned char *plaintextencrypt, unsigned char *plaintextcrypt)
{
int i;
for (i = 0; i < 4; i++)
plaintextcrypt[4 * i] = Mult2(plaintextencrypt[4 * i]) ^ Mult3(plaintextencrypt[4 * i + 1]) ^ plaintextencrypt[4 * i + 2] ^ plaintextencrypt[4 * i + 3];
for (i = 0; i < 4; i++)
plaintextcrypt[4 * i + 1] = plaintextencrypt[4 * i] ^ Mult2(plaintextencrypt[4 * i + 1]) ^ Mult3(plaintextencrypt[4 * i + 2]) ^ plaintextencrypt[4 * i + 3];
for (i = 0; i < 4; i++)
plaintextcrypt[4 * i + 2] = plaintextencrypt[4 * i] ^ plaintextencrypt[4 * i + 1] ^ Mult2(plaintextencrypt[4 * i + 2]) ^ Mult3(plaintextencrypt[4 * i + 3]);
for (i = 0; i < 4; i++)
plaintextcrypt[4 * i + 3] = Mult3(plaintextencrypt[4 * i]) ^ plaintextencrypt[4 * i + 1] ^ plaintextencrypt[4 * i + 2] ^ Mult2(plaintextencrypt[4 * i + 3]);
}
/* 逆列混淆 */
#define xtime(x) ((x<<1) ^ (((x>>7) & 1) * 0x1b))
#define Multiply(x,y) (((y & 1) * x) ^ ((y>>1 & 1) * xtime(x)) ^ ((y>>2 & 1) * xtime(xtime(x))) ^ ((y>>3 & 1) * xtime(xtime(xtime(x)))) ^ ((y>>4 & 1) * xtime(xtime(xtime(xtime(x))))))
void MixColumnsRe(unsigned char *state)
{

unsigned char a, b, c, d;
for (int i = 0; i < 4; i++)
{
a = state[4*i];
b = state[4*i+1];
c = state[4*i+2];
d = state[4*i+3];
state[4 * i] = Multiply(a, 0x0e) ^ Multiply(b, 0x0b) ^ Multiply(c, 0x0d) ^ Multiply(d, 0x09);
state[4 * i + 1] = Multiply(a, 0x09) ^ Multiply(b, 0x0e) ^ Multiply(c, 0x0b) ^ Multiply(d, 0x0d);
state[4 * i + 2] = Multiply(a, 0x0d) ^ Multiply(b, 0x09) ^ Multiply(c, 0x0e) ^ Multiply(d, 0x0b);
state[4 * i + 3] = Multiply(a, 0x0b) ^ Multiply(b, 0x0d) ^ Multiply(c, 0x09) ^ Multiply(d, 0x0e);
}
}
int CharToWord(unsigned char *character, int first)/* 字节转字 */
{
return (((int)character[first] & 0x000000ff) << 24) | (((int)character[first + 1] & 0x000000ff) << 16) | (((int)character[first + 2] & 0x000000ff) << 8) | ((int)character[first + 3] & 0x000000ff);
}
void WordToChar(unsigned int word, unsigned char *character)/* 字转字节 */
{
for (int i = 0; i < 4; character[i++] = (word >> (8 * (3 - i))) & 0xFF);
}
void ExtendCipherKey(unsigned int *CipherKey_word, int round)/* 密钥扩展 */
{
unsigned char CipherKeyChar[4] = { 0 },CipherKeyCharEncrypt[4] = { 0 };
unsigned int Rcon[10] = { 0x01000000,0x02000000,0x04000000,0x08000000,0x10000000,0x20000000,0x40000000,0x80000000,0x1B000000,0x36000000 }; // 轮常量
for (int i = 4; i < 8; i++)
{
if (!(i % 4))
{
WordToChar((CipherKey_word[i - 1] >> 24) | (CipherKey_word[i - 1] << 8), CipherKeyChar);
SubBytes(CipherKeyChar, CipherKeyCharEncrypt, 4);
CipherKey_word[i] = CipherKey_word[i - 4] ^ CharToWord(CipherKeyCharEncrypt, 0) ^ Rcon[round];
}
else
CipherKey_word[i] = CipherKey_word[i - 4] ^ CipherKey_word[i - 1];
}
}
#include <stdlib.h>
void genString(int size){
char *text = (char *)malloc(size * sizeof(char));
for (size_t i = 0; i < size; i++)
{
text[i]=35+i;
}
puts(text);

}
char table[]="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~ ";
char res[]={0x36,0x35,0x34,0x33,0x3a,0x39,0x38,0x37,0x3e,0x3d,0x85,0x84,0x83,0x8a,0x89,0x88,0x87,0x8e,0x8d,0x8c,0x8b,0x92,0x91,0x90,0x8f,0x76,0x75,0x74,0x73,0x7a,0x79,0x78,0x77,0x7e,0x7d,0x7c,0xa5,0xa4,0xa3,0xaa,0xa9,0xa8,0xa7,0xae,0xad,0xac,0xab,0xb2,
0xb1,0xb0,0xaf,0x96,0x95,0x94,0x93,0x9a,0x99,0x98,0x97,0x9e,0x9d,0x9c,0x45,0x44,0x43,0x4a,0x49,0x48,0x47,0x4e,0x4d,0x4c,0x4b,0x52,0x51,0x50,0x4f,0x3c,0x3b,0x42,0x41,0x40,0x3f,0xa6,0x9b,0xa2,0xa1,0xa0,0x9f,0x86,0x7b,0x82,0x81,0x80,0x66,0x66
};
char getcc(char in){
for (size_t i = 0; i < 96; i++)
{
if (in==res[i])
{
return table[i];
}

}
}
void main()
{
printf("**************AES加解密***************\n");
int i = 0, k;
unsigned mm[]={0x71,0x55,0x7f,0xa8,0xfa,0x0e,0xa3,0x19,0xa0,0x5c,0xf9,0x0e,0x9b,0x0b,0x5e,0xfc,0xb5,0xa8,0x49,0xfd,0x90,0x99,0x74,0xc7,0x77,0x02,0x6a,0xf5,0x9a,0x6a,0xba,0x7f,0xfb,0xe7,0x68,0xda,0x54,0xee,0xe8,0xbb,0x78,0x01,0xe7,0xbb,0xa2,0x95,0x95,0xfa};
unsigned char PlainText[48] ="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
,
CipherKey[16] = { 0x05,0x06,0x07,0x08,0x37,0x42,0x4d,0x58,0x63,0x00,0x0a,0x0c,0x0d,0x0e,0x0f,0x10 },
CipherKey1[16] = { 0x05,0x06,0x07,0x08,0x37,0x42,0x4d,0x58,0x63,0x00,0x0a,0x0c,0x0d,0x0e,0x0f,0x10},
PlainText1[48] = {
0x71, 0x55, 0x7F, 0xA8, 0xFA, 0x0E, 0xA3, 0x19, 0xA0, 0x5C, 0xF9, 0x0E, 0x9B, 0x0B, 0x5E, 0xFC,
0xB5, 0xA8, 0x49, 0xFD, 0x90, 0x99, 0x74, 0xC7, 0x77, 0x02, 0x6A, 0xF5, 0x9A, 0x6A, 0xBA, 0x7F,
0xFB, 0xE7, 0x68, 0xDA, 0x54, 0xEE, 0xE8, 0xBB, 0x78, 0x01, 0xE7, 0xBB, 0xA2, 0x95, 0x95, 0xFA

},
PlainText2[48] = { 0x71, 0x55, 0x7F, 0xA8, 0xFA, 0x0E, 0xA3, 0x19, 0xA0, 0x5C, 0xF9, 0x0E, 0x9B, 0x0B, 0x5E, 0xFC,
0xB5, 0xA8, 0x49, 0xFD, 0x90, 0x99, 0x74, 0xC7, 0x77, 0x02, 0x6A, 0xF5, 0x9A, 0x6A, 0xBA, 0x7F,
0xFB, 0xE7, 0x68, 0xDA, 0x54, 0xEE, 0xE8, 0xBB, 0x78, 0x01, 0xE7, 0xBB, 0xA2, 0x95, 0x95, 0xFA
};
unsigned int CipherKey_word[44] = { 0 };
for (i = 0; i < 4; CipherKey_word[i++] = CharToWord(CipherKey, 4 * i));
printf("密钥:");
for (k = 0; k < 16; k++) printf("%2X ", CipherKey[k]);
printf("\n明文:");
for (k = 0; k < 16; k++) printf("%02X ", PlainText[k]);
printf("\n**************开始加密****************");
AddRoundKey(PlainText, CipherKey);
for (i = 0; i < 9; i++)
{
SubBytes(PlainText, PlainText1, 16);/*S 盒置换 */
ShiftRows(PlainText1); /* 行移位 */
MixColumns(PlainText1, PlainText2); /* 列混淆 */
ExtendCipherKey(CipherKey_word + 4 * i, i);/* 子密钥生成 */
for (k = 0; k < 4; k++) WordToChar(CipherKey_word[k + 4 * (i + 1)], CipherKey + 4 * k);
for (k = 0; k < 16; k++) printf("%02X ", CipherKey[k]);
AddRoundKey(PlainText2, CipherKey);/* 轮密钥加 */
for (k = 0; k < 16; k++) PlainText[k] = PlainText2[k];
}

SubBytes(PlainText, PlainText1, 16);
ShiftRows(PlainText1);
ExtendCipherKey(CipherKey_word + 4 * i, i);
for (k = 0; k < 4;WordToChar(CipherKey_word[k + 4 * (i + 1)], CipherKey + 4 * k), k++);
AddRoundKey(PlainText1, CipherKey);
printf("\n\n最终AES加密后的密文为:");
for (i = 0; i < 16; i++) printf("%02X ", PlainText1[i]);

for (size_t i = 0; i < 16; i++)
{
PlainText1[i]=mm[i+16]; // 解密第二段第三段偏移 16,32 即可
}


printf("\n\n**************开始解密***************");
AddRoundKey(PlainText1, CipherKey);
for (i = 0; i < 9; i++)
{
SubBytesRe(PlainText1, PlainText, 16);/*S 盒置换 */
for (k = 0; k < 4; WordToChar(CipherKey_word[k + 40 - 4 * (i + 1)], CipherKey + 4 * k),k++);/* 子密钥生成 */
ShiftRowsRe(PlainText);/* 行移位逆 */
AddRoundKey(PlainText, CipherKey);/* 轮密钥加 */
MixColumnsRe(PlainText);/* 列混淆逆运算 */
for (k = 0; k < 16;PlainText1[k] = PlainText[k],k++);
}
printf("\n最后一次循环:");
ShiftRowsRe(PlainText);/* 行移位逆 */
SubBytesRe(PlainText, PlainText1, 16);/*S 盒置换 */
AddRoundKey(PlainText1, CipherKey1);
printf("\n最终AES解密后的明文为:");

for (i = 0; i < 16; i++) printf("%c",getcc( PlainText1[i]));
printf("\n");

}

最后的flag:ffYffnfffff6rfffKBf|KLfzfx-CfFffffffWfffmfffff~f

Crypto

Mycode

加解密脚本都写好了,直接fromhex然后爆破即可

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
import numpy as np

def substitute(state, sub_box):
return [sub_box[b & 0xF] | (sub_box[(b >> 4) & 0xF] << 4) for b in state]

def generate_round_keys(base_key, rounds):
round_keys = []
temp_key = base_key
for _ in range(rounds):
round_keys.append(temp_key & 0xFFFFFFFF)
temp_key ^= ((temp_key << 1) & 0xFFFFFFFF) | ((temp_key >> 31) & 0x1)
return round_keys

def process_state(base_key, state, rounds, encrypt):
sub_box = [0x9, 0x4, 0xA, 0xB, 0xD, 0x1, 0x8, 0x5, 0x6, 0x2, 0x0, 0x3, 0xC, 0xE, 0xF, 0x7]
inv_sub_box = [0xA, 0x5, 0x9, 0xB, 0x1, 0x7, 0x8, 0xF, 0x6, 0x0, 0x2, 0x3, 0xC, 0x4, 0xD, 0xE]

round_keys = generate_round_keys(base_key, rounds)

if encrypt:
for round in range(rounds):
state = substitute(state, sub_box)
state = [s ^ ((round_keys[round] >> (i * 8)) & 0xFF) for i, s in enumerate(state)]
else:
for round in range(rounds - 1, -1, -1):
state = [s ^ ((round_keys[round] >> (i * 8)) & 0xFF) for i, s in enumerate(state)]
state = substitute(state, inv_sub_box)

return state

def encrypt(plaintext, key, rounds=10):
length = len(plaintext)
padded_length = length if length % 4 == 0 else length + (4 - (length % 4))
plaintext += b'\x00' * (padded_length - length)

ciphertext = bytearray(padded_length)
for i in range(0, padded_length, 4):
state = list(plaintext[i:i+4])
state = process_state(key, state, rounds, True)
ciphertext[i:i+4] = state

return ciphertext

def decrypt(ciphertext, key, rounds=10):
length = len(ciphertext)
plaintext = bytearray(length)
for i in range(0, length, 4):
state = list(ciphertext[i:i+4])
state = process_state(key, state, rounds, False)
plaintext[i:i+4] = state

return plaintext.rstrip(b'\x00')

# def main():
# plaintext = b"DASCTF{******}"
# key = 0xECB... # 4 bytes
# ciphertext = encrypt(plaintext, key)
# print("Ciphertext:", ''.join(f"{b:02X}" for b in ciphertext))


Ciphertext='A6B343D2C6BE1B268C3EA4744E3AA9914E29A0789F299022820299248C23D678442A902B4C24A8784A3EA401'
Ciphertext=bytes.fromhex(Ciphertext)
print(Ciphertext)
for key in range(0xECB00000,0xECBFFFFF):
out=decrypt(Ciphertext,key)
if b'DASCTF' in out:
print(key)
print(out)

#DASCTF{6ef4d8e1-845a-4e3c-a4e1-a15e5530a0f4}

DlcgH-1

看到题目的时候确实慌了,k和t都是512位,爆破不现实,又想到DH算法本身并不会,所以也没做过多尝试就返回去看re了

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
from Crypto.Util.number import *
from gmpy2 import *

flag = b'DASCTF{******}'
def iterate_function(seed, coeff_a, coeff_b, prime_modulus):
return (coeff_a * seed + coeff_b) % prime_modulus

def iterate_multiple_times(seed, num_iterations, coeff_a, coeff_b, prime_modulus):
for _ in range(num_iterations):
seed = iterate_function(seed, coeff_a, coeff_b, prime_modulus)
return seed

p = getPrime(600)
a = getPrime(512)
b = getPrime(512)
s = getPrime(512)
k = getPrime(512)
t = getPrime(512)

A = iterate_multiple_times(s, k, a, b, p)
B = iterate_multiple_times(s, t, a, b, p)

print("p =", p)
print("a =", a)
print("b =", b)
print("s =", s)
print("A =", A)
print("B =", B)

secret1 = iterate_multiple_times(A, k, a, b, p)
secret2 = iterate_multiple_times(B, t, a, b, p)

assert secret1 == secret2
'''
p = 2565258348684709722726260231955260453241716968378483821594041597297293609376806025180965681289016169408781752953380586044352169083397987333072306444539318806255242559916564022662479
a = 7703427441632069990122897903141278700284019287330080801753208940444135129072547305259960648105321270085533531118395452229965873504176368162947864923497711
b = 8477265953761650860710068507342719089504862957398782381045770264963932696457722724393775545810962476516315838411812248360284564925846788951219272632661157
s = 9228773209718156231041982890745928246648483643042884535935071957475932603607283209094294685862893340598940862096657878372229519375655468524041406914666867
A = 434251860827782638796736001849473241231781620594954088572922898040098881748337513244415553659525671751903798527967205418513869125476445927127124010452649344318178999731385274553080
B = 434251860827782638796736001849473241231781620594954088572922898040098881748337513244415553659525671751903798527967205418513869125476445927127124010452649344318178999731385274553080
'''

p2 = next_prime(secret1)
q2 = getPrime(600)
n2 = p2*q2
e = 4
m = bytes_to_long(flag)
c = pow(m, e, n2)
print("n2 =", n2)
print("c =", c)

'''
n2 = 3241139665583501598296135149075754735041636843305130049654913708275571916563715101898946962033698805416493133339619007016676895968314902474922279948997540924678346952667095320094789476561995339618782687993966133770687551933070478999383821269223854568552819152909266096733330218505088222661907600152055916956562332379930822529724151378274932991887183193175206749
c = 1131281812215293796960536920068009435705926803182047772347743960804329656316689664084120353862091370978145286943689311985878028828902275260824388998300548644880722651153603738691769179255824425771260974588160589473958033612303767050773921373389315920529311000160530833707622310013322631917184737227893101365726934901652170763292132835433158093074003616578836411
'''

赛后看到wp发现可以爆破k,怎么想都不现实,但是别人能出就该想想原本不现实的方法,算出p和q,后来想想%p其实可以循环

发现e和phi不互素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
p=1472490340321845700492870656866629756386520746748019952980831685935628618084832981576756885932019702470337632472478610542460495595381421112792242654382213433012352298291319463142659# n = 3241139665583501598296135149075754735041636843305130049654913708275571916563715101898946962033698805416493133339619007016676895968314902474922279948997540924678346952667095320094789476561995339618782687993966133770687551933070478999383821269223854568552819152909266096733330218505088222661907600152055916956562332379930822529724151378274932991887183193175206749
c = 1131281812215293796960536920068009435705926803182047772347743960804329656316689664084120353862091370978145286943689311985878028828902275260824388998300548644880722651153603738691769179255824425771260974588160589473958033612303767050773921373389315920529311000160530833707622310013322631917184737227893101365726934901652170763292132835433158093074003616578836411
e = 4
q=2201127964530536768531437690590447485511044947862563552674657770394302822371223893779621142446998848918986248500749184930380894798831854267120305815092270548187578354416455278612511
R.<x> = PolynomialRing(GF(p))
f1 = x^4 - c
res1 = f1.roots()
R.<x> = PolynomialRing(GF(q))
f2 = x^4 - c
res2 = f2.roots()

for i in res1:
for j in res2:
m = crt([int(i[0]),int(j[0])],[p,q])
print(long_to_bytes(m))

当然发现p和q都%4=3,也就是用rabin解密

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
import math
from Crypto.Util.number import *
from gmpy2 import *

p = 2565258348684709722726260231955260453241716968378483821594041597297293609376806025180965681289016169408781752953380586044352169083397987333072306444539318806255242559916564022662479
a = 7703427441632069990122897903141278700284019287330080801753208940444135129072547305259960648105321270085533531118395452229965873504176368162947864923497711
b = 8477265953761650860710068507342719089504862957398782381045770264963932696457722724393775545810962476516315838411812248360284564925846788951219272632661157
s = 9228773209718156231041982890745928246648483643042884535935071957475932603607283209094294685862893340598940862096657878372229519375655468524041406914666867
A = 434251860827782638796736001849473241231781620594954088572922898040098881748337513244415553659525671751903798527967205418513869125476445927127124010452649344318178999731385274553080
B = 434251860827782638796736001849473241231781620594954088572922898040098881748337513244415553659525671751903798527967205418513869125476445927127124010452649344318178999731385274553080
n = 3241139665583501598296135149075754735041636843305130049654913708275571916563715101898946962033698805416493133339619007016676895968314902474922279948997540924678346952667095320094789476561995339618782687993966133770687551933070478999383821269223854568552819152909266096733330218505088222661907600152055916956562332379930822529724151378274932991887183193175206749
c = 1131281812215293796960536920068009435705926803182047772347743960804329656316689664084120353862091370978145286943689311985878028828902275260824388998300548644880722651153603738691769179255824425771260974588160589473958033612303767050773921373389315920529311000160530833707622310013322631917184737227893101365726934901652170763292132835433158093074003616578836411
e=4

seed=s
k=0
while seed!=A:
seed=(seed*a+b)%p
k+=1
print(k)

seed=A
for i in range(12345):
seed=(seed*a+b)%p
p=next_prime(seed)
print(p)
q=n//p
print(q)

inv_p = invert(p, q)
inv_q = invert(q, p)

cs = [c]
lge = math.log(e, 2)
for i in range(int(lge)):
ps = []
for c2 in cs:
r = pow(c2, (p + 1) // 4, p)
s = pow(c2, (q + 1) // 4, q)

x = (r * inv_q * q + s * inv_p * p) % n
y = (r * inv_q * q - s * inv_p * p) % n
if x not in ps:
ps.append(x)
if n - x not in ps:
ps.append(n - x)
if y not in ps:
ps.append(y)
if n - y not in ps:
ps.append(n - y)
cs = ps

for m in cs:
flag=long_to_bytes(m)
if b'DASCTF' in flag:
print(flag)

Misc

FinalSign

得到的字符串尝试转化成16进制,去异或DASCTF,看到hellow,猜测循环异或的字符串是helloworld,得到flag

1
2
3
4
5
6
7
8
9
10
11
12
s='2c243f2f3b3114345d0a0909333f06100143023b2c55020912'
print(len(s))
# for i in range(0,len(s),2):
# print(int(s[i:i+2],16),end=",")
a=[44,36,63,47,59,49,20,52,93,10,9,9,51,63,6,16,1,67,2,59,44,85,2,9,18]
print(len(a))
s1='helloworld'
for i in range(len(a)):
print(chr(a[i]^ord(s1[i%len(s1)])),end="")
#print(i)

#DASCTF{F1nal_Sign1n_D0ne}

实际上是snow无密钥解密得到异或的字符串helloworld

信创安全

easy_hpp-1

两次解压得到modules.abc

发现aes和base64,没发现密文,事后想到要搜索等号

看到zjuctf一眼原题但是没做过

也没有so文件,比赛的时候就卡住了

复现的时候找到几乎原题,就是加密有些不一样

Writeups - GoPoux 的笔记本

下载能反编译abc的jadx,找到真正的密文

init函数设置好算法和共同的key,encryptX对应aes_ecb,encryptY对应aes_cbc

总体调用逻辑为encrypt->encryptX->encryptY->encodeX->encodeY

encrypt把明文分成前后各16字节

aes_cbc的iv为aes_ecb的加密结果

encodeX把aes_cbc加密的密文放到前面,把两个密文异或后得到的值放到后面,encodeY为base64

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
import numpy as np
from Crypto.Cipher import AES
import base64

def string_to_uint8_array(s):
return np.array([ord(c) for c in s], dtype=np.uint8)

def encodeX(arg0, arg1):
res = []
for i in range(16):
res.append(arg1[i])
for i in range(16):
res.append(arg0[i] ^ arg1[i])
return res

def encodeY(arg):
return base64.b64encode(bytes(arg)).decode()

def decodeY(arg):
return base64.b64decode(arg)

def decodeX(res):
arg1 = res[:16]
arg0 = res[16:]
for i in range(16):
arg0[i] ^= arg1[i]
return arg0, arg1

commonCipherKey = string_to_uint8_array("DASCTF2024-OHAPP").tobytes()

code = "/aPR+E8wS9+XbFMUfm8NacHpP190pf5xaR8+MIm/8gw="

tmp4 = code

tmp3 = decodeY(tmp4)
tmp3 = [c for c in tmp3]
# print(tmp3)

tmp1, tmp2 = decodeX(tmp3)
tmp1 = bytes(tmp1)
tmp2 = bytes(tmp2)

cipherY = AES.new(commonCipherKey, AES.MODE_CBC, iv=tmp1)
slice2 = cipherY.decrypt(tmp2)
# print(slice2)

cipherX = AES.new(commonCipherKey, AES.MODE_ECB)
slice1 = cipherX.decrypt(tmp1)
# print(slice1)

flag = slice1+ slice2
print(flag)

#b'DASCTF{Ea5Y_ohaPp_&_5iMPl3_fl4g}'

理清思路可以直接借助cyberchef处理

1
2
3
4
5
6
7
8
9
10
result2_hex = 'fda3d1f84f304bdf976c53147e6f0d69'
xor_result_hex = 'c1e93f5f74a5fe71691f3e3089bff20c'

result2_bytes = bytes.fromhex(result2_hex)
xor_result_bytes = bytes.fromhex(xor_result_hex)

result1_bytes = bytes(a ^ b for a, b in zip(result2_bytes, xor_result_bytes))

print(result1_bytes.hex())
#3c4aeea73b95b5aefe736d24f7d0ff65

浙江省省赛2024决赛wp
https://j1ya-22.github.io/2024/11/12/浙江省省赛2024决赛wp/
作者
j1ya
发布于
2024年11月12日
许可协议