Crypto mostlycommon 共模再开个方
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import gmpy2from Crypto.Util.number import *e1 = 65536 // 2 e2 = 270270 // 2 n = 122031686138696619599914690767764286094562842112088225311503826014006886039069083192974599712685027825111684852235230039182216245029714786480541087105081895339251403738703369399551593882931896392500832061070414483233029067117410952499655482160104027730462740497347212752269589526267504100262707367020244613503 c1 = 39449016403735405892343507200740098477581039605979603484774347714381635211925585924812727991400278031892391996192354880233130336052873275920425836986816735715003772614138146640312241166362203750473990403841789871473337067450727600486330723461100602952736232306602481565348834811292749547240619400084712149673 c2 = 43941404835820273964142098782061043522125350280729366116311943171108689108114444447295511969090107129530187119024651382804933594308335681000311125969011096172605146903018110328309963467134604392943061014968838406604211996322468276744714063735786505249416708394394169324315945145477883438003569372460172268277 get_tuple = gmpy2.gcdext(e1, e2) r = -get_tuple[1 ] s = get_tuple[2 ] a = gmpy2.powmod(gmpy2.invert(c1, n), r, n) b = gmpy2.powmod(c2, s, n) m = gmpy2.f_mod(gmpy2.mul(a,b),n) print (gmpy2.iroot(m, 2 ))print (long_to_bytes(gmpy2.iroot(m, 2 )[0 ]))
easytask 虽然r
是完全可以爆破的,但是要3个小时才能跑完,比赛中没有出
没做出来的原因总结一下几点
遍历所有的r
不慢,但是不精明的操作(在循环中生成AES解密)会导致空间复杂度很大,导致程序非常慢
赛后问尚师傅,其实真正的r
开头是-3 -2
(应该是刻意为之),所以尽管空间复杂度很大,但是比赛中还是遍历到了,判断机制写得不对
综上,判断机制不是非得是flag.starswith(b'flag')
,求出来的m
很有特征的;可以学尚师傅,先自己定个r
,然后用脚本跑一遍(处理大数据,样本方法
比赛中先算出r
保存在内存里,再开始遍历
调整后的脚本快多了
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 import hashlibfrom Crypto.Cipher import AESimport refrom itertools import productc = '1070260d8986d5e3c4b7e672a6f1ef2c185c7fff682f99cc4a8e49cfce168aa0' c = bytes .fromhex(c) ct_e = '[151991736758354 115130361237591 58905390613532 130965235357066 74614897867998 48099459442369 45894485782943 7933340009592 25794185638]' ct_W = '''[-10150241248 -11679953514 -8802490385 -12260198788 -10290571893 -334269043 -11669932300 -2158827458 -7021995] [ 52255960212 48054224859 28230779201 43264260760 20836572799 8191198018 14000400181 4370731005 14251110] [ 2274129180 -1678741826 -1009050115 1858488045 978763435 4717368685 -561197285 -1999440633 -6540190] [ 45454841384 34351838833 19058600591 39744104894 21481706222 14785555279 13193105539 2306952916 7501297] [-16804706629 -13041485360 -8292982763 -16801260566 -9211427035 -4808377155 -6530124040 -2572433293 -8393737] [ 28223439540 19293284310 5217202426 27179839904 23182044384 10788207024 18495479452 4007452688 13046387] [ 968256091 -1507028552 1677187853 8685590653 9696793863 2942265602 10534454095 2668834317 8694828] [ 33556338459 26577210571 16558795385 28327066095 10684900266 9113388576 2446282316 -173705548 -577070] [ 35404775180 32321129676 15071970630 24947264815 14402999486 5857384379 10620159241 2408185012 7841686]''' e = [] for i in re.findall(r"\d+" , ct_e): e.append(int (i)) e = matrix(e) W = [[0 for _ in range (9 )] for j in range (9 )] ct_W = re.findall(r'-?\d+' , ct_W) for i in range (len (ct_W)): W[i // 9 ][i % 9 ] = int (ct_W[i]) W = matrix(W) inv_W = W.inverse() table = [_ for _ in range (-3 , 4 )] r = product(table, repeat=9 ) for ri in r: rx = matrix(ri) m = (e - rx) * inv_W if 0 < m[0 ][0 ] < 1024 : M = list (m[0 ]) key = hashlib.sha256(str (M).encode()).digest() cipher = AES.new(key, AES.MODE_ECB) flag = cipher.decrypt(c) if flag.startswith(b'flag' ) or flag.startswith(b'SET' ): print (r) print (flag) break
让我看看之前的脚本为啥不能出
我们自己写一个r
,就[-3,-3,-3,-3,-3,-3]
吧,然后走一遍,我知道了,是这个问题
sage矩阵转列表的时候要多取一个,差不多是这么一个意思吧
竟然是非预期,做的时候也想着用格来做,但直接爆破还是太诱人了,原题
https://hxp.io/blog/26/VolgaCTF-2016-Quals-crypto300-XXY-writeup/
经过一番搜索后发现原来这是GHH加密
Civet cat for Prince 目的,已知IV,可以获得输入name+'a_cat_permission'
的密文,可以有最多两次自己输入IV和密文进行解密,求输入name+'Princepermission'
的密文,注意最后这里我们可以自己定义IV
重点是最后一句话,这就是利用点,复现的时候我一个上午都没注意到,以为是要用它的IV;然后下午看到,那就比较简单了
一个小思路,假设获取的name_cipher
$c$分成前半段$c_1,\ c_2$,密文构造成 $$ c_1\oplus a_cat_permission\ \oplus Princepermission + c_2\notag $$ 这样第二段密文解密出来就是Princepermission
然后利用一次解密的机会,将上面这个密文的前半段和系统的IV丢进去,得到的结果记为$m_1$,求 $$ m_1\oplus IV \oplus Princepermission\notag $$ 这样解密出来的第一段就是Princepermission
,其实name无所谓什么都可以
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 import hashlibfrom pwn import *from itertools import productimport stringcontext.log_level = 'debug' table = string.ascii_letters + string.digits class Solve : def __init__ (self ): self.sh = remote('node4.buuoj.cn' , 29129 ) self._Princepermission = b'Princepermission' self._a_cat_permission = b'a_cat_permission' self.iv = b'' self.cipher_name = b'' self.payload_cipher = b'' self.payload_iv = b'' def proof_of_work (self ): """ [+] sha256(XXXX+Q3kqSv2c) == e9ded46c9d0dbcf14d8c36852678fe59daec43b1025c282738a81e7ea9f395f9 [+] Give Me XXXX : """ proof = self.sh.recvline() tail = proof[16 :24 ].decode() HASH = proof[29 :93 ].decode() for i in product(table, repeat=4 ): head = '' .join(i) t = hashlib.sha256((head + tail).encode()).hexdigest() if t == HASH: self.sh.recvuntil(b'[+] Give Me XXXX :' ) self.sh.sendline(head.encode()) break def solve_BANNER (self, _name ): self.sh.sendlineafter(b'[-]' , b'1' ) self.sh.sendlineafter(b'[-]' , _name) self.sh.recvline() self.sh.recvline() self.sh.recvuntil(b'Miao~ ' ) self.iv = self.sh.recvuntil(b"I'm a" )[:-6 ] print (len (self.iv)) def solve_NAME (self ): self.sh.sendlineafter(b'[-]' , b'1' ) self.sh.recvuntil(b'Permission:' ) self.cipher_name = self.sh.recvuntil(b"I'm a" )[:-6 ] self.cipher_name = self.cipher_name self.payload_cipher = xor(xor(self.cipher_name[:16 ], self._a_cat_permission), self._Princepermission) + self.cipher_name[16 :32 ] def solve_Princepermission (self ): self.sh.sendlineafter(b'[-]' , b'2' ) self.sh.sendlineafter(b'[-]' , self.payload_cipher[:16 ]) self.sh.sendlineafter(b'[-]' , self.iv) self.sh.recvuntil(b'The message is ' ) self.payload_iv = xor(xor(self.sh.recvuntil(b'1.getpermission' )[:16 ], self.iv), self._Princepermission) def solve_flag (self ): self.sh.sendlineafter(b'[-]' , self.payload_cipher) self.sh.sendlineafter(b'[-]' , self.payload_iv) self.sh.recvuntil(b'The prince asked me to tell you this:\n' ) flag = self.sh.recvline() print (flag) def solve (self ): self.proof_of_work() self.solve_BANNER(self._Princepermission) self.solve_NAME() self.solve_Princepermission() self.sh.sendlineafter(b'[-]' , b'3' ) self.solve_flag() if __name__ == '__main__' : solution = Solve() solution.solve()
好一个狸猫换太子
Re EasyRe 反编译失败,查了好久,尝试平衡栈,手动修无果,然后想起一开始看到一串32位的字符串没用到,随便搜了下竟然是hello world
的md5,抱着试一试的心态丢进去就对了