BUUCTF刷题Crypto篇
文章目录
前言
快一个月没刷buu的题了,我这就是……断断续续型/冲动型努力?
一、[GWCTF 2019]BabyRSA
1.分析题目已知
下载题目附件,压缩包中是一个py文件和一个文本文件。
具体内容如下:
显然,secret文件的内容就是encrypt.py文件的输出,也就是给了我们N(即p*q)和密文(分了成两段并偏偏用m1m2表示了而已)。
分析一下py文件,可知加密过程:
1)把待加密的flag平分成两段等长的部分;
2)随机生成一个1024bit长度的素数,再将这个素数与一个未知数相乘,得到一个值;
3)选取这个值的下一个素数作为p;
选取p的下一个素数作为q;
4)N=p*q,e是65537,分别将两段明文转换成整数相加的结果和两段明文转成整数后分别取三次方再相加的结果用公钥加密。
此处完全不用去纠结2)到底得到了啥!
重要的是,根据3)可以知道p、q是两个相邻的素数,就是说p和q的值是非常接近的!
N已知,直接对N开二次方根得到的值(用pt表示),应该是大于p而小于q的,所以我就直接猜测一波位于pt之后的第一个素数(用qt表示)就是我们想要求的q,如果N可以整除qt,且N除以qt的得到的商也是素数,那么商就是p,qt就是q。
p和q一旦求出,e又是已知的,后面就顺理成章能求出私钥d,然后拿着私钥d去解密密文m1和m2,得到c1和c2。
只是这道题还有个对明文的处理,那就根据4)中分析的处理过程,在c1和c2已知的条件下解二元三次方程组得到F1和F2就好了。
2.解题Python脚本
from Crypto.Util.number import *
import gmpy2
from sympy import *
N=636585149594574746909030160182690866222909256464847291783000651837227921337237899651287943597773270944384034858925295744880727101606841413640006527614873110651410155893776548737823152943797884729130149758279127430044739254000426610922834573094957082589539445610828279428814524313491262061930512829074466232633130599104490893572093943832740301809630847541592548921200288222432789208650949937638303429456468889100192613859073752923812454212239908948930178355331390933536771065791817643978763045030833712326162883810638120029378337092938662174119747687899484603628344079493556601422498405360731958162719296160584042671057160241284852522913676264596201906163
pt=gmpy2.iroot(N,2)[0]
qt=nextprime(pt) #nextprime()在sympy模块哦
if N%qt==0:
if isPrime(N//qt):
p=N//qt #p=797862863902421984951231350430312260517773269684958456342860983236184129602390919026048496119757187702076499551310794177917920137646835888862706126924088411570997141257159563952725882214181185531209186972351469946269508511312863779123205322378452194261217016552527754513215520329499967108196968833163329724620251096080377747699
q=qt #q=797862863902421984951231350430312260517773269684958456342860983236184129602390919026048496119757187702076499551310794177917920137646835888862706126924088411570997141257159563952725882214181185531209186972351469946269508511312863779123205322378452194261217016552527754513215520329499967108196968833163329724620251096080377748737
phi=(p-1)*(q-1)
e=65537
d=gmpy2.invert(e,phi)
m1=90009974341452243216986938028371257528604943208941176518717463554774967878152694586469377765296113165659498726012712288670458884373971419842750929287658640266219686646956929872115782173093979742958745121671928568709468526098715927189829600497283118051641107305128852697032053368115181216069626606165503465125725204875578701237789292966211824002761481815276666236869005129138862782476859103086726091860497614883282949955023222414333243193268564781621699870412557822404381213804026685831221430728290755597819259339616650158674713248841654338515199405532003173732520457813901170264713085107077001478083341339002069870585378257051150217511755761491021553239
m2=487443985757405173426628188375657117604235507936967522993257972108872283698305238454465723214226871414276788912058186197039821242912736742824080627680971802511206914394672159240206910735850651999316100014691067295708138639363203596244693995562780286637116394738250774129759021080197323724805414668042318806010652814405078769738548913675466181551005527065309515364950610137206393257148357659666687091662749848560225453826362271704292692847596339533229088038820532086109421158575841077601268713175097874083536249006018948789413238783922845633494023608865256071962856581229890043896939025613600564283391329331452199062858930374565991634191495137939574539546
c1=pow(m1,d,N)
c2=pow(m2,d,N)
'''通过解方程组求出flag的前后两部分,sympy模块里提供了解方程组的函数'''
x=symbols('x')
y=symbols('y')
[X1,X2]=solve([x+y-c1,x**3+y**3-c2],[x,y])
'''因为这里x,y明显是可以交换取值的,即Python求解出的结果是两组解,X1(x1,y1)和X2(x2,y2),且有x1=y2,x2=y1,将整数转换成字节码后,就清楚了两个值谁在前谁在后'''
#print(X1,X2)
print(long_to_bytes(X1[0]))
print(long_to_bytes(X1[1]))
'''这么写的话刚好反了,输出后就会发现实际F1是X1[1],F2是X1[0],但无妨,提交flag时拼接一下即可'''
程序输出:
flag{f709e0e2cfe7e530ca8972959a1033b2}
二、[ACTF新生赛2020]crypto-rsa3
1.分析题目已知
题目压缩包中是一个py文件和一个文本文件,同上面一题一样。其实仔细一看思路也一样而且更简单♪(^∇^*)
具体内容如下:
可以看出,又是p、q是相邻素数的情况,两者很接近,就去开根号n。文本文件中放的就是py文件最后输出的n和c的值。e也已知,有手就行直接写脚本拿到flag。
2.解题Python脚本
from Crypto.Util.number import *
import gmpy2
from sympy import *
n=177606504836499246970959030226871608885969321778211051080524634084516973331441644993898029573612290095853069264036530459253652875586267946877831055147546910227100566496658148381834683037366134553848011903251252726474047661274223137727688689535823533046778793131902143444408735610821167838717488859902242863683
c=1457390378511382354771000540945361168984775052693073641682375071407490851289703070905749525830483035988737117653971428424612332020925926617395558868160380601912498299922825914229510166957910451841730028919883807634489834128830801407228447221775264711349928156290102782374379406719292116047581560530382210049
pt=gmpy2.iroot(n,2)[0]
qt=nextprime(pt)
if n%qt==0:
if isPrime(n//qt):
p=n//qt
q=qt
phi=(p-1)*(q-1)
e=65537
d=gmpy2.invert(e,phi)
m=pow(c,d,n)
print(long_to_bytes(m))
运行输出:
flag{p_and_q_should_not_be_so_close_in_value}
三、SameMod
1.分析题目已知
仅有一个txt文件,很明显给出的两组数据中有同样的n和不同的e,然后对应两个不同的密文。结合题目叫samemod,那肯定是考察共模攻击咯。
2.解题Python脚本
之前做共模题留的脚本解这道题不对,而且这道题在最后将整数转换成字节码时不能直接long_to_bytes,而是要注意三位数和两位数分开去对应字符的ASCII码。看到了别人的代码才知道自己错在哪。
代码参考自:http://t.csdn.cn/LWni4
import gmpy2
from Crypto.Util.number import *
e1=773
e2=839
n=6266565720726907265997241358331585417095726146341989755538017122981360742813498401533594757088796536341941659691259323065631249
c1=3453520592723443935451151545245025864232388871721682326408915024349804062041976702364728660682912396903968193981131553111537349
c2=5672818026816293344070119332536629619457163570036305296869053532293105379690793386019065754465292867769521736414170803238309535
def egcd(a,b):
if b==0:
return a,0
else:
x,y=egcd(b,a%b)
return y,x-a//b*y
s1=egcd(e1,e2)[0]
s2=egcd(e1,e2)[1]
if(s1<0):
s1=-s1
c1=gmpy2.invert(c1,n)
if(s2<0):
s2=-s2
c2=gmpy2.invert(c2,n)
m=pow(c1,s1,n)*pow(c2,s2,n)%n
print(m)
m=str(m)
flag=''
i=0
while i < len(m):
if m[i]=='1':
flag+=chr(int(m[i:i+3]))
i+=3
else:
flag+=chr(int(m[i:i+2]))
i+=2
print(flag)
脚本运行结果:
这里先输出了解密后得到的“long”,而之前自己存的共模脚本得到的都不是这个数,具体还没研究怎么回事,因为之前也不懂共模的脚本是按什么原理写的……
flag{whenwethinkitispossible}
总结
刷题,哪怕不是很细地去刷题,也是非常必要的!
因为一个月前不会的题型今天才刷到,现在觉得是很简单了,可是当时想了很久没想到在已知p、q接近的情况下可以对n开根号再确定p和q的思路。
其实中间也想到过,但是因为不够自信所以没有去尝试,白白搭了很多思考时间还很焦虑,觉得自己天赋上比别人差了太多,其实可能是别人刷题进度领先所以看到就会,自己也可以去勤能补拙不是吗?