HWSCTF2022初赛WriteUp

HWS2022 WriteUp

reverse

re1

TEA变种,key为0x1234,0x2345, 0x4567, 0x6789, 直接对密文进行解密即可

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

#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>

unsigned char ciphertext[] =
{
0x47, 0x3B, 0xBD, 0x10, 0xF9, 0xE0, 0x55, 0x61, 0xC5, 0xEB,
0xF7, 0x6A, 0x5F, 0x43, 0x23, 0x8D, 0x05, 0x16, 0x09, 0x1A,
0xEF, 0x40, 0x3D, 0xD4, 0x67, 0x6A, 0xB1, 0xB4, 0xA9, 0x78,
0x35, 0x6B, 0x00};

void decrypt(unsigned int *a2)
{
unsigned int a_7; // r9d
unsigned int sum; // edi
unsigned int a_1; // ebp
unsigned int a_0; // esi
unsigned int a_2; // r14d
unsigned int a_3; // r15d
unsigned int a_4; // r12d
unsigned int a_5; // r13d
uint32_t *v10; // r11
uint32_t *v11; // r10
uint64_t v12; // rbx
uint32_t *v13; // r9
uint64_t result; // rax
bool v15; // zf
unsigned int a_6; // [rsp+40h] [rbp+8h]
int v17; // [rsp+48h] [rbp+10h]
unsigned int a_7_; // [rsp+50h] [rbp+18h]
uint32_t key_14000403[] = {
0x1234, 0x2345, 0x4567, 0x6789};
a_7 = a2[7];
sum = 0x9E3779B9 * 12;
a_1 = a2[1];
a_0 = *a2;
a_2 = a2[2];
a_3 = a2[3];
a_4 = a2[4];
a_5 = a2[5];
a_6 = a2[6];
a_7_ = a_7;
v17 = 12;
do
{

v15 = v17-- == 1;

v12 = (sum >> 2) & 3 ^ 3;
v13 = &key_14000403[(sum >> 2) & 3 ^ 2];
v11 = &key_14000403[(sum >> 2) & 3 ^ 1];

v10 = a2[6];
result = sum ^ a_0;
a_7_ -= (result + (key_14000403[v12] ^ (unsigned int)v10)) ^ (((16 * (uint32_t)v10) ^ (a_0 >> 3)) + (((unsigned int)v10 >> 5) ^ (4 * a_0)));
a_7 = a_7_;
a2[7] = a_7_;

(v10) = a_6 - (((sum ^ a_7_) + (*v13 ^ a_5)) ^ (((16 * a_5) ^ (a_7_ >> 3)) + ((a_5 >> 5) ^ (4 * a_7_))));
a2[6] = (unsigned int)v10;
a_6 = (unsigned int)v10;

v10 = &key_14000403[(sum >> 2) & 3];
a_5 -= ((*v11 ^ a_4) + (sum ^ a_6)) ^ (((16 * a_4) ^ (a_6 >> 3)) + ((a_4 >> 5) ^ (4 * a_6)));
a2[5] = a_5;

a_4 -= ((sum ^ a_5) + (*v10 ^ a_3)) ^ (((16 * a_3) ^ (a_5 >> 3)) + ((a_3 >> 5) ^ (4 * a_5)));
a2[4] = a_4;

a_3 -= ((sum ^ a_4) + (key_14000403[v12] ^ a_2)) ^ (((16 * a_2) ^ (a_4 >> 3)) + ((a_2 >> 5) ^ (4 * a_4)));
a2[3] = a_3;

a_2 -= ((sum ^ a_3) + (*v13 ^ a_1)) ^ (((16 * a_1) ^ (a_3 >> 3)) + ((a_1 >> 5) ^ (4 * a_3)));
a2[2] = a_2;

a_1 -= ((*v11 ^ a_0) + (sum ^ a_2)) ^ (((16 * a_0) ^ (a_2 >> 3)) + ((a_0 >> 5) ^ (4 * a_2)));
a2[1] = a_1;

a_0 -= ((sum ^ a_1) + (*v10 ^ a_7)) ^ (((16 * a_7) ^ (a_1 >> 3)) + ((a_7 >> 5) ^ (4 * a_1)));
*a2 = a_0;

sum -= 0x9E3779B9;
} while (!v15);
}

int main(int argc, const char *argv[])
{
decrypt(ciphertext);
uint8_t *sb = (uint8_t *)ciphertext;
printf("\nok\n");
for (int i = 0; i < 32; i++)
{
printf("0x%x ", sb[i]);
}
printf("\n%s\n", ciphertext);
return 0;
}

re2

rc4解密,最后要异或72

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
#include <stdio.h>
#include <stdint.h>

uint8_t secrets[] = {
0x7F, 0xB6, 0x88, 0x12, 0xDC, 0xC3, 0xDE, 0xDB, 0x30, 0x24,
0xE3, 0xC1, 0x0F, 0xC9, 0x7F, 0xC2, 0x4D, 0x9C, 0x6B, 0x02,
0x26, 0x20, 0xF1, 0x25, 0xA0, 0xE3, 0xC6, 0xDE,
0x00
};

int SECRET_LEN = 28;

int sub_401040()
{
char *v2; // ecx
int j; // ebx
int v6; // [esp-Ch] [ebp-50548h]
int v7; // [esp-8h] [ebp-50544h]
int v8[65534]; // [esp+Ch] [ebp-50530h]
char sbox[66816]; // [esp+40004h] [ebp-10538h] BYREF
int key[6]; // [esp+50504h] [ebp-38h]
char *v11; // [esp+5051Ch] [ebp-20h]
int v12; // [esp+50520h] [ebp-1Ch]
int v13; // [esp+50524h] [ebp-18h]
int v14; // [esp+50528h] [ebp-14h]
int v15; // [esp+5052Ch] [ebp-10h]
int v16; // [esp+50530h] [ebp-Ch]
int v17; // [esp+50534h] [ebp-8h]
int i; // [esp+50538h] [ebp-4h]

do
secrets[v16++] ^= 0;
while (secrets[v16]);
printf("ok\n");
key[0] = 81;
key[1] = 102;
key[2] = 114;
key[3] = 111;
key[4] = 115;
key[5] = 116;
printf("ok\n");
for (i = 0; i < 256; ++i)
*(uint32_t *)&sbox[4 * i + 0x10100] = i;
printf("ok\n");
for (i = 0; i < 256; ++i)
sbox[i + 0x10000] = key[i % 6];
printf("ok\n");
v17 = 0;
for (i = 0; i < 256; ++i)
{
v17 = (sbox[i + 0x10000] + *(uint32_t *)&sbox[4 * i + 0x10100] + v17) % 256;
v14 = *(uint32_t *)&sbox[4 * i + 0x10100];
*(uint32_t *)&sbox[4 * i + 0x10100] = *(uint32_t *)&sbox[4 * v17 + 0x10100];
*(uint32_t *)&sbox[4 * v17 + 0x10100] = v14;
}
printf("ok\n");
// v15 = dword_41B2E8;
v15 = SECRET_LEN;
v13 = 0;
v17 = 0;
i = 0;
while (v15--)
{
i = (i + 1) % 256;
v17 = (*(uint32_t *)&sbox[4 * i + 65792] + v17) % 256;
v14 = *(uint32_t *)&sbox[4 * i + 65792];
*(uint32_t *)&sbox[4 * i + 65792] = *(uint32_t *)&sbox[4 * v17 + 65792];
*(uint32_t *)&sbox[4 * v17 + 65792] = v14;
v12 = (*(uint32_t *)&sbox[4 * v17 + 65792] + *(uint32_t *)&sbox[4 * i + 0x10100]) % 256;
v8[v13++] = *(uint32_t *)&sbox[4 * v12 + 65792];
}
printf("ok\n");
for (i = 0; i < SECRET_LEN; ++i)
sbox[i] = (uint8_t)(v8[i]) ^ secrets[i];
printf("ok\n");
v11 = sbox;
for (j = 0; j < SECRET_LEN; ++j)
{
printf("%c", v11[j] ^ 72);
}
return 0;
}

int main(int argc, const char *argv[])
{
sub_401040();
return 0;
}

misc

最伟大的作品

通过钢琴不难猜到要找的每个音符(没学过钢琴不知道音符这个词对不对),通过anthemScore进行识别。

random

seed已知,那么就可以推导出每次的随机数,shuffle亦可以逆推

首先逆推shuffle

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
import random
from PIL import Image

random.seed(793211)
cat = Image.open('1.png')
x, y = cat.size
bits = x * y
num = random.getrandbits(bits)
# print(num)
num = random.getrandbits(bits)
# print(num)
FLAG = b'a' * 28
rn = random.getrandbits((bits - len(FLAG)) * 8)
# print(rn)
r3 = list(range(bits))
# print(r3)
random.shuffle(r3)
# print(r3)
sidx = [0] * 28
i = 0
for idx, val in enumerate(r3):
if 0 <= val <= 27:
print(val, 'shuffled to index ', idx)
sidx[val] = idx
i += 1

print(i)
print(len(sidx))
print(sidx)

然后通过输出的sidx进行解密

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
import random
from PIL import Image
from hashlib import md5
from Crypto.Util.number import long_to_bytes as n2b

xx = Image.open('./xx.png')
cat = Image.open('1.png')
xx_size = xx.size
xx_x, xx_y = xx_size
cat_size = cat.size
cat_x, cat_y = cat_size
bits = cat_x * cat_y
r1 = [0] * bits
r3 = [0] * bits
print(bits)
sidx = [8782, 2846, 7397, 27016, 4439, 21573, 3086, 24287, 24106, 2626, 19741, 27445, 24191, 14995,
1928, 15300, 6853, 16317, 12778, 2888, 9656, 12191, 22583, 13212, 4385, 3928, 24431, 10939]
xx_pixels = []


for i in range(xx_x):
for j in range(xx_y):
p_xx = xx.getpixel((i, j))
p_cat = cat.getpixel((i, j))
xx_pixels.append(p_xx[2] ^ p_cat[2])

print(len(xx_pixels))
print((xx_pixels))

for idx, val in enumerate(sidx):
print(chr(xx_pixels[val]), end='')


crypto

easyrsa

LCG,直接套脚本就可以了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from Crypto.Util.number import *

p = 31893593182018727625473530765941216190921866039118147474754069955393226712079257707838327486268599271803

output = [
25820280412859586557218124484272275594433027771091486422152141535682739897353623931875432576083022273940,
24295465524789348024814588142969609603624462580932512051939198335014954252359986260009296537423802567677,
14963686422550871447791815183480974143372785034397446416396172429864269108509521776424254168481536292904
]
n = p

MMI = lambda A, n,s=1,t=0,N=0: (n < 2 and t%N or MMI(n, A%n, t, s-A//n*t, N or n),-1)[n<1] #逆元计算
a=(output[2]-output[1])*MMI((output[1]-output[0]),n)%n
ani=MMI(a,n)
b=(output[1]-a*output[0])%n
seed = (ani*(output[0]-b))%n
plaintext=seed
print(long_to_bytes(plaintext))

side channel

Read&Solve

RSA的侧信道攻击,直接把高波峰转换成1,低的转换成0,也就是1010110100101100,然后转换成16进制ad2c即可