[NSSRound#11

Toretto·2024-01-14 04:49·60 次阅读

[NSSRound#11

ez_enc https://www.nssctf.cn/problem/3624

打开附件,看到一堆A和B

并且题目有提示说并不是培根密码,虽然看着确实像培根密码

看着也确实不是密文。转念一想可能是摩斯电码,毕竟只有A和B,但是试了一下感觉不行。因为没有间隔符号。那只有一个可能了,是2进制。
试试A=0,B=1。总字符数192,正是8的倍数,这或许说明我们走对了
进入Pycharm试一下

很幸运,我猜对了


MyMessage https://www.nssctf.cn/problem/3626

附件看到是个RSA加密代码

Copy
import os flag = os.getenv('FLAG') e = 127 def sign(): msg = input("Input message:") p = getPrime(512) q = getPrime(512) n = p*q c = pow(bytes_to_long((msg + flag).encode()), e, n) print(f"n: {n}") print(f"Token: {hex(c)}") def main(): while True: sign() main()

很明显是一个低加密指数广播攻击,虽然127次方看上去还是很大,但是相比常用的65537还是小得多。我们尝试使用Hestad广播攻击
前提是多组不同n d c 相同的m e。根据多组结果使用中国剩余定理即可。
如果一个用户使用同一个加密指数 e 加密了同一个密文,并发送给了其他 e 个用户。那么就会产生广播攻击。这一攻击由 Håstad 提出。

使用不同的模数 n,相同的公钥指数 e加密相同的信息,就会得到多个 m^e≡ci(modni),
将 m^e 视为一个整体 M这就是典型的中国剩余定理适用情况。容易求得 me的值,当e较小时直接开 e方即可,可使用gmpy2.iroot(M,e) 方法。
更一般情况(k组数据的 N不同)见15。
sage中的中国剩余定理

Copy
Sum = 0 prod = reduce(lambda a, b: a*b, modulus) for m_i, r_i in zip(modulus, remainders): p = prod // m_i Sum += r_i * (inverse_mod(p,m_i)*p) return Sum % prod chinese_remainder([3,5,7],[2,3,2]) #23

另一种方法
sage
crt([2,3,2],[3,5,7])

由于这里是需要一个交互的过程,所以我们需要编写一个EXP来解决


其实这里还有别的做法,因为每次生成p和q都是随机的,都是512位的质数。可以多次执行脚本让它p发生碰撞,也就产生了模不互素从而直接分解n,获取p和q
当然512位的质数还是比较多的,而且e并不是一个素数,不一定很容易解出m,所以这一招比较看运气。


MyGame https://www.nssctf.cn/problem/3627

打开又是一个RSA,看到程序后和上一题一样是个交互题目

Copy
from Crypto.Util.number import * import os import random import string flag = os.getenv('FLAG') def menu(): print('''=---menu---= 1. Guess 2. Encrypt ''') p = getPrime(512) q = getPrime(512) n = p*q def randommsg(): return ''.join(random.choices(string.ascii_lowercase+string.digits, k=30)) mymsg = randommsg() def guess(): global mymsg msg = input() if msg == mymsg: print(flag) else: print(mymsg) mymsg = randommsg() def encrypt(): e = random.getrandbits(8) c = pow(bytes_to_long(mymsg.encode()), e, n) print(f'Cipher_{e}: {c}') def main(): print(f'n: {n}') while True: opt = int(input()) if opt == 1: guess() elif opt == 2: encrypt() main()

这里我们可以一直加密,用不同的e加密,直到有两个互素的e加密后就可以利用欧几里得扩展得到m%n了,又因为msg是个240位的,远小于n。所以就直接得到msg了
由于书都比较小,不用编写脚本,可以直接访问得到数据。但我试了试环境好像访问不到。还是写脚本吧

Copy
from pwn import * import re import binascii, gmpy2 from functools import reduce import libnum from Crypto.Util.number import * host = 'node4.anna.nssctf.cn' port = 28676 conn = remote(host, port) data1 = conn.recvline().decode() n = int(re.findall(r'n: (\d+)', data1)[0]) def interact_with_server(conn): conn.sendline("2") data1 = conn.recvline().decode() print(data1) e, c = re.findall(r'Cipher_(\d+): (\d+)', data1)[0] e = int(e) c = int(c) return e, c # ------------ 共模攻击 ------------ def attack(): e1, c1 = interact_with_server(conn) e2, c2 = interact_with_server(conn) g, x, y = gmpy2.gcdext(e1, e2) m = pow(c1, x, n) * pow(c2, y, n) % n return long_to_bytes(m) def get_flag(): m = attack() print(m) conn.sendline("1") conn.sendline(m) return conn.recvline().decode() while True: flag = get_flag() if "NSS" in flag: print(flag) break


ez_signin https://www.nssctf.cn/problem/3623

这一题看到加密代码很少

Copy
from Crypto.Util.number import * from secret import flag p = getPrime(512) q = getPrime(512) assert p > q n = p*q e = 65536 m = bytes_to_long(flag) num1 = (pow(p,e,n)-pow(q,e,n)) % n num2 = pow(p-q,e,n) c = pow(m,e,n) print("num1=",num1) print("num2=",num2) print("n=",n) print("c=",c)

检测后发现很容易可以从num1和num2中分解得到p和q
因为num1+num2一定是p的倍数,而且n又是p的倍数。所以直接最大公因数就行
但是奇怪的是e是65536,一般应该是65535。那么显然是不存在d的,因为偶数是找不到模逆的
这时候想到rabin加密了,虽然不是2但是2的16次方,完全可以循环16次rabin加密就行。不管这样结出来的明文的可能性是4的16次方.
我们得列出列表,来收集这些明文,最后依次检测是不是flag

Copy
import gmpy2 from Crypto.Util.number import * num1= 110685964869038101380235652027332015958128603350413727850893655074368015284650791635258308680430215918731273586597361623512140204478590179690715372189514914340429601741942658984761614051105581961057775714201491328480827905421164422497527363441161446242624509435260517986434745759253101095141745550414521468822 num2= 63210351635781847372830700485007297377375775643156487235778801368498975531484913995621874442482895778739619063486655962272514693032490561929843297015425751778424820425910582853550610526159134582792699019283641445537238096156294242292540150449544782194998266119692364633769463988092183790013663712200415681420 n= 114499042279482676425219257260918090608522636999564178196754449111573549596657067426783034754940837036863724460716934023705920707856624611455651699771653145888404986479719922661857103143545446099698742014947716777100998012665461174689284009186486218411925840300139349848651509685998745685826881267614627082033 c= 11724126358580594223781319253174116746050646551575036388394126758617650640905746475340310937290390189297334156991771783558736717485534028986618312699472130756539423815384967603854038723029702581333047836952993300386844875547551490117849525861450759893085799319974128416211487436945325017668136630738374326122 e=65536 p=gmpy2.gcd(n,(num1+num2)%n) q=n//p cs=[c] def rabin(c,p,q): mp = pow(c, (p + 1) // 4, p) mq = pow(c, (q + 1) // 4, q) yp = inverse(p,q) yq = inverse(q,p) r = (yp * p * mq + yq * q * mp) % n r_ = n - r s = (yp * p * mq - yq * q * mp) % n s_ = n - s return r,r_,s,s_ for i in range(16): ps = [] for c2 in cs: r,r_,s,s_ = rabin(c2,p,q) if r not in ps: ps.append(r) if r_ not in ps: ps.append(r_) if s not in ps: ps.append(s) if s_ not in ps: ps.append(s_) # print(ps) cs = ps for i in range(len(cs)): result=long_to_bytes(cs[i]) if b"NSSCTF" in result: print(result)

最后也是成功获取flag


ez_fac https://www.nssctf.cn/problem/3622

image
再从源码中可以看到a0,a1,b0,b1都是特定设计好的数字,拿到后我们可以看看长度
image
image
首先大致算了一下,a0,a1都是512位,而b0,b1只有406/407位,这样就说明e和b的平方乘积相比a的平方小得多。那么大致可以知道a0,a1和p,q的公因数差距不大。开始想从a0,a1直接爆破出p和q。但是失败了,确实512位质数还是太多了,p和q之间距离还是很大的

Copy
from gmpy2 import * from Crypto.Util.number import * from sympy import * c= 9720283929719601703720008779197503559402739477763957201141946610105329811871505829125672263176597338889316455047157317596759022420905670592061367780914195007303951628004544805510914555042066582216382514914696778670095828231349003026058020585490828168190809232814960086781574147790920080422550532400703998155 n= 67459379864091010179271920792489582731235533723909717315375622327987843142831939840025514452751600383312764125946633184064078453148057079732916054519655889016557885840577145455336901990579679382642836729589461108672259719605619276464762810082080140318021418614340400805782958042491334351690713829160811856163 a0= 8213365927808830445867562574661770383034147875691144429967734275073175584647628179765422915830721680687760244911700195720957426828362263237784939307191476 a1= 8213365927808830445867562508017792850396351421957931575960454954877777106261017240301197904738558557985011272118611159718454142038027294464112105379369524 b0= 70619405839477281187724234968115650918360209963699988281299808297679478776371706541285253302764483389205021664611868399109 b1= 95986820469722612222755549468800659456753452569775903037389099807153418503214360388001934584727945583869225348204785755141 e=(n-pow(a0,2))//pow(b0,2) print(e) p=a0 while true: p=nextprime(p) if(n%p==0): print("p:"+str(p))

之后想了想也只能去分解n了,毕竟没有其他任何提示。只能从给定的两个等式来分解n了
那么怎么分解呢?要想从等式去分解n,只有将n放在左边,右边是一个乘积形式。这样右边的式子中一定得有p和q倍数才行,那就可以使用欧几里得算法得到最小公因数获取p,q了
原本给定两个等式n右边都是加法,显然不行。得想办法去除一个,可以分别对n乘b0平方和b1平方再减法消去

Copy
import gmpy2 from Crypto.Util.number import * c= 9720283929719601703720008779197503559402739477763957201141946610105329811871505829125672263176597338889316455047157317596759022420905670592061367780914195007303951628004544805510914555042066582216382514914696778670095828231349003026058020585490828168190809232814960086781574147790920080422550532400703998155 n= 67459379864091010179271920792489582731235533723909717315375622327987843142831939840025514452751600383312764125946633184064078453148057079732916054519655889016557885840577145455336901990579679382642836729589461108672259719605619276464762810082080140318021418614340400805782958042491334351690713829160811856163 a0= 8213365927808830445867562574661770383034147875691144429967734275073175584647628179765422915830721680687760244911700195720957426828362263237784939307191476 a1= 8213365927808830445867562508017792850396351421957931575960454954877777106261017240301197904738558557985011272118611159718454142038027294464112105379369524 b0= 70619405839477281187724234968115650918360209963699988281299808297679478776371706541285253302764483389205021664611868399109 b1= 95986820469722612222755549468800659456753452569775903037389099807153418503214360388001934584727945583869225348204785755141 e=(n-pow(a0,2))//pow(b0,2) #n(b1^2-b0^2)===(b1^2*a0^2)-(b0^2*a1^2) #n(b1^2-b0^2)===(b1*a0+b0*a1)*(b1*a0-b0*a1) #n(b0^2-b1^2)===(b0^2*a1^2)-(b1^2*a0^2) #n(b0^2-b1^2)===(b0*a1+b1*a0)*(b0*a1-b1*a0) p=gmpy2.gcd(n,(b0*a1-b1*a0)) q=n//p phi = (p-1)*(q-1) d=gmpy2.invert(e,phi) print(long_to_bytes(pow(c,d,n)))

image

posted @   Erebussss  阅读(60)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示