BUUCTF 每日打卡 2021-8-30
引言
马上开学了,摸了 打了DASCTF八月赛,比赛结束前1小时参赛,结果解题最多的题没做出来(啊这)
[DASCTF八月赛 2021]easymath
比赛的时候没做出来,后来Pheonix大佬告诉了我解法 给的代码很短:
1 2 3 assert (len (open ('flag.txt' , 'rb' ).read()) < 50 )assert (str (int .from_bytes(open ('flag.txt' , 'rb' ).read(), byteorder='big' ) << 10000 ).endswith( '1862790884563160582365888530869690397667546628710795031544304378154769559410473276482265448754388655981091313419549689169381115573539422545933044902527020209259938095466283008' ))
做到时候很疑惑,把给的数字转换成二进制也就五百多位,哪来左移10000位呢 也可以有这样的关系式:\(end = flag * 2^{10000}\space mod \space 10^{175}\) 其中175是给的结尾部分的十进制位数,模\(10^{175}\) 的目的是为了求\(2^{10000}\) 的逆元,得到flag 解密代码如下:
1 2 3 4 5 6 7 from Crypto.Util.number import *end = 1862790884563160582365888530869690397667546628710795031544304378154769559410473276482265448754388655981091313419549689169381115573539422545933044902527020209259938095466283008 t = inverse(2 **10000 , 10 **175 ) m = long_to_bytes(((end * t) % 10 **175 ) // GCD(2 **10000 , 10 **175 )) print (m)
结果为: 这里值得注意的是,如果用t = gmpy2.invert(2**10000, 10**175)
,则会报错: 那为什么用Crypto.Util.number
库的inverse
就行呢?还有,为什么要除GCD(2**10000, 10**175)
呢? 模逆元的定义中有这样一段话: 整数 a 对模数 n 之模逆元存在的充分必要条件是 a 和 n 互素 ,若此模逆元存在,在模数 n 下的除法可以用和对应模逆元的乘法来达成,此概念和实数除法的概念相同 本题中\(10^{175}\) 和\(2^{10000}\) 显然不互素,inverse
先分离出了GCD(2**10000, 10**175)
,才可以进行模逆元计算,因此最后要除GCD(2**10000, 10**175)
[DASCTF八月赛 2021]let's play with rsa~
加密代码如下:
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 from sympy import isprime,nextprimefrom Crypto.Util.number import getPrime as getprime ,long_to_bytes,bytes_to_long,inverseflag='flag{***************}' def play (): p=getprime(1024 ) q=getprime(1024 ) n=p*q e=65537 print "Hello,let's play rsa~\n" print 'Now,I make some numbers,wait a second\n' n1=getprime(200 ) n2=getprime(200 ) number=n1*n2 print "Ok,i will send two numbers to you,one of them was encoded.\n" print "Encode n1:%d,\n" %(pow (n1,e,n)) print "And n2:%d.\n" %n2 print "Information that can now be made public:the public key (n,e):(%d,%d)\n" %(n,e) while True : try : c=int (raw_input("ok,now,tell me the value of the number (encode it for safe):" )) except : print "Sorry,the input is illeagal, and the integer is accept~" else : break d=inverse(e,(p-1 )*(q-1 )) m=pow (c,d,n) if m==number: print "It's easy and interesting,didn't it?\n" print "This is the gift for you :" +flag else : print "Emmmmm,there is something wrong, bye~\n" if __name__ == '__main__' : play()
先随机生成了两个数n1,n2
,然后给了我们pow(n1,e,n)
和n2
,让我们传进去一个c
使得c
最后RSA解密后与n1*n2
相等 那直接把n2
加密之后和pow(n1,e,n)
相乘,传进去不就行了吗(啊这) 生成c
代码如下:
1 2 3 4 5 6 c1 = n2 = n = e = 65537 c2 = pow (n2, e, n) print (c1*c2 % n)
把结果传入即可
[DASCTF八月赛 2021]ezRSA
加密代码如下:
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 from secret import flagfrom Crypto.Util.number import *from random import getrandbitsfrom hashlib import sha256class EzRsa : def __init__ (self ): self.E = 0x10001 self.P = getPrime(1024 ) self.Q = getPrime(1024 ) while GCD((self.P-1 )*(self.Q-1 ), self.E) != 1 : self.Q = getPrime(1024 ) self.N = self.P*self.Q def encrypt (self ): f = getrandbits(32 ) c = pow (f, self.E, self.N) return (f, c) def encrypt_flag (self, flag ): f = bytes_to_long(flag) c = pow (f, self.E, self.N) return c def proof (): seed = getrandbits(32 ) print (seed) sha = sha256(str (seed).encode()).hexdigest() print (f"sha256({seed>>18 } ...).hexdigest() = {sha} " ) sha_i = input ("plz enter seed: " ) if sha256(sha_i.encode()).hexdigest() != sha: exit(0 ) if __name__ == "__main__" : proof() print ("welcome to EzRsa" ) print (""" 1. Get flag 2. Encrypt 3. Insert 4. Exit """ ) A = EzRsa() coin = 5 while coin > 0 : choose = input ("> " ) if choose == "1" : print ( f"pow(flag,e,n) = {A.encrypt_flag(flag)} \ne = 0x10001" ) exit(0 ) elif choose == "2" : f, c = A.encrypt() print (f"plain = {f} \ncipher = {c} " ) coin -= 1 elif choose == "3" : q = getrandbits(1024 ) n = A.P*q f = getrandbits(32 ) c = pow (f, 0x10001 , n) print (f"plain = {f} \ncipher = {c} " ) coin -= 1 elif choose == "4" : print ("bye~" ) else : print ("wrong input" ) print ("Now you get the flag right?" )
输入1,能得到加密后的flag和e 输入2,用EzRsa
中的公钥记为nt
,随机加密一个数,得到明文和密文 输入3,用EzRsa
中的p和一个随机生成的q生成新的公钥记为nk
,随机加密一个数,得到明文和密文 我们可以利用明文,e和密文得到公钥 由于有四次机会,可以得到一对nt
和一对nk
,由此得到输入2中的\(n1 = gcd(nt1, nt2)\) 和输入3中的\(n2 = gcd(nk1, nk2)\) ,由于n1
和n2
有公因子p,得到\(p = gcd(n1,n2)\) ,所以可以分解EzRsa
中的n,得到flag 至于proof()
部分,不知道为什么,他把seed
都print出来了,直接复制就行了 解密代码如下:
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 *import gmpy2ck1 = 10802736552802052334675431350693279487373514975583856720432908395157316583920875453552436496142443616668241018608905018877443641691597372943993746940796864088947110039691619330329829547914610310034042851600736815309651502714085552791205969637596625163884286216655679274373500381744546328590741571307166491219684988090657352142159038206188374695832891006030375956054657085966865212601720744964287594027579678929262839778089899170206998082556473498244863021611505400743727905185153354589976465321853027253539821633361185313034408565005594026376244077003811333923401071515437065293484027335646730805732706266190998912717 mk1 = 3467298486 ck2 = 7952426014817800345542743164212370465256522007694059040467262294139883798321376411423890059270181570060140439911489431487610048706425767050670076985945266595950167706634614499687295626618973683170430839755441335740665931270096392149318526814329218978695464692209823256428215580327499120933284877331428541567646264394511614834203230064225146095541013932153997347325545390454756521012184772766523934716861371813919366599810016530328522084402639154774851578047016291472426451432937369700785642186037817214135023341172743718729742706979406927034574357730393647164709577350234290575266246455335325036550238459460266826777 mk2 = 2637805758 ct1 = 5258297249437233269252734235581546483712740587856019368263741383010451771667214261941296958987255470129584667269164992391194597613632284942804492915958705615338348819026219002542835081068188830987745841778711674448286841103336689060336238552664704124260432965541782948103450178133013110447584887798935485919036836447185053522888046907188507552263118079180956315895262605349789171527309529542909346214121425645357866293754412692643751802750793196774012389022291591637648327944593680206557486483425679654293733112064106916782478544290625173885362276421903124336254498078544284381979906370583318057836106074195007704645 mt1 = 4018514725 ct2 = 2216710613849759291749271001172813296813995296942937937269459242162726262423838768504690540899513401365048563136110961705376280976325200801225641366994647978361247640072336671999168903599506081309580038964520354319361272932687736277969229054373565318758544270975463383927123441762751596885765477383664317818484566431143004646542531904764815747154445292706021915390615940095755639417784345435399786628193680479805174721200711052159068548732143161630778867220968156180570439298242013424813121308759181410582014316563549742660719169563010989100847264028027523510004333399915674385321042096844588069039993247180371045195 mt2 = 3768336235 e = 0x10001 c = 2409589959567577978959459059612176821685774169484662256361511224239193757207995235364470043362762616376254680228672727010474530311597231338182077689977346876997505890770280261284937438407769714519654847286916170373152881118623219276049395838329185415833388821874689670453791866822667341256546099953050403653918769534241514590069310425374668208283548693974017032984604264320169879760335946006653980827443567622501985484127746767154218399238266814865552396320059488020365523603371608242845046716068485196590482585388538864834136370002751749734914128047230447149334621639953462809629563555690666798206156581413136941807 nk1 = pow (mk1, e) - ck1 nk2 = pow (mk2, e) - ck2 n1 = gmpy2.gcd(nk1, nk2) print (n1)nt1 = pow (mt1, e) - ct1 nt2 = pow (mt2, e) - ct2 n2 = gmpy2.gcd(nt1, nt2) print (n2)p = gmpy2.gcd(n1, n2) print (p)print (gmpy2.is_prime(p))q = n1 // p print (q)print (gmpy2.is_prime(q))phi = (p-1 )*(q-1 ) d = inverse(e, phi) m = pow (c, d, p*q) print (long_to_bytes(m))
另外,发现Crypto.Util.number
中的GCD()
函数比gmpy2
的gcd()
计算较大数时慢很多
结语
希望继续坚持