比赛难度中等偏难,主办方修了非预期还没修好,不修了摆烂了。
队伍成绩:425pt/10kill/全国48名/华中赛区3名
个人成绩:359pt/6kill/1三血/全国42名
Misc
ez_usb[三血]
打开流量包,发现好多USB流量。
其中2.8可以确定是键盘。
2.4查了下好像是U盘。
2.10有个罗技标,查了下产品id应该也是键盘。
所以目标放在那俩把键盘上,写一下带过滤的提取,分别提取出两个键盘的流量数据。
tshark -r "ez_usb.pcapng" -Y "usb.src==\"2.8.1\" && usb.dst==host" -T fields -e usbhid.data > keyboarda.txt
tshark -r "ez_usb.pcapng" -Y "usb.src==\"2.10.1\" && usb.dst==host" -T fields -e usbhid.data > keyboardb.txt
改改通用的键盘流量解码脚本,跑一下。
mappings_a = {0x04: "a", 0x05: "b", 0x06: "c", 0x07: "d", 0x08: "e", 0x09: "f", 0x0a: "g", 0x0b: "h", 0x0c: "i",
0x0d: "j", 0x0e: "k", 0x0f: "l", 0x10: "m", 0x11: "n", 0x12: "o", 0x13: "p", 0x14: "q", 0x15: "r",
0x16: "s", 0x17: "t", 0x18: "u", 0x19: "v", 0x1a: "w", 0x1b: "x", 0x1c: "y", 0x1d: "z", 0x1e: "1",
0x1f: "2", 0x20: "3", 0x21: "4", 0x22: "5", 0x23: "6", 0x24: "7", 0x25: "8", 0x26: "9", 0x27: "0",
0x28: "[enter]", 0x2a: "[del]", 0x2b: "[tab]", 0x2c: " ", 0x2d: "-", 0x2e: "=", 0x2f: "[", 0x30: "]", 0x31: "\\",
0x32: "~", 0x33: ";", 0x34: "'", 0x36: ",", 0x37: ".", 0x39: "[cap]"}
mappings_A = {0X04: "A", 0X05: "B", 0X06: "C", 0X07: "D", 0X08: "E", 0X09: "F", 0X0A: "G", 0X0B: "H", 0X0C: "I",
0X0D: "J", 0X0E: "K", 0X0F: "L", 0X10: "M", 0X11: "N", 0X12: "O", 0X13: "P", 0X14: "Q", 0X15: "R",
0X16: "S", 0X17: "T", 0X18: "U", 0X19: "V", 0X1A: "W", 0X1B: "X", 0X1C: "Y", 0X1D: "Z", 0X1E: "1",
0X1F: "2", 0X20: "3", 0X21: "4", 0X22: "5", 0X23: "6", 0X24: "7", 0X25: "8", 0X26: "9", 0X27: "0",
0X28: "[ENTER]", 0X2A: "[DEL]", 0X2B: "[TAB]", 0X2C: " ", 0X2D: "-", 0X2E: "=", 0X2F: "[", 0X30: "]", 0X31: "\\",
0X32: "~", 0X33: ";", 0X34: "'", 0X36: ",", 0X37: ".", 0X39: "[CAP]"}
data = ""
with open("keyboarda.txt", 'r') as f:
for i in f:
a = bytes.fromhex(i)
if a[0] == 0:
if a[2] != 0:
data += mappings_a[a[2]]
elif a[0] == 0x20:
if a[2] != 0:
data += mappings_A[a[2]]
print(data)
data = ""
with open("keyboardb.txt", 'r') as f:
for i in f:
a = bytes.fromhex(i)
if a[0] == 0:
if a[2] != 0:
data += mappings_a[a[2]]
elif a[0] == 0x20:
if a[2] != 0:
data += mappings_A[a[2]]
print(data)
发现一堆十六进制和Tab、CapsLock、Delete,反正大小写对十六进制不影响,所以忽略掉CapsLock,然后Tab键感觉也没啥用,反正就在开头有一次键入,至于Delete的话这里意思应该是删掉前一个键入,所以最终得到的两串十六进制是:
526172211a0700cf907300000d00000000000000c4527424943500300000002a00000002b9f9b0530778b5541d33080020000000666c61672e747874b9ba013242f3afc000b092c229d6e994167c05a78708b271ffc042ae3d251e65536f9ada87c77406b67d0e6316684766a86e844dc81aa2c72c71348d10c43d7b00400700
35c535765e50074a
前者把十六进制转raw得到一个rar压缩包。
打开发现需要密码。
尝试用第二个字符串当密码成功解压,得到flag。
flag{20de17cc-d2c1-4b61-bebd-41159ed7172d}
问卷调查
掐点去做的问卷,没赶上后面出问题的时候,直接出了flag交了。
flag{Thanksforplayingourgames}
Crypto
基于挑战码的双向认证+基于挑战码的双向认证2
非预期了,直接扫盘就能找到两题的flag。
find / -name '*flag*'
flag{81f14d6d-aef0-418b-85cb-0e8d4fc9515a}
flag{34f5fdaf-c373-47fd-afab-01ed2914c11a}
Reverse
baby_tree
拿到题目,发现是个swift的ast,没找到啥好用的一键还原成.swift代码的工具,那就强行转成自己擅长的python代码再逆向吧。
先当作js高亮一下,方便看代码关系和层次。
然后手动标记一下一些重要的关键词,主要如下:
encoded
keyValue
extension
@
i@
b@
k@
value=
r0
r1
r2
r3
然后就来分析ast了。
先是定义了个check函数,传参是俩字符串,然后返回逻辑值。根据缩进判断函数主体逻辑在brace_stmt块里。
然后是定义了个b变量,初始值是拆分encoded得到的。
然后定义的k变量和b差不多,只不过是拆分keyValue的。
然后定义了几个未初始化的变量r0、r1、r2、r3。
然后下面就是一个超大循环体和超大返回语句。
先看for循环,迭代器i的定义比较长,...操作符类似于kotlin的..,就是个range,然后下面俩argument分别表示开头和结尾,所以开头很简单,是0,结尾是外面一个-操作符,两个元是b.count和4,所以现在这个for循环就是for i in range(0, len(b) - 4+1):,+1是因为python里结尾不包括,但是swift是包括的。
然后看for循环主体部分,主要就是六个感觉像赋值语句的东西。
先看第一个,赋值的目标是一个四元组,内容是r0、r1、r2、r3。
然后值的话,第一个就是b[i],第二个是b[i+1],第三个是b[i+2],第四个是b[i+3]。
所以python代码就是r0, r1, r2, r3 = b[i], b[i+1], b[i+2], b[i+3]。
然后看第二个复制块,赋值目标是b[i+0]。
值是r2 ^ ((k[0] + (r0 >> 4)) & 0xff),一层一层分析操作符及其元就可以得出,不再详细解释。
下面4个赋值块和上面这2个赋值块其实代码也差不多,所以不过多解释,分别是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]
最后来看函数return,就是比较b和一个数组常量。
然后看函数外面的顶层代码。先是判断了下cmd传参个数,确保>=2。
然后把arg[1]赋值给data。
key定义成常量,值是345y。
然后最后调用上面的check函数,传参是(data, key),把结果赋值给result。
所以最后代码就是:
def check(encoded: str, keyValue: str) -> bool:
b = [ord(i) for i in encoded] # len == 42
k = [ord(i) for i in keyValue] # len == 4
r0, r1, r2, r3 = 0, 0, 0, 0
for i in range(0, len(b) - 4+1):
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]
return b == [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]
if __name__ == '__main__':
print(check(flag, "345y"))
那么这就简单了,其中涉及的其实主要就是异或操作,反向异或就完事,然后注意一下赋值的顺序问题,以及key的初始值应该先走一轮,就可以直接写个逆向逻辑的函数去解了:
def rev(encoded: list, keyValue: str) -> str:
b = encoded
k = [ord(i) for i in keyValue] # len == 4
for i in range(0, len(b) - 4+1):
k[0], k[1], k[2], k[3] = k[1], k[2], k[3], k[0]
for i in range(len(b) - 4+1-1, 0-1, -1):
k[1], k[2], k[3], k[0] = k[0], k[1], k[2], k[3]
r1 = b[i + 3] ^ k[3]
r0 = b[i + 2] ^ k[2]
r3 = b[i + 1] ^ ((k[1] + (r1 >> 2)) & 0xff)
r2 = b[i + 0] ^ ((k[0] + (r0 >> 4)) & 0xff)
(b[i], b[i + 1], b[i + 2], b[i + 3]) = (r0, r1, r2, r3)
return bytearray(b).decode()
if __name__ == '__main__':
print(rev(
[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],
"345y"
))
flag{30831242-56db-45b4-96fd-1f47e60da99d}
babycode
拿到题目,发现后缀是mrb的,然后文件头是RITEXXXX,所以肯定是mruby的字节码了。
那就先用./mruby -v去提取字节码的汇编吧。
得到:
irep 0x55cb1570a510 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:0x55cb1570a5c0)
010 TCLASS R2
012 METHOD R3 I(1:0x55cb1570adc0)
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 0x55cb1570a5c0 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:0x55cb1570a690)
010 RETURN R1
irep 0x55cb1570a690 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:0x55cb1570a7d0)
022 DEF R1 :encrypt
025 TCLASS R1
027 METHOD R2 I(1:0x55cb1570a870)
030 DEF R1 :encrypt
033 SSEND R1 :private n=0 (0x00)
037 TCLASS R1
039 METHOD R2 I(2:0x55cb1570ab90)
042 DEF R1 :to_key
045 TCLASS R1
047 METHOD R2 I(3:0x55cb1570ac60)
050 DEF R1 :enc_one
053 RETURN R1
irep 0x55cb1570a7d0 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 0x55cb1570a870 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:0x55cb1570aac0)
333 SENDB R11 :collect n=0 (0x00)
337 STRING R12 L(0) ;
340 SEND R11 :join n=1 (0x01)
344 RETURN R11
irep 0x55cb1570aac0 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 0x55cb1570ab90 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 0x55cb1570ac60 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:0x55cb1570ad30)
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 0x55cb1570ad30 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 0x55cb1570adc0 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
先看开头的0x55cb1570a510代码块,大概意思就是定义Crypt类,然后定义的时候执行0x55cb1570a5c0初始化,执行再给这个类加上个0x55cb1570adc0叫做check函数,然后就是gets输入,赋值给p,再调用check(p),最后判断返回的逻辑值。
那就接着看0x55cb1570a5c0初始化了啥东西,实际上就是执行了下0x55cb1570a690。
那就接着看0x55cb1570a690,先是定义了俩常量XX=305419896,YY=16,然后加了0x55cb1570a7d0和0x55cb1570a870都叫encrypt(至于为啥能有俩同名函数,应该是重载之类的?不太清楚,ruby总不能连重载特性都没有吧),然后0x55cb1570ab90叫to_key,0x55cb1570ac60叫enc_one,就完事了。
那着时候就去看主要的逻辑check,也就是0x55cb1570adc0,可以看出传参是p,局部变量是i、lst_ch、c、k、cipher_text,然后根据几个LT指令和JMP、JMPNOT指令,可以看出是对i做循环,条件是for i in range(len(p))。
然后024~030就是取p[i],然后032~036把取的结果ord一下再赋值给c,039~045取c和lst_ch异或,其中lst_ch在上面定义过,LOADI_0就说明初始值是0,然后049~052是取个i+1,055是把上面的c^lst_ch和这个i+1异或,然后059把异或结果chr回来,063~072表示给p[i]赋值上面的chr结果,074~080说明把c赋值给lst_ch。
然后080说明循环步长是1,086循环结束,定义k="aaaassssddddffff",然后089~105调用Crypt.CIPHER.encrypt(p, k),赋值给cipher_text,最后108~114比较cipher_text和常量f469358b7f165145116e127ad6105917bce5225d6d62a714c390c5ed93b22d8b6b102a8813488fdb,相等即通过。
所以再去看encrypt,先看0x55cb1570a7d0的,传参是t, p,好像就是包装了下另一个在0x55cb1570a870的encrypt。
那就看0x55cb1570a870,传参还是t, p,其中004~011就是key = to_key(p),014和017分别定义c=[]和n=0。
接着又是一个循环,可以看出是while n < len(t): n += 8
然后循环内035~153其实就是:
num1 = ord(t[n]) << 24
num1 += ord(t[n+1]) << 16
num1 += ord(t[n+2]) << 8
num1 += ord(t[n+3])
同理下面156~277就是:
num2 = ord(t[n+4]) << 24
num2 += ord(t[n+5]) << 16
num2 += ord(t[n+6]) << 8
num2 += ord(t[n+7])
然后280~317是:
enum1, enum2 = enc_one(num1, num2, key)
c.append(enum1)
c.append(enum2)
出了循环后,是调用了"".join(c.collect(0x55cb1570aac0))。
而0x55cb1570aac0就是进制转换。
to_key的0x55cb1570ab90就是每4字节转成一个整数。
enc_one的0x55cb1570ac60就是YY.times循环0x55cb1570ad30,也就是循环YY次,然后返回y, z。
最后0x55cb1570ad30,就是一堆位操作,记好各个寄存器就行:
y = y + ((((z << 3) ^ (z >> 5)) + z) ^ (s + key[((s >> 11) + 1) & 3]))
y = y & 0xffffffff
s = s + XX
z = z + ((((y << 3) ^ (y >> 5)) + y) ^ (s + key[(s + 1) & 3]))
z = z & 0xffffffff
最后转换的python代码如下:
def main(p):
return check(p)
def encrypt(t, p):
key = to_key(p)
c = []
n = 0
while n < len(t):
# num1 = int(t[n:n + 4].hex(), 16)
num1 = ord(t[n]) << 24
num1 += ord(t[n+1]) << 16
num1 += ord(t[n+2]) << 8
num1 += ord(t[n+3])
# num2 = int(t[n+4:n+8].hex(), 16)
num2 = ord(t[n+4]) << 24
num2 += ord(t[n+5]) << 16
num2 += ord(t[n+6]) << 8
num2 += ord(t[n+7])
enum1, enum2 = enc_one(num1, num2, key)
c.append(enum1)
c.append(enum2)
n += 8
return "".join([("00000000"+hex(i)[2:])[-8:] for i in c])
def to_key(p):
a = []
for i in range(0, len(p), 4):
a.append(int(p.encode()[i:i+4].hex(), 16))
return a
def enc_one(num1, num2, key):
y = num1 # R5
z = num2 # R6
s = 0 # R7
for _ in range(YY):
y = y + ((((z << 3) ^ (z >> 5)) + z) ^ (s + key[((s >> 11) + 1) & 3]))
y = y & 0xffffffff
s = s + XX
z = z + ((((y << 3) ^ (y >> 5)) + y) ^ (s + key[(s + 1) & 3]))
z = z & 0xffffffff
return y, z
def check(p):
p = bytearray(p.encode())
lst_ch = 0
for i in range(len(p)):
c = p[i]
p[i] = (c ^ lst_ch) ^ (i + 1)
lst_ch = c
k = "aaaassssddddffff"
print(p.hex())
cipher_text = encrypt(p, k)
return cipher_text
if __name__ == '__main__':
XX = 305419896
YY = 16
main(flag)
所以写出逆向逻辑就行。
def to_key(p):
a = []
for i in range(0, len(p), 4):
a.append(int(p.encode()[i:i+4].hex(), 16))
return a
c = "f469358b7f165145116e127ad6105917bce5225d6d62a714c390c5ed93b22d8b6b102a8813488fdb"
XX = 305419896
YY = 16
key = to_key("aaaassssddddffff")
dec = bytearray(40)
for i in range(0, len(c), 16):
num1 = int(c[i:i+8], 16)
num2 = int(c[i+8:i+16], 16)
y = num1 # R5
z = num2 # R6
s = 0
for _ in range(YY):
s = s + XX
for _ in range(YY):
z = z - ((((y << 3) ^ (y >> 5)) + y) ^ (s + key[(s + 1) & 3]))
z = z & 0xffffffff
s = s - XX
y = y - ((((z << 3) ^ (z >> 5)) + z) ^ (s + key[((s >> 11) + 1) & 3]))
y = y & 0xffffffff
dec[i//2:i//2+4] = bytes.fromhex(("0000"+hex(y)[2:])[-8:])
dec[i//2+4:i//2+8] = bytes.fromhex(("0000"+hex(z)[2:])[-8:])
print(dec.hex())
lst_ch = 0
for i in range(len(dec)):
c = dec[i]
dec[i] = (c ^ (i + 1)) ^ lst_ch
lst_ch = dec[i]
print(dec)
flag{6ad1c70c-daa4-11ec-9d64-0242ac1200}

