GDOUCTF 2023

由于当时比赛那天参加学校活动比较忙错过了比赛,那就看看题吧。

Absolute_Baby_Encrytpion

题目给了一段密文和js代码:

1
+}!q")hiim)#}-nvm)i-$#mvn#0mnbm)im#n+}!qnm8)i-$#mvnoc#0nz<$9inm!>-n1:1-nm8)i-$~c58n!}qhij#0[noic##m8nc8n?!8c}w!n]>&
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
let messagetoEncrypt = prompt("Enter a string: ").toLowerCase();
let charArray = messagetoEncrypt.split("");
let encryptedString = "";
let hasInvalidCharacter = false;

for (let i = 0; i < charArray.length; i++) {
switch (charArray[i]) {
case 'a':
encryptedString = encryptedString.concat('!')
break;
case 'b':
encryptedString = encryptedString.concat('1')
break;
case 'c':
encryptedString = encryptedString.concat(')')
break;
case 'd':
encryptedString = encryptedString.concat('v')
break;
case 'e':
encryptedString = encryptedString.concat('m')
break;
case 'f':
encryptedString = encryptedString.concat('+')
break;
case 'g':
encryptedString = encryptedString.concat('q')
break;
case 'h':
encryptedString = encryptedString.concat('0')
break;
case 'i':
encryptedString = encryptedString.concat('c')
break;
case 'j':
encryptedString = encryptedString.concat(']')
break;
case 'k':
encryptedString = encryptedString.concat('(')
break;
case 'l':
encryptedString = encryptedString.concat('}')
break;
case 'm':
encryptedString = encryptedString.concat('[')
break;
case 'n':
encryptedString = encryptedString.concat('8')
break;
case 'o':
encryptedString = encryptedString.concat('5')
break;
case 'p':
encryptedString = encryptedString.concat('$')
break;
case 'q':
encryptedString = encryptedString.concat('*')
break;
case 'r':
encryptedString = encryptedString.concat('i')
break;
case 's':
encryptedString = encryptedString.concat('>')
break;
case 't':
encryptedString = encryptedString.concat('#')
break;
case 'u':
encryptedString = encryptedString.concat('<')
break;
case 'v':
encryptedString = encryptedString.concat('?')
break;
case 'w':
encryptedString = encryptedString.concat('o')
break;
case 'x':
encryptedString = encryptedString.concat('^')
break;
case 'y':
encryptedString = encryptedString.concat('-')
break;
case 'z':
encryptedString = encryptedString.concat('_')
break;
case '0':
encryptedString = encryptedString.concat('h')
break;
case '1':
encryptedString = encryptedString.concat('w')
break;
case '2':
encryptedString = encryptedString.concat('e')
break;
case '3':
encryptedString = encryptedString.concat('9')
break;
case '4':
encryptedString = encryptedString.concat('g')
break;
case '5':
encryptedString = encryptedString.concat('z')
break;
case '6':
encryptedString = encryptedString.concat('d')
break;
case '7':
encryptedString = encryptedString.concat('~')
break;
case '8':
encryptedString = encryptedString.concat('=')
break;
case '9':
encryptedString = encryptedString.concat('x')
break;
case '!':
encryptedString = encryptedString.concat('j')
break;
case '@':
encryptedString = encryptedString.concat(':')
break;
case '#':
encryptedString = encryptedString.concat('4')
break;
case '$':
encryptedString = encryptedString.concat('b')
break;
case '%':
encryptedString = encryptedString.concat('`')
break;
case '^':
encryptedString = encryptedString.concat('l')
break;
case '&':
encryptedString = encryptedString.concat('3')
break;
case '*':
encryptedString = encryptedString.concat('t')
break;
case '(':
encryptedString = encryptedString.concat('6')
break;
case ')':
encryptedString = encryptedString.concat('s')
break;
case '_':
encryptedString = encryptedString.concat('n')
break;
case '+':
encryptedString = encryptedString.concat(';')
break;

case '-':
encryptedString = encryptedString.concat('\'')
break;
case '=':
encryptedString = encryptedString.concat('r')
break;
case '`':
encryptedString = encryptedString.concat('k')
break;
case '~':
encryptedString = encryptedString.concat('p')
break;
case '{':
encryptedString = encryptedString.concat('\"')
break;
case '}':
encryptedString = encryptedString.concat('&')
break;
case '[':
encryptedString = encryptedString.concat('/')
break;
case ']':
encryptedString = encryptedString.concat('\\')
break;
case '|':
encryptedString = encryptedString.concat('2')
break;
case ':':
encryptedString = encryptedString.concat('.')
break;
case ';':
encryptedString = encryptedString.concat('%')
break;
case '\"':
encryptedString = encryptedString.concat('|')
break;
case '\'':
encryptedString = encryptedString.concat(',')
break;
case '<':
encryptedString = encryptedString.concat('@')
break;
case '>':
encryptedString = encryptedString.concat('{')
break;
case ',':
encryptedString = encryptedString.concat('u')
break;
case '.':
encryptedString = encryptedString.concat('7')
break;
case '?':
encryptedString = encryptedString.concat('y')
break;
case '/':
encryptedString = encryptedString.concat('a')
break;

default:
hasInvalidCharacter = true;
}
}

if (hasInvalidCharacter) {
encryptedString = "Invalid String!";
} else {
console.log(`Your encoded string is ${encryptedString}`);
}

简单的单表代换,写个python脚本就能得到flag:

1
2
3
4
str='+}!q")hiim)#}-nvm)i-$#mvn#0mnbm)im#n+}!qnm8)i-$#mvnoc#0nz<$9inm!>-n1:1-nm8)i-$~c58n!}qhij#0[noic##m8nc8n?!8c}w!n]>&'
book1='abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+=`~{}[]|:;\<>,.?/'
book2='!1)vm+q0c](}[85$*i>#<?o^-_hwe9gzd~=xj:4b`13t6sn;rkp"&/\2.%|,@{u7ya'
print(''.join(book1[book2.index(i)]for i in str))

Magic of Encoding

题目给了一大堆base64编码,先用cyberchef解码一下试试:

1
2
3
4
5
6
7
8
flag{Xd_fake_flag_xD}find_me_if_you_canfind_me_if_you_canflag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}find_me_if_you_canfind_me_if_you_canflag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}find_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canflag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}find_me_if_you_canfind_me_if_you_canflag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{not_the_correct_flag_lol}
flag{not_the_correct_flag_lol}
flag{not_the_correct_flag_lol}
flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{Xd_fake_flag_xD}find_me_if_you_canfind_me_if_you_canflag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}find_me_if_you_canfind_me_if_you_canflag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}find_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canflag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}find_me_if_you_canfind_me_if_you_canflag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}find_me_if_you_canfind_me_if_you_canflag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}find_me_if_you_canfind_me_if_you_canflag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}find_me_if_you_canfind_me_if_you_canflag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}find_me_if_you_canfind_me_if_you_canflag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}find_me_if_you_canflag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}find_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canflag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}find_me_if_you_canflag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}find_me_if_you_canflag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}flag{Xd_fake_flag_xD}find_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canflag{not_the_correct_flag_lol}
flag{not_the_correct_flag_lol}
flag{not_the_correct_flag_lol}
flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}flag{not_the_correct_flag_lol}find_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canfind_me_if_you_canflag{Xd_fake_flag_xD}find_me_if_you_canPK.........T.V.........¥¹.}µ.}¥.}å½Õ}..¹.±..ía.}....}.±..}á.õ.±..ía.}....}.±..}á.õ.±..í¹½Ñ}Ñ¡.}.½ÉÉ..Ñ}.±..}±½±ô).±..í¹½Ñ}Ñ¡.}.½ÉÉ..Ñ}.±..}±½±ô).±..í¹½Ñ}Ñ¡.}.½ÉÉ..Ñ}.±..}±½±ô).±..í¹½Ñ}Ñ¡.}.½ÉÉ..Ñ}.±..}±½±õ.±..í¹½Ñ}Ñ¡.}.½ÉÉ..Ñ}.±..}±½±õ.±..í¹½Ñ}Ñ¡.}.½ÉÉ..Ñ}.±..}±½±õ.±..í¹½Ñ}Ñ¡.}.½ÉÉ..Ñ}.±..}±½±õ.±..í¹½Ñ}Ñ¡.}.½ÉÉ..Ñ}.±..}±½±õ.±..í¹½Ñ}Ñ¡.}.½ÉÉ..Ñ}.±..}±½±õ.±..í¹½Ñ}Ñ¡.}.½ÉÉ..Ñ}.±..}±½±õ.±..í¹½Ñ}Ñ¡.}.½ÉÉ..Ñ}.±..}±½±õ.±..í¹½Ñ}Ñ¡.}.½ÉÉ..Ñ}.±..}±½±õ.±..í¹½Ñ}Ñ¡.}.½ÉÉ..Ñ}.±..}±½±õ.±..í¹½Ñ}Ñ¡.}.½ÉÉ..Ñ}.±..}±½±õ.±..í¹½Ñ}Ñ¡.}.½ÉÉ..Ñ}.±..}±½±õ.±..í¹½Ñ}Ñ¡.}.½ÉÉ..Ñ}.±..}±½±õ.±..í¹½Ñ}Ñ¡.}.½ÉÉ..
.....

可以看到一大群flag,后面还跟着生成了非常多的乱码,而且一眼望过去几乎全是重复句段,只是有的是假flag有的是乱码,在确定了并没有藏flag在这里面之后,我发现了:

1
find_me_if_you_canfind_me_if_you_canflag{Xd_fake_flag_xD}find_me_if_you_canPK.........T.V.........¥¹.}µ.}¥.}å½Õ}..¹.±..ía.}....}.±..}á.õ.±..ía.}....}.±..}á.õ.±..í¹½Ñ}Ñ¡.}.½ÉÉ..Ñ}.±..}±½±ô).±..í¹½Ñ}Ñ¡.}.½ÉÉ..Ñ}.±..}±½±ô).±..í¹½Ñ}Ñ¡.}.½ÉÉ..Ñ}.±..

在第一块这里正常句段转到乱码的地方出现了一个PK,这就代表可能藏了压缩包(这不是misc题吗……),通过比较乱码字段和假flag段的base64源码发现其实是一样的,所以题目中所有解码出的文本几乎都为假flag段。我猜测这里这些乱码的出现是因为PK压缩包base64加密的问题导致原来的假flag码加密错位导致出现了乱码,不过它们的base64码是一样的,可以用假flag直接去掉这些码,保留pk压缩包:

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

with open('Magic_Of_Encoding.txt') as f:
f=f.read()
list = ["flag{Xd_fake_flag_xD}","find_me_if_you_can","flag{not_the_correct_flag_lol}","\nflag{not_the_correct_flag_lol}\nflag{not_the_correct_flag_lol}\n"]
base64_flag_list = [b64encode(i.encode()).decode() for i in list]
for i in base64_flag_list:
f = f.replace(i,"")
with open('2.txt','wb') as t:
t.write(b64decode(f))

将得到的二进制文本写入压缩包,解压得到flag。

Math Problem

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/usr/bin/env sage
import secret
from Crypto.Util.number import *

p, q = getPrime(512), getPrime(512)
e, n = 0x10001, p * q
c = pow(bytes_to_long(secret.flag), e, n)

a, b = getPrime(512), getPrime(512)
E = EllipticCurve(GF(p), [a, b])
G = E.lift_x(ZZ(getPrime(64)))
print(f"{a = }\n{b = }\ny = {G.xy()[1]}")

'''
e = 65537
n = 79239019133008902130006198964639844798771408211660544649405418249108104979283858140199725213927656792578582828912684320882248828512464244641351915288069266378046829511827542801945752252863425605946379775869602719406340271702260307900825314967696531175183205977973427572862807386846990514994510850414958255877
c = 45457869965165575324534408050513326739799864850578881475341543330291990558135968254698676312246850389922318827771380881195754151389802803398367341521544667542828862543407738361578535730524976113729406101764290984943061582342991118766322793847422471903811686775249409300301726906738475446634950949059180072008
a = 9303981927028382051386918702900550228062240363697933771286553052631411452412621158116514735706670764224584958899184294505751247393129887316131576567242619
b = 9007779281398842447745292673398186664639261529076471011805234554666556577498532370235883716552696783469143334088312327338274844469338982242193952226631913
y = 970090448249525757357772770885678889252473675418473052487452323704761315577270362842929142427322075233537587085124672615901229826477368779145818623466854
'''

G = E.lift_x(ZZ(getPrime(64)))这段代码是为椭圆曲线创建一个点。具体来说,它接受一个x坐标作为输入,返回一个对应的点。这个点的纵坐标y是根据椭圆曲线上的方程计算得出的。

一道数学题,用了ECC算法。

题目把a和b都给了,已知方程参数和生成点y,x位数比较小,尝试使用coppersmith求x:

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

e = 65537
n = 79239019133008902130006198964639844798771408211660544649405418249108104979283858140199725213927656792578582828912684320882248828512464244641351915288069266378046829511827542801945752252863425605946379775869602719406340271702260307900825314967696531175183205977973427572862807386846990514994510850414958255877
c = 45457869965165575324534408050513326739799864850578881475341543330291990558135968254698676312246850389922318827771380881195754151389802803398367341521544667542828862543407738361578535730524976113729406101764290984943061582342991118766322793847422471903811686775249409300301726906738475446634950949059180072008

a = 9303981927028382051386918702900550228062240363697933771286553052631411452412621158116514735706670764224584958899184294505751247393129887316131576567242619
b = 9007779281398842447745292673398186664639261529076471011805234554666556577498532370235883716552696783469143334088312327338274844469338982242193952226631913
y = 970090448249525757357772770885678889252473675418473052487452323704761315577270362842929142427322075233537587085124672615901229826477368779145818623466854

p.<x>=PolynomialRing(Zmod(n))
f=x^3+a*x+b-y^2
f=f.monic()
x0=f.small_roots(X=2^64,beta=0.4,epsilon=0.01)[0]

这里再详细的回顾一下f.small_roots()这个函数,这行代码的含义是在多项式f中找到一个小于$2^{64}$的根。参数beta表示多项式模的次数系数上限,epsilon表示找到可接受的根的概率,这两个参数都控制了算法的时间复杂度和准确率。由于多项式模问题是一个NP难问题,因此在实际运行中,可能需要多次运行算法才能找到一个合适的解。

NP难问题指的是一类NP问题,这些问题非常困难,目前没有已知的多项式算法能够在多项式时间内解决它们。因此不能保证在多项式时间内求解这些问题,但是可以在多项式时间内验证一个给定的解是否正确。——取自ChatGPT

这里如果不加epsilon参数会求不出来,测试设为0.01能求出小值根。

得到根之后代入回原方程组得到f值,由于是在模n多项式环下为0,f值小于n,和n有公共因子p,得到因式分解:

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

e = 65537
n = 79239019133008902130006198964639844798771408211660544649405418249108104979283858140199725213927656792578582828912684320882248828512464244641351915288069266378046829511827542801945752252863425605946379775869602719406340271702260307900825314967696531175183205977973427572862807386846990514994510850414958255877
c = 45457869965165575324534408050513326739799864850578881475341543330291990558135968254698676312246850389922318827771380881195754151389802803398367341521544667542828862543407738361578535730524976113729406101764290984943061582342991118766322793847422471903811686775249409300301726906738475446634950949059180072008

x = 9757458594430450711
f = x**3+a*x+b-y**2
p = gmpy2.gcd(f, n)
q = n//p
phi = (p-1)*(q-1)
d = gmpy2.invert(e, phi)
m = pow(c, d, n)
print(long_to_bytes(m))

babylua

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
local flag = '' --这里是你要逆推出的flag
local md5 = require("md5")

math.randomseed(os.time())

local function randomStr(len)
local rankStr = ""
local randNum = 0
for i = 1, len do
randNum = math.random(1, 2)
if randNum == 1 then
rankStr = rankStr .. string.char(math.random(65, 90))
elseif randNum == 2 then
rankStr = rankStr .. string.char(math.random(97, 122))
end
end
return rankStr
end

local seed = randomStr(4)
local key = md5.sumhexa(md5.sumhexa(seed))
print(key:sub(1,10))

secret = {}

for i = 1, #flag do
secret[i] = string.byte(flag:sub(i,i)) + string.byte(key:sub(i,i))
end

for i, v in ipairs(secret) do
io.write(v, ' ')
end

print()

--程序运行输出结果:
--b5e62abe84
--200 161 198 157 173 169 199 150 105 163 193 175 173 194 135 131 135 225
--请你分析代码,逆向推出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
local flag = '' --这里是你要逆推出的flag
local md5 = require("md5")

-- 根据当前系统时间设置随机数生成器的种子
math.randomseed(os.time())

-- 生成指定长度的随机字符串
local function randomStr(len)
local result = ""
local randNum = 0
for i = 1, len do
-- 随机生成一个数字,1表示大写字母,2表示小写字母
randNum = math.random(1, 2)
-- 根据randNum生成对应类型的随机字符
if randNum == 1 then
result = result .. string.char(math.random(65, 90)) -- 生成一个大写字母
elseif randNum == 2 then
result = result .. string.char(math.random(97, 122)) -- 生成一个小写字母
end
end
return result
end

-- 生成4位的随机字符串种子seed
local seed = randomStr(4)

-- 将seed进行两次MD5加密后得到密钥key(key为32位的16进制字符串)
local key = md5.sumhexa(md5.sumhexa(seed))

-- 输出key的前10位
print(key:sub(1,10))

-- 加密flag
local secret = {}
for i = 1, #flag do
secret[i] = string.byte(flag:sub(i,i)) + string.byte(key:sub(i,i))
end

-- 输出加密后的每一个字符
for i, v in ipairs(secret) do
io.write(v, ' ')
end

print()

--程序运行输出结果:
--b5e62abe84
--200 161 198 157 173 169 199 150 105 163 193 175 173 194 135 131 135 225
--请你分析代码,逆向推出flag

题目给了两次md5加密后的前10位,四位的seed可以尝试爆破,用itertools库生成所有随机组合的大写小写字母:

1
2
3
4
5
6
7
8
9
10
11
12
import string
import itertools
from hashlib import md5

chars = string.ascii_lowercase+string.ascii_uppercase
cs = itertools.product(chars, repeat=4)
for c in cs:
s=''.join(c)
h = md5((md5(s.encode()).hexdigest()).encode()).hexdigest()
if h[:10]=='b5e62abe84':
print(s,h)
break

爆破出之后直接按照他给的算法逆回去就得到flag了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import string
import itertools
from hashlib import md5

chars = string.ascii_lowercase+string.ascii_uppercase
cs = itertools.product(chars, repeat=4)
for c in cs:
s=''.join(c)
h = md5((md5(s.encode()).hexdigest()).encode()).hexdigest()
if h[:10]=='b5e62abe84':
print(s,h)
break

a = [200, 161, 198, 157, 173, 169, 199, 150, 105, 163, 193, 175, 173, 194, 135, 131, 135, 225]
for i in range(len(a)):
num,b=a[i],ord(h[i])
print(chr(num-b),end='')

WEEK 1

[EIS 2019]rsa1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from flag import FLAG
from Crypto.Util.number import *
import gmpy2
import random

while True:
p = int(gmpy2.next_prime(random.randint(10**399, 10**400-1)))
q = int(str(p)[200:]+str(p)[:200])
if gmpy2.is_prime(q):
break

m = bytes_to_long(FLAG)
n = p*q
e = 65537
c = pow(m,e,n)

with open("enc","wb") as f:
f.write(str(c))
f.write("\n")
f.write(str(n))
'''
c=16396023285324039009558195962852040868243807971027796599580351414803675753933120024077886501736987010658812435904022750269541456641256887079780585729054681025921699044139927086676479128232499416835051090240458236280851063589059069181638802191717911599940897797235038838827322737207584188123709413077535201099325099110746196702421778588988049442604655243604852727791349351291721230577933794627015369213339150586418524473465234375420448340981330049205933291705601563283196409846408465061438001010141891397738066420524119638524908958331406698679544896351376594583883601612086738834989175070317781690217164773657939589691476539613343289431727103692899002758373929815089904574190511978680084831183328681104467553713888762965976896013404518316128288520016934828176674482545660323358594211794461624622116836
n=21173064304574950843737446409192091844410858354407853391518219828585809575546480463980354529412530785625473800210661276075473243912578032636845746866907991400822100939309254988798139819074875464612813385347487571449985243023886473371811269444618192595245380064162413031254981146354667983890607067651694310528489568882179752700069248266341927980053359911075295668342299406306747805925686573419756406095039162847475158920069325898899318222396609393685237607183668014820188522330005608037386873926432131081161531088656666402464062741934007562757339219055643198715643442608910351994872740343566582808831066736088527333762011263273533065540484105964087424030617602336598479611569611018708530024591023015267812545697478378348866840434551477126856261767535209092047810194387033643274333303926423370062572301
'''

看完代码可以发现,p为一个400位随机数,q是p的前200位和后200位互换位置得到的数,和之前做的有道hamburgerRSA比较像,已知:

把pq都分成两个部分a和b,每个都是200位,那么ab乘积也就是个400位的数。

现在,n的前200位是ab的前200位(先不考虑中间区段的进位),末200位为ab后200位(这个不会被进位卡混淆),可以得到ab的乘积,得到乘积之后,减回去稍微计算一下就能得到$a^2+b^2$:

我们先走到这里检查一下:

1
2
3
4
5
6
c=16396023285324039009558195962852040868243807971027796599580351414803675753933120024077886501736987010658812435904022750269541456641256887079780585729054681025921699044139927086676479128232499416835051090240458236280851063589059069181638802191717911599940897797235038838827322737207584188123709413077535201099325099110746196702421778588988049442604655243604852727791349351291721230577933794627015369213339150586418524473465234375420448340981330049205933291705601563283196409846408465061438001010141891397738066420524119638524908958331406698679544896351376594583883601612086738834989175070317781690217164773657939589691476539613343289431727103692899002758373929815089904574190511978680084831183328681104467553713888762965976896013404518316128288520016934828176674482545660323358594211794461624622116836
n=21173064304574950843737446409192091844410858354407853391518219828585809575546480463980354529412530785625473800210661276075473243912578032636845746866907991400822100939309254988798139819074875464612813385347487571449985243023886473371811269444618192595245380064162413031254981146354667983890607067651694310528489568882179752700069248266341927980053359911075295668342299406306747805925686573419756406095039162847475158920069325898899318222396609393685237607183668014820188522330005608037386873926432131081161531088656666402464062741934007562757339219055643198715643442608910351994872740343566582808831066736088527333762011263273533065540484105964087424030617602336598479611569611018708530024591023015267812545697478378348866840434551477126856261767535209092047810194387033643274333303926423370062572301
e = 65537
N=str(n)
ab=int(N[:200]+N[600:])
a2b2=(n-ab*pow(10,400)-ab)//pow(10,200)

输出发现$a^2+b^2$是负数,这肯定是不对的,问题出在哪里呢,可以看看之前的公式:

我们还有中间四百位没有考虑,$a^2+b^2$的位数是未知的。类比一下,对于一个两位数,$a^2+b^2$最小就是$10^2+10^2=200$,三位;最大有$99^2+99^2=19602$,五位。相应的,$a^2+b^2$的位数应该在399,400,401三个值上,如果出现401位,首位只能为1。

所以出现负数的结果,一定是$a^2+b^2$位数为401导致ab数值错误,稍微修改一下:

1
2
3
4
5
6
c=16396023285324039009558195962852040868243807971027796599580351414803675753933120024077886501736987010658812435904022750269541456641256887079780585729054681025921699044139927086676479128232499416835051090240458236280851063589059069181638802191717911599940897797235038838827322737207584188123709413077535201099325099110746196702421778588988049442604655243604852727791349351291721230577933794627015369213339150586418524473465234375420448340981330049205933291705601563283196409846408465061438001010141891397738066420524119638524908958331406698679544896351376594583883601612086738834989175070317781690217164773657939589691476539613343289431727103692899002758373929815089904574190511978680084831183328681104467553713888762965976896013404518316128288520016934828176674482545660323358594211794461624622116836
n=21173064304574950843737446409192091844410858354407853391518219828585809575546480463980354529412530785625473800210661276075473243912578032636845746866907991400822100939309254988798139819074875464612813385347487571449985243023886473371811269444618192595245380064162413031254981146354667983890607067651694310528489568882179752700069248266341927980053359911075295668342299406306747805925686573419756406095039162847475158920069325898899318222396609393685237607183668014820188522330005608037386873926432131081161531088656666402464062741934007562757339219055643198715643442608910351994872740343566582808831066736088527333762011263273533065540484105964087424030617602336598479611569611018708530024591023015267812545697478378348866840434551477126856261767535209092047810194387033643274333303926423370062572301
e = 65537
N=str(n)
ab=int(str(int(N[:200])-1)+N[600:])
a2b2=(n-ab*pow(10,400)-ab)//pow(10,200)

现在就对了,已经知道了$ab,a^2+b^2$,用一些中学数学知识就能得到$a+b,a-b$,进而得到$a,b$,最终得到$p,q$,得解:

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

c=16396023285324039009558195962852040868243807971027796599580351414803675753933120024077886501736987010658812435904022750269541456641256887079780585729054681025921699044139927086676479128232499416835051090240458236280851063589059069181638802191717911599940897797235038838827322737207584188123709413077535201099325099110746196702421778588988049442604655243604852727791349351291721230577933794627015369213339150586418524473465234375420448340981330049205933291705601563283196409846408465061438001010141891397738066420524119638524908958331406698679544896351376594583883601612086738834989175070317781690217164773657939589691476539613343289431727103692899002758373929815089904574190511978680084831183328681104467553713888762965976896013404518316128288520016934828176674482545660323358594211794461624622116836
n=21173064304574950843737446409192091844410858354407853391518219828585809575546480463980354529412530785625473800210661276075473243912578032636845746866907991400822100939309254988798139819074875464612813385347487571449985243023886473371811269444618192595245380064162413031254981146354667983890607067651694310528489568882179752700069248266341927980053359911075295668342299406306747805925686573419756406095039162847475158920069325898899318222396609393685237607183668014820188522330005608037386873926432131081161531088656666402464062741934007562757339219055643198715643442608910351994872740343566582808831066736088527333762011263273533065540484105964087424030617602336598479611569611018708530024591023015267812545697478378348866840434551477126856261767535209092047810194387033643274333303926423370062572301
e = 65537
N=str(n)
ab=int(str(int(N[:200])-1)+N[600:])
a2b2=(n-ab*pow(10,400)-ab)//pow(10,200)
ajiab=gmpy2.iroot(a2b2+2*ab,2)[0]
ajianb=gmpy2.iroot(a2b2-2*ab,2)[0]
a=(ajiab+ajianb)//2
b=(ajiab-ajianb)//2
p=pow(10,200)*a+b
q=pow(10,200)*b+a
phi=(p-1)*(q-1)
d=gmpy2.invert(e,phi)
m=pow(c,d,n)
print(long_to_bytes(m))