0%

ciscnctf2022/

ciscnctf2022

好久没有写博客了,由于期末原因,国赛的逆向还没复现,今天复现一下,总的来说,国赛的三道题,其中两道都是语文题,蚌埠住了。

baby_tree

记得找了很多工具发现并不能转换,所以只能硬看swift的ast代码

image-20220617094847961

首先我们能发现对比字符串和key的位置

image-20220617100004163

image-20220617095951534

继续往下看在625行大概是调用了check函数,其中传入了两个参数,分别是data和key

image-20220617103522582

Original init:这个应该是初始化一下,Processed init:这个是运行函数。接下来我们直接查check函数,发现是在最初。

image-20220617104011665

这个地方可以研究一下,其实是传入两个参数,string类型的,这个函数应该是bool类型,这么长的一段并无什么运算符,但可能是将两个string类型转换成数组,一个是b数组,一个是k数组,其中b数组应该是encode的位置,k数组应该就是key。接下来在70行又声明了4个变量r0,r1,r2,r3。继续看在第99行进入循环。

image-20220617104939675

这个循环长度不难猜出是0-cout(b)-4,但如果没看到的话,估计后面几位会错。接下来是个赋值条件,形成第一个元组(r0,r1,r2,r3)

image-20220617105646948

assign_expr和load_expr都是赋值的意思下面通过value的值变换可以猜测,r0,r1,r2,r3 = b[0],b[1],b[2],b[3]

image-20220617110005652

我们分析一个加密:

image-20220617114011203

可以看出,缩进代表运算顺序,缩进越多优先级越高,argument后是参数,extension.后是运算符,那么上述图片可以表示为:

1
b[i+0] = r2 ^ ((k[0] + (r0 >> 4)) & 0xff)

那么接下来的跟上述是一样的可分析出大概逻辑:

1
2
3
4
5
6
7
for i in range(0,len(b)-3):
r0,r1,r2,r3=b[i],b[i+1],b[i+2],b[i+3]
b[i+0] = r2 ^ ((k[0] + (r0 >> 4)) & 0xff)
b[i+1] = r3 ^ ((k[1] + (r1 >> 2)) & 0xff)
b[i+2] = r0 ^ k[2]
b[i+3] = r1 ^ k[3]
k[0], k[1], k[2], k[3] = k[1], k[2], k[3], k[0]

我们直接写出解密脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
flag = ""
key = b"345y"
k=list(key)
cmp = [88, 35, 88, 225, 7, 201, 57, 94, 77, 56, 75, 168, 72, 218, 64, 91, 16, 101, 32, 207, 73, 130, 74, 128, 76, 201, 16, 248, 41, 205, 103, 84, 91, 99, 79, 202, 22, 131, 63, 255, 20, 16]
b = [0]*len(cmp)
k[0], k[1], k[2], k[3] = k[2], k[3], k[0], k[1]
for i in range(38, -1, -1):
r1 = cmp[i+3] ^ k[3]
r0 = cmp[i+2] ^ k[2]
r3 = cmp[i+1] ^ (0xff & (k[1] + (r1 >> 2)))
r2 = cmp[i] ^ (0xff & (k[0] + (r0 >> 4)))
k[0], k[1], k[2], k[3] = k[3], k[0], k[1], k[2]
cmp[i], cmp[i+1], cmp[i+2], cmp[i+3] = r0, r1, r2, r3
print(cmp)
for i in range(len(cmp)):
flag += chr(cmp[i])
print(flag)
#flag{30831242-56db-45b4-96fd-1f47e60da99d}

本以为这个题就是阅读题的极限了,没想到下一题也是阅读题。

babycode

这个题给了一个.mrb文件后缀是将 ruby 代码编译为 mruby 字节码作为字符串并评估字符串化字节码,通过010前面字符RITE0300,可以判断出mruby的版本是3.1.0,我们下载https://github.com/mruby/mruby/releases/tag/3.1.0源码,首先要安装sudo apt-get install rake,接下来make,然后进入bin里就可以使用mruby了./mruby -v -b babycode.mrb.

image-20220617144108971

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
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
mruby 3.1.0 (2022-05-12)
irep 0x56306d9014d0 nregs=5 nlocals=2 pools=1 syms=5 reps=2 ilen=55
local variable names:
R1:p
000 LOADNIL R2
002 LOADNIL R3
004 CLASS R2 :Crypt
007 EXEC R2 I(0:0x56306d901580)
010 TCLASS R2
012 METHOD R3 I(1:0x56306d901d80)
015 DEF R2 :check
018 SSEND R2 :gets n=0 (0x00)
022 SEND R2 :chomp n=0 (0x00)
026 MOVE R1 R2 ; R1:p
029 MOVE R3 R1 ; R1:p
032 SSEND R2 :check n=1 (0x01)
036 JMPNOT R2 050
040 STRING R3 L(0) ; yes
043 SSEND R2 :puts n=1 (0x01)
047 JMP 052
050 LOADNIL R2
052 RETURN R2
054 STOP

irep 0x56306d901580 nregs=3 nlocals=1 pools=0 syms=1 reps=1 ilen=12
000 LOADNIL R1
002 LOADNIL R2
004 CLASS R1 :CIPHER
007 EXEC R1 I(0:0x56306d901650)
010 RETURN R1

irep 0x56306d901650 nregs=3 nlocals=1 pools=0 syms=6 reps=4 ilen=55
000 LOADI32 R1 305419896
006 SETCONST XX R1
009 LOADI R1 16
012 SETCONST YY R1
015 LOADSELF R1
017 SCLASS R1
019 METHOD R2 I(0:0x56306d901790)
022 DEF R1 :encrypt
025 TCLASS R1
027 METHOD R2 I(1:0x56306d901830)
030 DEF R1 :encrypt
033 SSEND R1 :private n=0 (0x00)
037 TCLASS R1
039 METHOD R2 I(2:0x56306d901b50)
042 DEF R1 :to_key
045 TCLASS R1
047 METHOD R2 I(3:0x56306d901c20)
050 DEF R1 :enc_one
053 RETURN R1

irep 0x56306d901790 nregs=9 nlocals=5 pools=0 syms=3 reps=0 ilen=29
local variable names:
R1:t
R2:p
R3:&
R4:cip
000 ENTER 2:0:0:0:0:0:0 (0x80000)
004 GETCONST R5 CIPHER
007 SEND R5 :new n=0 (0x00)
011 MOVE R4 R5 ; R4:cip
014 MOVE R5 R4 ; R4:cip
017 MOVE R6 R1 ; R1:t
020 MOVE R7 R2 ; R2:p
023 SEND R5 :encrypt n=2 (0x02)
027 RETURN R5

irep 0x56306d901830 nregs=16 nlocals=11 pools=1 syms=8 reps=1 ilen=346
local variable names:
R1:t
R2:p
R3:&
R4:key
R5:c
R6:n
R7:num1
R8:num2
R9:enum1
R10:enum2
000 ENTER 2:0:0:0:0:0:0 (0x80000)
004 MOVE R12 R2 ; R2:p
007 SSEND R11 :to_key n=1 (0x01)
011 MOVE R4 R11 ; R4:key
014 ARRAY R5 R5 0 ; R5:c
017 LOADI_0 R6 ; R6:n
019 MOVE R11 R6 ; R6:n
022 MOVE R12 R1 ; R1:t
025 SEND R12 :length n=0 (0x00)
029 LT R11 R12
031 JMPNOT R11 327
035 MOVE R11 R1 ; R1:t
038 MOVE R12 R6 ; R6:n
041 GETIDX R11 R12
043 SEND R11 :ord n=0 (0x00)
047 SEND R11 :to_i n=0 (0x00)
051 LOADI R12 24
054 SEND R11 :<< n=1 (0x01)
058 MOVE R7 R11 ; R7:num1
061 MOVE R11 R7 ; R7:num1
064 MOVE R12 R1 ; R1:t
067 MOVE R13 R6 ; R6:n
070 ADDI R13 1
073 GETIDX R12 R13
075 SEND R12 :ord n=0 (0x00)
079 SEND R12 :to_i n=0 (0x00)
083 LOADI R13 16
086 SEND R12 :<< n=1 (0x01)
090 ADD R11 R12
092 MOVE R7 R11 ; R7:num1
095 MOVE R11 R7 ; R7:num1
098 MOVE R12 R1 ; R1:t
101 MOVE R13 R6 ; R6:n
104 ADDI R13 2
107 GETIDX R12 R13
109 SEND R12 :ord n=0 (0x00)
113 SEND R12 :to_i n=0 (0x00)
117 LOADI R13 8
120 SEND R12 :<< n=1 (0x01)
124 ADD R11 R12
126 MOVE R7 R11 ; R7:num1
129 MOVE R11 R7 ; R7:num1
132 MOVE R12 R1 ; R1:t
135 MOVE R13 R6 ; R6:n
138 ADDI R13 3
141 GETIDX R12 R13
143 SEND R12 :ord n=0 (0x00)
147 SEND R12 :to_i n=0 (0x00)
151 ADD R11 R12
153 MOVE R7 R11 ; R7:num1
156 MOVE R11 R1 ; R1:t
159 MOVE R12 R6 ; R6:n
162 ADDI R12 4
165 GETIDX R11 R12
167 SEND R11 :ord n=0 (0x00)
171 SEND R11 :to_i n=0 (0x00)
175 LOADI R12 24
178 SEND R11 :<< n=1 (0x01)
182 MOVE R8 R11 ; R8:num2
185 MOVE R11 R8 ; R8:num2
188 MOVE R12 R1 ; R1:t
191 MOVE R13 R6 ; R6:n
194 ADDI R13 5
197 GETIDX R12 R13
199 SEND R12 :ord n=0 (0x00)
203 SEND R12 :to_i n=0 (0x00)
207 LOADI R13 16
210 SEND R12 :<< n=1 (0x01)
214 ADD R11 R12
216 MOVE R8 R11 ; R8:num2
219 MOVE R11 R8 ; R8:num2
222 MOVE R12 R1 ; R1:t
225 MOVE R13 R6 ; R6:n
228 ADDI R13 6
231 GETIDX R12 R13
233 SEND R12 :ord n=0 (0x00)
237 SEND R12 :to_i n=0 (0x00)
241 LOADI R13 8
244 SEND R12 :<< n=1 (0x01)
248 ADD R11 R12
250 MOVE R8 R11 ; R8:num2
253 MOVE R11 R8 ; R8:num2
256 MOVE R12 R1 ; R1:t
259 MOVE R13 R6 ; R6:n
262 ADDI R13 7
265 GETIDX R12 R13
267 SEND R12 :ord n=0 (0x00)
271 SEND R12 :to_i n=0 (0x00)
275 ADD R11 R12
277 MOVE R8 R11 ; R8:num2
280 MOVE R12 R7 ; R7:num1
283 MOVE R13 R8 ; R8:num2
286 MOVE R14 R4 ; R4:key
289 SSEND R11 :enc_one n=3 (0x03)
293 AREF R9 R11 0 ; R9:enum1
297 AREF R10 R11 1 ; R10:enum2
301 MOVE R11 R5 ; R5:c
304 MOVE R12 R9 ; R9:enum1
307 SEND R11 :<< n=1 (0x01)
311 MOVE R11 R5 ; R5:c
314 MOVE R12 R10 ; R10:enum2
317 SEND R11 :<< n=1 (0x01)
321 ADDI R6 8 ; R6:n
324 JMP 019
327 MOVE R11 R5 ; R5:c
330 BLOCK R12 I(0:0x56306d901a80)
333 SENDB R11 :collect n=0 (0x00)
337 STRING R12 L(0) ;
340 SEND R11 :join n=1 (0x01)
344 RETURN R11

irep 0x56306d901a80 nregs=7 nlocals=3 pools=1 syms=1 reps=0 ilen=16
local variable names:
R1:x
R2:&
000 ENTER 1:0:0:0:0:0:0 (0x40000)
004 STRING R4 L(0) ; %.8x
007 MOVE R5 R1 ; R1:x
010 SSEND R3 :sprintf n=2 (0x02)
014 RETURN R3

irep 0x56306d901b50 nregs=6 nlocals=3 pools=1 syms=1 reps=0 ilen=16
local variable names:
R1:p
R2:&
000 ENTER 1:0:0:0:0:0:0 (0x40000)
004 MOVE R3 R1 ; R1:p
007 STRING R4 L(0) ; L*
010 SEND R3 :unpack n=1 (0x01)
014 RETURN R3

irep 0x56306d901c20 nregs=11 nlocals=8 pools=0 syms=2 reps=1 ilen=42
local variable names:
R1:num1
R2:num2
R3:key
R4:&
R5:y
R6:z
R7:s
000 ENTER 3:0:0:0:0:0:0 (0xc0000)
004 MOVE R8 R1 ; R1:num1
007 MOVE R9 R2 ; R2:num2
010 LOADI_0 R10
012 MOVE R5 R8 ; R5:y
015 MOVE R6 R9 ; R6:z
018 MOVE R7 R10 ; R7:s
021 GETCONST R8 YY
024 BLOCK R9 I(0:0x56306d901cf0)
027 SENDB R8 :times n=0 (0x00)
031 MOVE R8 R5 ; R5:y
034 MOVE R9 R6 ; R6:z
037 ARRAY R8 R8 2
040 RETURN R8

irep 0x56306d901cf0 nregs=10 nlocals=3 pools=1 syms=5 reps=0 ilen=186
local variable names:
R1:i
R2:&
000 ENTER 1:0:0:0:0:0:0 (0x40000)
004 GETUPVAR R3 5 0
008 GETUPVAR R4 6 0
012 LOADI_3 R5
014 SEND R4 :<< n=1 (0x01)
018 GETUPVAR R5 6 0
022 LOADI_5 R6
024 SEND R5 :>> n=1 (0x01)
028 SEND R4 :^ n=1 (0x01)
032 GETUPVAR R5 6 0
036 ADD R4 R5
038 GETUPVAR R5 7 0
042 GETUPVAR R6 3 0
046 GETUPVAR R7 7 0
050 LOADI R8 11
053 SEND R7 :>> n=1 (0x01)
057 ADDI R7 1
060 LOADI_3 R8
062 SEND R7 :& n=1 (0x01)
066 GETIDX R6 R7
068 ADD R5 R6
070 SEND R4 :^ n=1 (0x01)
074 ADD R3 R4
076 SETUPVAR R3 5 0
080 LOADL R4 L(0) ; 4294967295
083 SEND R3 :& n=1 (0x01)
087 SETUPVAR R3 5 0
091 GETUPVAR R3 7 0
095 GETCONST R4 XX
098 ADD R3 R4
100 SETUPVAR R3 7 0
104 GETUPVAR R3 6 0
108 GETUPVAR R4 5 0
112 LOADI_3 R5
114 SEND R4 :<< n=1 (0x01)
118 GETUPVAR R5 5 0
122 LOADI_5 R6
124 SEND R5 :>> n=1 (0x01)
128 SEND R4 :^ n=1 (0x01)
132 GETUPVAR R5 5 0
136 ADD R4 R5
138 GETUPVAR R5 7 0
142 GETUPVAR R6 3 0
146 GETUPVAR R7 7 0
150 ADDI R7 1
153 LOADI_3 R8
155 SEND R7 :& n=1 (0x01)
159 GETIDX R6 R7
161 ADD R5 R6
163 SEND R4 :^ n=1 (0x01)
167 ADD R3 R4
169 SETUPVAR R3 6 0
173 LOADL R4 L(0) ; 4294967295
176 SEND R3 :& n=1 (0x01)
180 SETUPVAR R3 6 0
184 RETURN R3

irep 0x56306d901d80 nregs=13 nlocals=8 pools=2 syms=7 reps=0 ilen=128
local variable names:
R1:p
R2:&
R3:i
R4:lst_ch
R5:c
R6:k
R7:cipher_text
000 ENTER 1:0:0:0:0:0:0 (0x40000)
004 LOADI_0 R3 ; R3:i
006 LOADI_0 R4 ; R4:lst_ch
008 MOVE R8 R3 ; R3:i
011 MOVE R9 R1 ; R1:p
014 SEND R9 :length n=0 (0x00)
018 LT R8 R9
020 JMPNOT R8 086
024 MOVE R8 R1 ; R1:p
027 MOVE R9 R3 ; R3:i
030 GETIDX R8 R9
032 SEND R8 :ord n=0 (0x00)
036 MOVE R5 R8 ; R5:c
039 MOVE R8 R5 ; R5:c
042 MOVE R9 R4 ; R4:lst_ch
045 SEND R8 :^ n=1 (0x01)
049 MOVE R9 R3 ; R3:i
052 ADDI R9 1
055 SEND R8 :^ n=1 (0x01)
059 SEND R8 :chr n=0 (0x00)
063 MOVE R9 R1 ; R1:p
066 MOVE R10 R3 ; R3:i
069 MOVE R11 R8
072 SETIDX R9 R10 R11
074 MOVE R8 R5 ; R5:c
077 MOVE R4 R8 ; R4:lst_ch
080 ADDI R3 1 ; R3:i
083 JMP 008
086 STRING R6 L(0) ; aaaassssddddffff ; R6:k
089 GETCONST R8 Crypt
092 GETMCNST R8 R8::CIPHER
095 MOVE R9 R1 ; R1:p
098 MOVE R10 R6 ; R6:k
101 SEND R8 :encrypt n=2 (0x02)
105 MOVE R7 R8 ; R7:cipher_text
108 MOVE R8 R7 ; R7:cipher_text
111 STRING R9 L(1) ; f469358b7f165145116e127ad6105917bce5225d6d62a714c390c5ed93b22d8b6b102a8813488fdb
114 EQ R8 R9
116 JMPNOT R8 124
120 LOADT R8
122 RETURN R8
124 LOADF R8
126 RETURN R8

经典阅读文档,那天做题的时候大概就已经猜出来是xtea加密,但是应该是还是有别的加密。当然这次再对照着opcode看,在xtea加密前还有一个异或。

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

/* take 64 bits of data in v[0] and v[1] and 128 bits of key[0] - key[3] */

void encipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {
unsigned int i;
uint32_t v0=v[0], v1=v[1], sum=0, delta=0x12345678;
for (i=0; i < num_rounds; i++) {
v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
sum += delta;
v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);
}
v[0]=v0; v[1]=v1;
}

void decipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {
unsigned int i;
uint32_t v0=v[0], v1=v[1], delta=0x12345678, sum=delta*num_rounds;
for (i=0; i < num_rounds; i++) {
v1 -= (((v0 << 3) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum+1) & 3]);
sum -= delta;
v0 -= (((v1 << 3) ^ (v1 >> 5)) + v1) ^ (sum + key[((sum>>11)+1) & 3]);
}
v[0]=v0; v[1]=v1;
}

int main()
{
uint32_t v[]={0xf469358b, 0x7f165145, 0x116e127a, 0xd6105917, 0xbce5225d, 0x6d62a714, 0xc390c5ed, 0x93b22d8b, 0x6b102a88, 0x13488fdb },k[4]={'aaaa','ssss','dddd','ffff'};
unsigned int r=32;//num_rounds建议取值为32
// v为要加密的数据是两个32位无符号整数
// k为加密解密密钥,为4个32位无符号整数,即密钥长度为128位
for(int i=0;i<5;++i){
decipher(16, &v[i*2], k);
printf("%08x%08x",v[i*2],v[i*2+1]);
}
return 0;
}
//67080e02194b500d5c585f0b5e40461511470a08154211560d47491e04031d262771217626242765
1
2
3
4
5
6
7
8
a = bytes.fromhex('67080e02194b500d5c585f0b5e40461511470a08154211560d47491e04031d262771217626242765')
a = list(a)
x=0
for i in range(len(a)):
a[i] ^= x ^ (i+1)
x = a[i]
print(bytes(a))
# flag{6ad1c70c-daa4-11ec-9d64-0242ac1200}

secreeeeet

这类题在外国的ctf见过一次,就是通过加密算法生成图片文件,我们要做的就是解密png文件。代码很多但多数无用,找到主要代码就行

我们通过自己构造flag.png尝试加密,发现每次加密都不一样,可能跟随机数有关

image-20220617155208038

发现在main函数开头调用了Xtime_get_ticks获取时间戳,动态调试发现sub_140004940函数将时间戳从数字变为字符串

image-20220617155639380

找到主要加密处;这个地方有点逆天,不知道是啥东西,经查阅应该是rabbit流加密

image-20220617155754520

借用REtard师傅的脚本

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
import struct

# https://github.com/Robin-Pwner/Rabbit-Cipher


def ROTL8(v, n):
return (((v << n) & 0xff) | ((v >> (8-n)) & 0xff))


def ROTL16(v, n):
return (((v << n) & 0xffff) | ((v >> (16-n)) & 0xffff))


def ROTL32(v, n):
return (((v << n) & 0xffffffff) | ((v >> (32-n)) & 0xffffffff))


def ROTL64(v, n):
return (((v << n) & 0xffffffffffffffff) | ((v >> (64-n)) & 0xffffffffffffffff))


def ROTR8(v, n):
return ROTL(V, 8-n)


def ROTR16(v, n):
return ROTL(V, 16-n)


def ROTR32(v, n):
return ROTL(V, 32-n)


def ROTR64(v, n):
return ROTL(V, 64-n)


def SWAP32(v):
return ((ROTL32(v, 8) & 0x00ff00ff) | (ROTL32(v, 24) & 0xff00ff00))


class Rabbit_state(object):
def __init__(self):
self.x = [0]*8
self.c = [0]*8
self.carry = 0


class Rabbit_ctx(object):
def __init__(self):
self.m = Rabbit_state()
self.w = Rabbit_state()


class Rabbit(object):
def __init__(self, key, iv):
self.ctx = Rabbit_ctx()
self.set_key(key)
if(len(iv)):
self.set_iv(iv)

def g_func(self, x):
x = x & 0xffffffff
x = (x*x) & 0xffffffffffffffff
result = (x >> 32) ^ (x & 0xffffffff)
return result

def set_key(self, key: bytes):
# generate four subkeys
key0, key1, key2, key3 = struct.unpack('<4I', key)
s = self.ctx.m
# generate initial state variables
s.x[0] = key0
s.x[2] = key1
s.x[4] = key2
s.x[6] = key3
s.x[1] = ((key3 << 16) & 0xffffffff) | ((key2 >> 16) & 0xffff)
s.x[3] = ((key0 << 16) & 0xffffffff) | ((key3 >> 16) & 0xffff)
s.x[5] = ((key1 << 16) & 0xffffffff) | ((key0 >> 16) & 0xffff)
s.x[7] = ((key2 << 16) & 0xffffffff) | ((key1 >> 16) & 0xffff)
# generate initial counter values
s.c[0] = ROTL32(key2, 16)
s.c[2] = ROTL32(key3, 16)
s.c[4] = ROTL32(key0, 16)
s.c[6] = ROTL32(key1, 16)
s.c[1] = (key0 & 0xffff0000) | (key1 & 0xffff)
s.c[3] = (key1 & 0xffff0000) | (key2 & 0xffff)
s.c[5] = (key2 & 0xffff0000) | (key3 & 0xffff)
s.c[7] = (key3 & 0xffff0000) | (key0 & 0xffff)
s.carry = 0

# Iterate system four times
for i in range(4):
self.next_state(self.ctx.m)

for i in range(8):
# modify the counters
self.ctx.m.c[i] ^= self.ctx.m.x[(i+4) & 7]

# Copy master instance to work instance
self.ctx.w = self.copy_state(self.ctx.m)

def copy_state(self, state):
n = Rabbit_state()
n.carry = state.carry

for i, j in enumerate(state.x):
n.x[i] = j
for i, j in enumerate(state.c):
n.c[i] = j
return n

def set_iv(self, iv: bytes):
# generate four subvectors
v = [0]*4
v[0], v[2] = struct.unpack('<2I', iv)
v[1] = (v[0] >> 16) | (v[2] & 0xffff0000)
v[3] = ((v[2] << 16) | (v[0] & 0x0000ffff)) & 0xffffffff
# Modify work's counter values
for i in range(8):
self.ctx.w.c[i] = self.ctx.m.c[i] ^ v[i & 3]
# Copy state variables but not carry flag
tmp = []

for cc in self.ctx.m.x:
tmp += [cc]
self.ctx.w.x = tmp

# Iterate system four times
for i in range(4):
self.next_state(self.ctx.w)

def next_state(self, state):
g = [0]*8
x = [0x4D34D34D, 0xD34D34D3, 0x34D34D34]
# calculate new counter values
for i in range(8):
tmp = state.c[i]
state.c[i] = (state.c[i]+x[i % 3]+state.carry) & 0xffffffff
state.carry = (state.c[i] < tmp)
# calculate the g-values
for i in range(8):
g[i] = self.g_func(state.x[i]+state.c[i])
# calculate new state values

j = 7
i = 0
while(i < 8):
state.x[i] = (g[i] + ROTL32(g[j], 16) +
ROTL32(g[j-1], 16)) & 0xffffffff
i += 1
j += 1
state.x[i] = (g[i] + ROTL32(g[j & 7], 8) + g[j-1]) & 0xffffffff
i += 1
j += 1
j &= 7

def crypt(self, msg):
plain = b""
l = len(msg)
c = self.ctx
x = [0]*4
start = 0
while(True):
self.next_state(c.w)
for i in range(4):
x[i] = c.w.x[i << 1]
x[0] ^= (c.w.x[5] >> 16) ^ (c.w.x[3] << 16)
x[1] ^= (c.w.x[7] >> 16) ^ (c.w.x[5] << 16)
x[2] ^= (c.w.x[1] >> 16) ^ (c.w.x[7] << 16)
x[3] ^= (c.w.x[3] >> 16) ^ (c.w.x[1] << 16)
b = [0]*16
for i, j in enumerate(x):
for z in range(4):
b[z+4*i] = 0xff & (j >> (8*z))
for i in range(16):
plain += bytes([(msg[start]) ^ b[i]])
start += 1
if(start == l):
return plain


py3版本的rabbit

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
from rabbit_cipher import Rabbit
from functools import lru_cache
from itertools import product
import string


def key_subs(key):
return key.translate(b''.maketrans(b'0123456789', b'qscfthnjik'))


def key_expand(key):
expand = bytearray(b'\x00'*0x10)
for i in range(0x10):
if i < len(key):
expand[i] = key[i]
else:
expand[i] = (expand[i - 1] + expand[i - 2]) & 0xFF
return bytes(expand)


def secret_crypt(msg, key):
return Rabbit(key_expand(key_subs(key)), b'\x01\x02\x03\x04\x05\x06\x07\x08').crypt(msg)


@lru_cache(100000)
def secret_crypt_lru(msg, key):
return secret_crypt(msg, key)


def xor(data, key):
data = bytearray(data)
for i in range(len(data)):
data[i] ^= key[i % 3]
return bytes(data)


def bruteforce_key(enc_msg):
png_fixed_header = b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR'
for k3 in product(string.digits, repeat=3):
key3 = ''.join(k3).encode()
for k5 in product(string.digits, repeat=5):
key5 = ''.join(k5).encode()
print('\rprocess', key3, key5, end='')
if xor(secret_crypt_lru(enc_msg, key5), key3) == png_fixed_header:
print('')
return (key3, key5)
raise Exception("not found")


flag_png_enc = open('flag.png.enc', 'rb').read()
key3, key5 = bruteforce_key(flag_png_enc[:0x10]) # (2, 80106)
flag_png = xor(secret_crypt_lru(flag_png_enc, key5), key3)
open('flag.png', 'wb').write(flag_png)

只需要爆破两个key然后逆向rabbit即可