手滑的袁学长 题目描述 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 import osfrom Crypto.Util import *from Crypto.Util.strxor import *from Crypto.Cipher import AESanswer = open ('FLAG1/flag' , 'rb' ).read() print (len (answer))def Function_enc (msg, key, p_2, c_2 ): msg = Padding.pad(msg, 16 ) struct = [msg[i:i+16 ] for i in range (0 , len (msg), 16 )] out = b'' for p in struct: c = strxor(p, c_2) c = AES.new(key, AES.MODE_ECB).encrypt(c) out += strxor(p_2, c) c_2 = c p_2 = p return out KEY = os.urandom(16 ) msg = 'I do not care the result' + KEY.hex () text = Function_enc(msg.encode(), KEY, answer[:16 ], answer[16 :]) print ('key = ' + KEY.hex ())print ('cipher =' + text.hex ())while True : print (0 )
解题思路 加密算法的大致思路如下,比较简单易懂
首先的思路是从后往前做,求出out3之后看看包不包含已知部分,核心思想还是Brute-force
一个小插曲 一开始以为思路跑偏了,因为袁学长删除的部分是hex之后的,就不是原理四部分组成的out了,但还是先记录下脚本
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 import osfrom Crypto.Util import *from Crypto.Util.strxor import *from Crypto.Cipher import AESimport syshex_num = '0123456789abcdef' key_hex = list ('2$9cf037f8b3a$2b19b5bda978c294$5' ) possible_key = [] for i in hex_num: key_hex[1 ] = i for j in hex_num: key_hex[13 ] = j for k in hex_num: key_hex[-2 ] = k possible_key.append("" .join(key_hex)) cipher_hex = '91e5fb43f053b21ce12e41df0b0ae0bb6a20c55719151$$fccecb4$$$$$2a27c8c582c6704f$$$$153bd3313b84235ace16a7b3b190$e487abfa9$cf379d1a3c' cipher_hex1 = '91e5fb43f053b21ce12e41df0b0ae0bb' cipher_hex2 = list ('6a20c55719151$$fccecb4$$$$$2a27c' ) cipher_hex3 = list ('8c582c6704f$$$$153bd3313b84235ac' ) cipher_hex4 = list ('e16a7b3b190$e487abfa9$cf379d1a3c' ) possible_cipher_hex4 = [] for i in hex_num: cipher_hex4[11 ] = i for j in hex_num: cipher_hex4[21 ] = j possible_cipher_hex4.append("" .join(cipher_hex4)) flag = 'DozerCTF{' for tmp_key in possible_key: msg = ('I do not care the result' + tmp_key.encode().hex ()).encode() msg = Padding.pad(msg, 16 ) struct = [msg[i:i + 16 ] for i in range (0 , len (msg), 16 )] tmp_m2, tmp_m3, tmp_m4 = struct[1 ], struct[2 ], struct[3 ] for tmp_out4 in possible_cipher_hex4: tmp_aes_c4 = strxor(number.long_to_bytes(int (tmp_out4, 16 )), tmp_m3) tmp_aes_m4 = AES.new(tmp_key.encode(), AES.MODE_ECB).decrypt(tmp_aes_c4) tmp_aes_c3 = strxor(tmp_m4, tmp_aes_m4) tmp_out3 = strxor(tmp_aes_c3, tmp_m2) tmp_out3 = tmp_out3.hex () if tmp_out3.startswith('8c582c6704f' ): print (tmp_out3) sys.exit(0 )
但后来发现应该没有错,我们自己写了一个flag,然后进行加密,看out输出和hex之后的结果,截取其中的某一段进行hex的反操作
1 2 3 4 out = b'\xafF/\xcaM\x1a\xcf\x9b%\x88T\x01\x8a\x1fKb\x04\x85\xd0\xd7\x8d\xb5\x16\xb6\xc5\xd2\xe1\x92\xff\xf3\xe6e\xe0A\x8f\xc5{(GG>\xbd\xff\xbc\xef\xef\xf0X@ .\xd6L\x08,\xa2H\xc3\x1a\xf4{DQB' cipher = af462fca4d1acf9b258854018a1f4b620485d0d78db516b6c5d2e192fff3e665e0418fc57b2847473ebdffbcefeff05840202ed64c082ca248c31af47b445142
1 2 3 4 5 from Crypto.Util.number import *c = '0485d0d78db516b6c5d2e192fff3e665' print (long_to_bytes(int (c, 16 )))
出来的结果是
1 b'\x04\x85\xd0\xd7\x8d\xb5\x16\xb6\xc5\xd2\xe1\x92\xff\xf3\xe6e'
显然结果是完全一样的,至于原理,应该是字节转数字的问题,这里不再深究
所以思路的基础没有毛病
然后发现aes的key有问题,之前代码里的key和题目中用来充当密钥的key不是一样的
我随机生成了一个key,并输出hex之后的结果
1 2 3 b'\xdb\x8dL+*\xf0?\x824oy\xf2cY\x95y' key_hex = db8d4c2b2af03f82346f79f263599579
用之前的简单转回字节的方法
1 2 3 from Crypto.Util.number import long_to_bytesprint ('db8d4c2b2af03f82346f79f263599579' .encode())print (long_to_bytes(int ('db8d4c2b2af03f82346f79f263599579' , 16 )))
出来是
1 b'db8d4c2b2af03f82346f79f263599579'
破案啦,显然两个字节流并不一样,问题出在aes的key上
然后用hex的反操作就可以逆回去
最终的操作如下
1 2 3 4 5 6 7 8 9 10 11 from Crypto.Util.number import long_to_bytesimport osKEY = os.urandom(16 ) print ("key = " , KEY)print ("key_hex = " , KEY.hex ())key = KEY.hex () print ("tmp_key = " , bytes .fromhex(key))print (long_to_bytes(int (key, 16 )))assert KEY == bytes .fromhex(key)assert KEY == long_to_bytes(int (key, 16 ))
运行结果
1 2 3 4 key = b':\xa7\xb6G\x02m\x8f\xcc,n\xa6\xfcH\xea\xc44' key_hex = 3aa7b647026d8fcc2c6ea6fc48eac434 tmp_key = b':\xa7\xb6G\x02m\x8f\xcc,n\xa6\xfcH\xea\xc44' b':\xa7\xb6G\x02m\x8f\xcc,n\xa6\xfcH\xea\xc44'
当然,有用到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 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 import osfrom Crypto.Util import *from Crypto.Util.strxor import *from Crypto.Cipher import AESimport syshex_num = '0123456789abcdef' key_hex = list ('2$9cf037f8b3a$2b19b5bda978c294$5' ) possible_key = [] for i in hex_num: key_hex[1 ] = i for j in hex_num: key_hex[13 ] = j for k in hex_num: key_hex[-2 ] = k possible_key.append("" .join(key_hex)) cipher_hex = '91e5fb43f053b21ce12e41df0b0ae0bb6a20c55719151$$fccecb4$$$$$2a27c8c582c6704f$$$$153bd3313b84235ace16a7b3b190$e487abfa9$cf379d1a3c' cipher_hex1 = '91e5fb43f053b21ce12e41df0b0ae0bb' cipher_hex2 = list ('6a20c55719151$$fccecb4$$$$$2a27c' ) cipher_hex3 = list ('8c582c6704f$$$$153bd3313b84235ac' ) cipher_hex4 = list ('e16a7b3b190$e487abfa9$cf379d1a3c' ) possible_cipher_hex4 = [] for i in hex_num: cipher_hex4[11 ] = i for j in hex_num: cipher_hex4[21 ] = j possible_cipher_hex4.append("" .join(cipher_hex4)) flag = 'DozerCTF{' count = 0 for tmp_key in possible_key: msg = ('I do not care the result' + tmp_key).encode() msg = Padding.pad(msg, 16 ) struct = [msg[i:i + 16 ] for i in range (0 , len (msg), 16 )] tmp_m2, tmp_m3, tmp_m4 = struct[1 ], struct[2 ], struct[3 ] for tmp_out4 in possible_cipher_hex4: tmp_aes_c4 = strxor(bytes .fromhex(tmp_out4), tmp_m3) tmp_aes_m4 = AES.new(bytes .fromhex(tmp_key), AES.MODE_ECB).decrypt(tmp_aes_c4) tmp_aes_c3 = strxor(tmp_m4, tmp_aes_m4) tmp_out3 = strxor(tmp_aes_c3, tmp_m2) tmp_out3 = tmp_out3.hex () count += 1 print (count) if tmp_out3.startswith('8c582c6704f' ): print ("key_hex =" , tmp_key) print ("tmp_aes_m4 =" , tmp_aes_m4) sys.exit(0 )
跑出来是
1 2 key_hex = 279cf037f8b3a92b19b5bda978c294f5 tmp_aes_m4 = b'\xde@=0N\xbf\x0c\xc0i\x82\x02x\xd6z\x0e\x93'
什么都已经知道了,剩下的就是还原answer了,四步奏aes,只要一步一步走回去就好了
解题脚本 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 osfrom Crypto.Util import *from Crypto.Util.strxor import *from Crypto.Cipher import AESdef function_dec (msg_p, key, aes_p ): msg_p = Padding.pad(msg_p, 16 ) struct = [msg_p[i:i+16 ] for i in range (0 , len (msg_p), 16 )] tmp_c = b'' for p in struct[3 :0 :-1 ]: c = strxor(aes_p, p) tmp_c = c c = AES.new(key, AES.MODE_ECB).decrypt(c) aes_p = c return tmp_c key_hex = '279cf037f8b3a92b19b5bda978c294f5' aes_m4 = b'\xde@=0N\xbf\x0c\xc0i\x82\x02x\xd6z\x0e\x93' KEY = bytes .fromhex(key_hex) msg = 'I do not care the result' + KEY.hex () aes_c1 = function_dec(msg.encode(), KEY, aes_m4) out1 = '91e5fb43f053b21ce12e41df0b0ae0bb' answer1 = strxor(bytes .fromhex(out1), aes_c1) msg1 = b'I do not care th' aes_m1 = AES.new(KEY, AES.MODE_ECB).decrypt(aes_c1) answer2 = strxor(msg1, aes_m1) print (answer1 + answer2)