corrupted_key
考点:RSA 已知cf+dq低位泄漏
题目
脚本
1 2 3 4 5 6 7 from Crypto.PublicKey import RSAfrom Crypto.Cipher import PKCS1_OAEPfrom secret import flagkey = RSA.generate(1024 ) open ("flag.enc" ,'wb' ).write(PKCS1_OAEP.new(key.publickey()).encrypt(flag))open ('priv.pem' ,'wb' ).write(key.exportKey('PEM' ))
corrupted key
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 -----BEGIN RSA PRIVATE KEY----- MIICXgIBAAKBgQDXFSUGqpzsBeUzXWtG9UkUB8MZn9UQkfH2Aw03YrngP0nJ3NwH UFTgzBSLl0tBhUvZO07haiqHbuYgBegO+Aa3qjtksb+bH6dz41PQzbn/l4Pd1fXm dJmtEPNh6TjQC4KmpMQqBTXF52cheY6GtFzUuNA7DX51wr6HZqHoQ73GQQIDAQAB yQvOzxy6szWFheigQdGxAkEA4wFss2CcHWQ8FnQ5w7k4uIH0I38khg07HLhaYm1c zUcmlk4PgnDWxN+ev+vMU45O5eGntzaO3lHsaukX9461mA== -----END RSA PRIVATE KEY-----
通过学习PEM文件格式,https://www.jianshu.com/p/c93a993f8997 ,可以获得模数、指数、低120的dq还有cf
我所能想到的是将下面这个等式模$q-1$,在这个多项式下用CopperSmith $$ ed=k\varphi+1 $$
但位数太大了,不行,或者说是模数不太对
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 from Crypto.Util.number import *c = 96458723724899437870554342796876171017896652413964521193266438981853945238446913579867464909353925601873532290626111170073532116639383463734148270579305067733147411306325252107181823453497914478588342362177625026365513002442585949837516090367171824895036711246039928723021679235071368954348296729327873680822 c1 = '' .join('''MIICXgIBAAKBgQDXFSUGqpzsBeUzXWtG9UkUB8MZn9UQkfH2Aw03YrngP0nJ3NwH UFTgzBSLl0tBhUvZO07haiqHbuYgBegO+Aa3qjtksb+bH6dz41PQzbn/l4Pd1fXm dJmtEPNh6TjQC4KmpMQqBTXF52cheY6GtFzUuNA7DX51wr6HZqHoQ73GQQIDAQAB''' .split('\n' ))c2 = '' .join('''yQvOzxy6szWFheigQdGxAkEA4wFss2CcHWQ8FnQ5w7k4uIH0I38khg07HLhaYm1c zUcmlk4PgnDWxN+ev+vMU45O5eGntzaO3lHsaukX9461mA==''' .split('\n' ))n = b'''\x00\xd7\x15%\x06\xaa\x9c\xec\x05\xe53]kF\xf5I\x14\x07\xc3\x19\x9f\xd5\x10\x91\xf1\xf6\x03\r7b\xb9\xe0?I\xc9\xdc\xdc\x07PT\xe0\xcc\x14\x8b\x97KA\x85K\xd9;N\xe1j*\x87n\xe6 \x05\xe8\x0e\xf8\x06\xb7\xaa;d\xb1\xbf\x9b\x1f\xa7s\xe3S\xd0\xcd\xb9\xff\x97\x83\xdd\xd5\xf5\xe6t\x99\xad\x10\xf3a\xe98\xd0\x0b\x82\xa6\xa4\xc4*\x055\xc5\xe7g!y\x8e\x86\xb4\\\xd4\xb8\xd0;\r~u\xc2\xbe\x87f\xa1\xe8C\xbd\xc6A''' n = bytes_to_long(n) e = 0x10001 cf = b'''\x00\xe3\x01l\xb3`\x9c\x1dd<\x16t9\xc3\xb98\xb8\x81\xf4#\x7f$\x86\r;\x1c\xb8Zbm\\\xcdG&\x96N\x0f\x82p\xd6\xc4\xdf\x9e\xbf\xeb\xccS\x8eN\xe5\xe1\xa7\xb76\x8e\xdeQ\xecj\xe9\x17\xf7\x8e\xb5\x98''' cf = bytes_to_long(cf) dp_bar = b'''\xc9\x0b\xce\xcf\x1c\xba\xb35\x85\x85\xe8\xa0A\xd1\xb1''' dp_bar = bytes_to_long(dp_bar) def coppersmith (k ): F.<x> = PolynomialRing(Zmod(n)) f = e * (x * 2 ^ 120 + dp_bar) + k - 1 f = f.monic() x0 = f.small_roots(X=2 ^392 ) return x0 from tqdm import tqdmfor k in tqdm(range (e, -1 , -1 )): x0 = coppersmith(k) if len (x0) != 0 : print (x0) break
解法一
泄漏$d$低位,再CopperSmith构造等式
别人的做法,首先根据$(1)$两边模$q-1$再化成等式可得 $$ ed_q=k(q-1)+1 $$ 爆破$k$可以求出低位的$q$
现在题目变成泄漏$q$的低120位,换做往常还是不能做,泄漏的位数太少了,但这里有$cf$,有一个比较变态的做法 $$ cf\cdot q^2-q\equiv 0\ (mod\ p)\notag $$ 看似上面这个模等于啥也没干,但是却可以用CopperSmith把$q$解出来,不知道为啥,但也是个新颖的思路
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 from Crypto.PublicKey import RSAfrom Crypto.Cipher import PKCS1_OAEPfrom Crypto.Util.number import *from gmpy2 import *from tqdm import tqdmn = 0xd7152506aa9cec05e5335d6b46f5491407c3199fd51091f1f6030d3762b9e03f49c9dcdc075054e0cc148b974b41854bd93b4ee16a2a876ee62005e80ef806b7aa3b64b1bf9b1fa773e353d0cdb9ff9783ddd5f5e67499ad10f361e938d00b82a6a4c42a0535c5e76721798e86b45cd4b8d03b0d7e75c2be8766a1e843bdc641 e = 0x10001 cf = 0xe3016cb3609c1d643c167439c3b938b881f4237f24860d3b1cb85a626d5ccd4726964e0f8270d6c4df9ebfebcc538e4ee5e1a7b7368ede51ec6ae917f78eb598 d_low = 0xc90bcecf1cbab3358585e8a041d1b1 q_low = [] for i in tqdm(range (1 , e, 2 )): try : q0 = invert(i, 2 ** 120 ) * (e * d_low + i - 1 ) % 2 ^ 120 q_low.append(q0) except : continue PR.<x> = Zmod(n)[] roots = [] for i in tqdm(range (len (q_low))): f = cf * (2 ^120 *x + int (q_low[i])) ^ 2 - (2 ^120 *x + int (q_low[i])) root = f.monic().small_roots(X = 2 ^(512 -120 )) if root: q = 2 ^120 *int (root[0 ]) + int (q_low[i]) p = n // q assert p * q == n d = inverse(e, (p - 1 ) * (q - 1 )) rsa = RSA.construct((int (n), int (e), int (d), int (p), int (q))) c = 96458723724899437870554342796876171017896652413964521193266438981853945238446913579867464909353925601873532290626111170073532116639383463734148270579305067733147411306325252107181823453497914478588342362177625026365513002442585949837516090367171824895036711246039928723021679235071368954348296729327873680822 c = long_to_bytes(c) print (PKCS1_OAEP.new(rsa).decrypt(c))
解法二
官方的正规解法:CopperSmith求出$dq$,再$dp$泄漏攻击
依旧是借助$(1)$,在化成$(2)$后将$kq$单独放到一边,得到 $$ ed_q+k-1=kq\notag $$ 已知$d_q$低位,$k$可以爆破,但是$q$不知道,不能构造一元CopperSmith。所以就想能不能把$q$给干掉,将其替换成已知低位的$kq$,于是就有 $$ cf\cdot q\equiv1\ (mod\ p)\rightarrow cf\cdot q-1\equiv0\ (mod\ p)\rightarrow cf\cdot (kq)^{x+1}-k\cdot (kq)^x\equiv0\ (mod\ n)\notag $$ 把$kq$代入上式可以,令$x=1$,就能得到一个模$n$等式,并且未知数个数为1,已知其低120位,设其高位为$x$,最终列出 $$ t = e\cdot (x+dp_l)-k+1\notag $$ $$ cf\cdot t^2-k\cdot t\equiv 0\ (mod\ n)\notag $$
用CopperSmith求解
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 from Crypto.Util.number import *from exploit.rsa.leakdpFracN import divide_pqfrom Crypto.PublicKey import RSAfrom Crypto.Cipher import PKCS1_OAEPc = 96458723724899437870554342796876171017896652413964521193266438981853945238446913579867464909353925601873532290626111170073532116639383463734148270579305067733147411306325252107181823453497914478588342362177625026365513002442585949837516090367171824895036711246039928723021679235071368954348296729327873680822 c1 = '' .join('''MIICXgIBAAKBgQDXFSUGqpzsBeUzXWtG9UkUB8MZn9UQkfH2Aw03YrngP0nJ3NwH UFTgzBSLl0tBhUvZO07haiqHbuYgBegO+Aa3qjtksb+bH6dz41PQzbn/l4Pd1fXm dJmtEPNh6TjQC4KmpMQqBTXF52cheY6GtFzUuNA7DX51wr6HZqHoQ73GQQIDAQAB''' .split('\n' ))c2 = '' .join('''yQvOzxy6szWFheigQdGxAkEA4wFss2CcHWQ8FnQ5w7k4uIH0I38khg07HLhaYm1c zUcmlk4PgnDWxN+ev+vMU45O5eGntzaO3lHsaukX9461mA==''' .split('\n' ))n = b'''\x00\xd7\x15%\x06\xaa\x9c\xec\x05\xe53]kF\xf5I\x14\x07\xc3\x19\x9f\xd5\x10\x91\xf1\xf6\x03\r7b\xb9\xe0?I\xc9\xdc\xdc\x07PT\xe0\xcc\x14\x8b\x97KA\x85K\xd9;N\xe1j*\x87n\xe6 \x05\xe8\x0e\xf8\x06\xb7\xaa;d\xb1\xbf\x9b\x1f\xa7s\xe3S\xd0\xcd\xb9\xff\x97\x83\xdd\xd5\xf5\xe6t\x99\xad\x10\xf3a\xe98\xd0\x0b\x82\xa6\xa4\xc4*\x055\xc5\xe7g!y\x8e\x86\xb4\\\xd4\xb8\xd0;\r~u\xc2\xbe\x87f\xa1\xe8C\xbd\xc6A''' n = bytes_to_long(n) e = 0x10001 cf = b'''\x00\xe3\x01l\xb3`\x9c\x1dd<\x16t9\xc3\xb98\xb8\x81\xf4#\x7f$\x86\r;\x1c\xb8Zbm\\\xcdG&\x96N\x0f\x82p\xd6\xc4\xdf\x9e\xbf\xeb\xccS\x8eN\xe5\xe1\xa7\xb76\x8e\xdeQ\xecj\xe9\x17\xf7\x8e\xb5\x98''' cf = bytes_to_long(cf) dq_bar = b'''\xc9\x0b\xce\xcf\x1c\xba\xb35\x85\x85\xe8\xa0A\xd1\xb1''' dq_bar = bytes_to_long(dq_bar) def coppersmith (k ): F.<x> = PolynomialRing(Zmod(n)) tmp = e * (x * 2 ^ 120 + dq_bar) + k - 1 f = cf * tmp ^ 2 - k * tmp f = f.monic() x0 = f.small_roots(X=2 ^392 ) return x0 from tqdm import tqdmfor k in tqdm(range (e, -1 , -1 )): x0 = coppersmith(k) if len (x0) != 0 : dq = int (x0[0 ] << 120 ) + dq_bar p, q = divide_pq(e, dq, n) d = inverse(e, n - p - q + 1 ) key = RSA.construct((int (n), int (e), int (d))) print (PKCS1_OAEP.new(key).decrypt(open ('flag.enc' , 'rb' ).read())) break
另外直接将PKCS1_OAEP写入文件的内容当成$c$是错的
RSA密钥文件格式 手撕PEM,小实验一下
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 from Crypto.PublicKey import RSAfrom base64 import *from Crypto.Util.number import long_to_byteskey = RSA.generate(1024 ) cont = key.exportKey('PEM' ) c = '' .join(''''MIICXAIBAAKBgQDKGq9TTDZq8d8bjHGBvBTLCv+VzlHp6dqSD8j6tOeidSjhBVvw BCIsHOeISc6A2xVlYh8RDtZwdNt5sYG4r2qExEybnKOSHIRdrAtQtlcMq+Igzz80 uAZ5rrv4GwP86B6KBcMLCQZw2iA9Ut5VO8bsEbx4+qbRklGSeiuD0V+jHQIDAQAB AoGAEVUD2ic8DM8yAgEjrtY8C5mlh5RfuVQLzDY8VyZygvUnN1JSqx0U99GBbae0 D6A6OoKVWszPSRT3HtLr5rRsdFAAH3JtkxOckD+pl6zYdWjxIrRxI3ZwQMapJV3P GEI4mt3foYcQewC9e7PmnQuaC7VLCuz75tCVwa8TV6boXWUCQQDc4laKq/IPfbS6 BtcFU0TlI8mBwJGoDLKt+5YB4c3nCYNEjb/8btO1b1i/ldl9qsgrCsXzOsPKg1mk XrTUCM/rAkEA6jwIUC+kfbM0nk5LdF4u7SWSJ+yJHmmXEwFGIhnQkSTzBoLMkuKd WIirD1gMYYUhq0OgxyFNVFQITYgeN9afFwJBALWFhB1eBQVaBwXBzT7hGYM9j8ID 4S+7j7OPR82wJagylx/lZdsrsOwv3z1DBoNRsEI/DkI/DtwEacy8z9pYi5UCQFKU QZYLheFvCZD6J23qOn8O7N04bgsTzNg9bb1d/oL9VNSpznfGfxSUckJhl1PWPM2F dSxfGEUvrxGueIDVIJcCQGUz3r6/0csCC06aQFZE/y1LvzfmZNEyrTY4pLq2QFif ZihZ0hFLIF7/8x/s4LH4u9TEJctvc46We31/wL4f1Sk=''' .split('\n' ))print (b64decode(c))n = 141922422162179017903127585740733292572168561849445377008084607260848440837899202013613994221251833956396740748218860865627125387303232010980772920302901970895962267669411141364137560651832837189240644578805960981842828200127571251887961801814486793715132007244098977233800900588064918877074282156319288828701 e = 0x10001 d = 12171007522857319381238253318351994781875551832519536046982694574694017938812266074388236449458713766466807278106098911329167549909820889661040390462523611239298122892357825060171192914736392814191400078975478302074496640294564924161354815518818393075514178864568095461878185396950184140746495040638346091877 p = 11568640743445096899087582701840791920416346538267286644696280445889201611816852678096203713970033443624441112801937495058400134469307102394543137970769899 q = 12267856294404649670607892358949867977588327036687686342888422897170960672423334427787576824476551036688316206161248780078052957870595041033189662792261399 dp = 9507054841699589984147260771102451611300236383386476709493145433185843422940202504492200430703237273703787928243385409903647015308115139856345336601152405 dq = 4325019754981452166553173824763670897694100983912431038229351527215695657969408760761584487076471484851054304337330867505430727552376496072018053295317143 cf = 5300411165607780716414732822919524340053628209205783274101215577479096542425160668007906344942502152526592241185925153869158983775649429578743583673931049 for i in [n, e, d, p, q, dp, dq, cf]: print (long_to_bytes(i))
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 0\x82\x02\\\x02\x01\x00\x02\x81\x81\x00 \xca\x1a\xafSL6j\xf1\xdf\x1b\x8cq\x81\xbc\x14\xcb\n\xff\x95\xceQ\xe9\xe9\xda\x92\x0f\xc8\xfa\xb4\xe7\xa2u(\xe1\x05[\xf0\x04",\x1c\xe7\x88I\xce\x80\xdb\x15eb\x1f\x11\x0e\xd6pt\xdby\xb1\x81\xb8\xafj\x84\xc4L\x9b\x9c\xa3\x92\x1c\x84]\xac\x0bP\xb6W\x0c\xab\xe2 \xcf?4\xb8\x06y\xae\xbb\xf8\x1b\x03\xfc\xe8\x1e\x8a\x05\xc3\x0b\t\x06p\xda =R\xdeU;\xc6\xec\x11\xbcx\xfa\xa6\xd1\x92Q\x92z+\x83\xd1_\xa3\x1d \x02\x03 \x01\x00\x01 \x02\x81\x80 \x11U\x03\xda\'<\x0c\xcf2\x02\x01#\xae\xd6<\x0b\x99\xa5\x87\x94_\xb9T\x0b\xcc6<W&r\x82\xf5\'7RR\xab\x1d\x14\xf7\xd1\x81m\xa7\xb4\x0f\xa0::\x82\x95Z\xcc\xcfI\x14\xf7\x1e\xd2\xeb\xe6\xb4ltP\x00\x1frm\x93\x13\x9c\x90?\xa9\x97\xac\xd8uh\xf1"\xb4q#vp@\xc6\xa9%]\xcf\x18B8\x9a\xdd\xdf\xa1\x87\x10{\x00\xbd{\xb3\xe6\x9d\x0b\x9a\x0b\xb5K\n\xec\xfb\xe6\xd0\x95\xc1\xaf\x13W\xa6\xe8]e \x02A\x00 \xdc\xe2V\x8a\xab\xf2\x0f}\xb4\xba\x06\xd7\x05SD\xe5#\xc9\x81\xc0\x91\xa8\x0c\xb2\xad\xfb\x96\x01\xe1\xcd\xe7\t\x83D\x8d\xbf\xfcn\xd3\xb5oX\xbf\x95\xd9}\xaa\xc8+\n\xc5\xf3:\xc3\xca\x83Y\xa4^\xb4\xd4\x08\xcf\xeb \x02A\x00 \xea<\x08P/\xa4}\xb34\x9eNKt^.\xed%\x92\'\xec\x89\x1ei\x97\x13\x01F"\x19\xd0\x91$\xf3\x06\x82\xcc\x92\xe2\x9dX\x88\xab\x0fX\x0ca\x85!\xabC\xa0\xc7!MTT\x08M\x88\x1e7\xd6\x9f\x17 \x02A\x00 \xb5\x85\x84\x1d^\x05\x05Z\x07\x05\xc1\xcd>\xe1\x19\x83=\x8f\xc2\x03\xe1/\xbb\x8f\xb3\x8fG\xcd\xb0%\xa82\x97\x1f\xe5e\xdb+\xb0\xec/\xdf=C\x06\x83Q\xb0B?\x0eB?\x0e\xdc\x04i\xcc\xbc\xcf\xdaX\x8b\x95 \x02@ R\x94A\x96\x0b\x85\xe1o\t\x90\xfa'm\xea:\x7f\x0e\xec\xdd8n\x0b\x13\xcc\xd8=m\xbd]\xfe\x82\xfdT\xd4\xa9\xcew\xc6\x7f\x14\x94rBa\x97S\xd6<\xcd\x85u,_\x18E/\xaf\x11\xaex\x80\xd5 \x97 \x02@ e3\xde\xbe\xbf\xd1\xcb\x02\x0bN\x9a@VD\xff-K\xbf7\xe6d\xd12\xad68\xa4\xba\xb6@X\x9ff(Y\xd2\x11K ^\xff\xf3\x1f\xec\xe0\xb1\xf8\xbb\xd4\xc4%\xcbos\x8e\x96{}\x7f\xc0\xbe\x1f\xd5)
Reference
官方wp
something else
RSA - Corrupted key 1
RSA - Corrupted key 2
RSA - Corrupted key 3
God Like RSA
Plaid CTF 2014
0CTF 2016 Quals – Equation
Corrupted Keys