复现了一下d3ctf里遇到的题
题目与解法
上题目代码
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 from Crypto.Util.number import bytes_to_long, getPrime from secret import msg from sympy import nextprime from gmpy2 import invert from hashlib import md5 flag = 'd3ctf{'+md5(msg).hexdigest()+'}' p = getPrime(256) q = getPrime(256) assert p > q n = p * q e = 0x10001 m = bytes_to_long(msg) c = pow(m, e, n) N = pow(p, 7) * q phi = pow(p, 6) * (p - 1) * (q - 1) d1 = getPrime(2000) d2 = nextprime(d1 + getPrime(1000)) e1 = invert(d1, phi) e2 = invert(d2, phi) print(f'c = {c}') print(f'N = {N}') print(f'e1 = {e1}') print(f'e2 = {e2}') ''' c = 2420624631315473673388732074340410215657378096737020976722603529598864338532404224879219059105950005655100728361198499550862405660043591919681568611707967 N = 1476751427633071977599571983301151063258376731102955975364111147037204614220376883752032253407881568290520059515340434632858734689439268479399482315506043425541162646523388437842149125178447800616137044219916586942207838674001004007237861470176454543718752182312318068466051713087927370670177514666860822341380494154077020472814706123209865769048722380888175401791873273850281384147394075054950169002165357490796510950852631287689747360436384163758289159710264469722036320819123313773301072777844457895388797742631541101152819089150281489897683508400098693808473542212963868834485233858128220055727804326451310080791 e1 = 425735006018518321920113858371691046233291394270779139216531379266829453665704656868245884309574741300746121946724344532456337490492263690989727904837374279175606623404025598533405400677329916633307585813849635071097268989906426771864410852556381279117588496262787146588414873723983855041415476840445850171457530977221981125006107741100779529209163446405585696682186452013669643507275620439492021019544922913941472624874102604249376990616323884331293660116156782891935217575308895791623826306100692059131945495084654854521834016181452508329430102813663713333608459898915361745215871305547069325129687311358338082029 e2 = 1004512650658647383814190582513307789549094672255033373245432814519573537648997991452158231923692387604945039180687417026069655569594454408690445879849410118502279459189421806132654131287284719070037134752526923855821229397612868419416851456578505341237256609343187666849045678291935806441844686439591365338539029504178066823886051731466788474438373839803448380498800384597878814991008672054436093542513518012957106825842251155935855375353004898840663429274565622024673235081082222394015174831078190299524112112571718817712276118850981261489528540025810396786605197437842655180663611669918785635193552649262904644919 '''
分析
1 2 3 4 5 6 7 8 flag = 'd3ctf{'+md5(msg).hexdigest()+'}' p = getPrime(256) q = getPrime(256) assert p > q n = p * q e = 0x10001 m = bytes_to_long(msg) c = pow(m, e, n)
普通的RSA加密,但n,p,q未知
1 2 3 4 5 6 N = pow(p, 7) * q phi = pow(p, 6) * (p - 1) * (q - 1) d1 = getPrime(2000) d2 = nextprime(d1 + getPrime(1000)) e1 = invert(d1, phi) e2 = invert(d2, phi)
这一段是将原来的n与phi都乘上了p6 ,然后生成了2000bits的质数d1与d2.从d2的生成代码可知,d1与d2的高位是相同的。之后通过求逆元的方式得到了e1,e2
解题
没见过的RSA变式加密很有可能在论文中找到。这道题就是如此,论文为:399.pdf (iacr.org)
在论文中可以找到一模一样的加密方式与攻击手段,但还是要验证攻击方式是否可用
题中给出的r=6,d1,d2为2000bits,N为2048bits。很容易得知
img
因此满足论文中所给出的攻击方法
接下来按照论文进行运算
img
用1式乘上e2减去2式乘上e1,得到
img
根据同余式的性质,因为phi=pr-1 (p-1)(q-1),所以上式等于
img
因此,在满足|d1-d2|<Ni (这里i=r(r-1)/(r+1)2 )的情况下,有如下式子
img
解出g有以下情况
img
照此思路就能得到p、q,从而得到flag。但难点在于x的计算存在困难。论文的示例中提到可以采用LLL算法来计算多项式方程的解,也可以用coppersmith攻击来求多项式的小根。使用sagemath可以很容易实现
解题代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 from Crypto.Util.number import * from hashlib import * import gmpy2 c=2420624631315473673388732074340410215657378096737020976722603529598864338532404224879219059105950005655100728361198499550862405660043591919681568611707967 N=1476751427633071977599571983301151063258376731102955975364111147037204614220376883752032253407881568290520059515340434632858734689439268479399482315506043425541162646523388437842149125178447800616137044219916586942207838674001004007237861470176454543718752182312318068466051713087927370670177514666860822341380494154077020472814706123209865769048722380888175401791873273850281384147394075054950169002165357490796510950852631287689747360436384163758289159710264469722036320819123313773301072777844457895388797742631541101152819089150281489897683508400098693808473542212963868834485233858128220055727804326451310080791 e1=425735006018518321920113858371691046233291394270779139216531379266829453665704656868245884309574741300746121946724344532456337490492263690989727904837374279175606623404025598533405400677329916633307585813849635071097268989906426771864410852556381279117588496262787146588414873723983855041415476840445850171457530977221981125006107741100779529209163446405585696682186452013669643507275620439492021019544922913941472624874102604249376990616323884331293660116156782891935217575308895791623826306100692059131945495084654854521834016181452508329430102813663713333608459898915361745215871305547069325129687311358338082029 e2=1004512650658647383814190582513307789549094672255033373245432814519573537648997991452158231923692387604945039180687417026069655569594454408690445879849410118502279459189421806132654131287284719070037134752526923855821229397612868419416851456578505341237256609343187666849045678291935806441844686439591365338539029504178066823886051731466788474438373839803448380498800384597878814991008672054436093542513518012957106825842251155935855375353004898840663429274565622024673235081082222394015174831078190299524112112571718817712276118850981261489528540025810396786605197437842655180663611669918785635193552649262904644919 e=0x10001 PR.<x> = PolynomialRing(Zmod(N)) f=e1*e2*x-(e1-e2) f=f.monic() k=f.small_roots(beta = 0.5, epsilon = 0.4, X = 2^1000)[0] #k=6026188071205144053368734157378113871998610498635758102306924949208539409278951959968138902906878320358536089190856063838203652085411343275918136041503018654914512075174785716697544493562866611023489700861401711316474669786472712436070391719434465362891545258455898553431580803183299730942414936305178 p7=gmpy2.gcd(e1*e2*k-(e1-e2),N) p=gmpy2.iroot(p7,6) #p=81911394167511996830305370213894554209992159667974516868378702592733037962549 q=N//p**7 #q=#59689394622751323780317475130818337618980301243859922297121750335804594909859 n=p*q phi=(p-1)*(q-1) d=gmpy2.invert(e,phi) m=long_to_bytes(gmpy2.powmod(c,d,n)) flag = 'd3ctf{'+md5(m).hexdigest()+'}' print(flag)
flag:d3ctf{42f79e777e622aef5344b04ad6233130}
总结
这是第一道复现的大赛题目,难度肯定是有的,复现的过程中也遇到了很多疑惑的地方,但最终还是复现出来了
参加d3也收获了许多经验,比如可以搜论文来解题,不要总想着硬啃
之后要干的事就是多看点书,多做点题,把数学知识补一补,学习一下LLL算法,small_root,coppersmith和sagemath