题目
附件
拿到附件后一看,傻眼了,仔细看,分为四个部分,那就一步一步慢慢来。
第一步
给了多组n,c,虽然这里只显示了三行,但其实有四组,那应该是中国剩余定理,四组n,c求出来是m**4,需开四次方,根据已知的最后一行可知这里求的是p,上脚本
import binascii,gmpy2
from functools import reduce
import libnum
def CRT(mi, ai):
assert(reduce(gmpy2.gcd,mi)==1)
assert (isinstance(mi, list) and isinstance(ai, list))
M = reduce(lambda x, y: x * y, mi)
ai_ti_Mi = [a * (M // m) * gmpy2.invert(M // m, m) for (m, a) in zip(mi, ai)]
return reduce(lambda x, y: x + y, ai_ti_Mi) % M
e= 4 #xiao
n= []
c= []
m=gmpy2.iroot(CRT(n, c), e)[0]
print(m)
print(libnum.n2s(int(m)))
结果:
拿到p,继续。
第二步
看见ee2 = 3,一般情况下发现低指数幂,很有可能是突破口,这里还可以发现tmp的3次方与n大小相差不大
已知:
k*n+ce2 == (e2 + tmp)**3
可以爆破k,从而解出e2
import gmpy2
ee1 = 42
ee2 = 3
ce1 =
ce2 =
tmp =
n =
for k in range(42000):
if(gmpy2.iroot(k*n+ce2,3)[0]==int(gmpy2.iroot(k*n+ce2,3)[0])):
print(gmpy2.iroot(k*n+ce2,3)[0]-tmp)
一般来说e2不会太大,这里只需找到刚好从负值到正值的那个数就是e2
至于e1,仔细观察可以发现ce1的值与n的值相差了数十个数量级,从概率统计的意义上讲,如果比n小的每个数作为结果的可能相同,那么这种事情发生的概率非常小,但是还有一种可能就是,由于e1很小,e1的42次方都比n小,从而导致模n没起效果。
我们试着给ce1开42次方,果然直接得到一个差不多的整数,证实了猜想。
第三步
这里给出很常规的n,e,c,上RsaCtfTool解
结果:
不过这一步的作用似乎微乎其微。
第四步
这一步也是最难的,难就难在gcd(e,phi) != 1,一般来说遇到这种情况都是让e除去其与欧拉函数的最大公约数,让这两个数重新互质,然后求m**gcd(e,phi)的值。
这里我没办法了,只能看看大佬的 wp(由于时间紧,下面就贴过来了)
import gmpy2
from Crypto.Util.number import *
q1=
q2 =
c1 =
c2 =
e1=15218928658178
e2=381791429275130
p=
n = [ q1, q2]
a=gmpy2.gcd(e1,(p-1)*(q1-1))
b=gmpy2.gcd(e2,(p-1)*(q2-1))
#a,b相同
c = [ gmpy2.powmod(c1,gmpy2.invert(e1//a,(p-1)*(q1-1)),q1), gmpy2.powmod(c2,gmpy2.invert(e2//b,(p-1)*(q2-1)),q2)]
M=n[0]*n[1]
m=[0]*2
t=[0]*2
x=0
for i in range(2):
m[i]=M//n[i]
t[i]=gmpy2.invert(m[i],n[i])#t[i]是m[i]的模n[i]逆元
x+=(c[i]*t[i]*m[i])
x=x%M
print(x)
#x=
e=7
d=gmpy2.invert(e,(q1-1)*(q2-1))
flag=gmpy2.iroot(gmpy2.powmod(x,d,q1*q2),2)[0]
print(long_to_bytes(flag))
这个问题碰巧a=b=14,那么最后就求出来了m**14相关的两个式子,这个幂次还是有点高,不好处理。
这里就有很巧妙的一招可以把复杂度降下来:
两个式子其实可以用中国剩余定理求m**14,为了使求出来的数尽可能小我们采用:
m14 ☰a1 mod p
m14 ☰ a1 mod q1
m14 ☰ a2 mod p
m 14 ☰ a2 mod q2
然后用求出来的(m2)7%(q1q2)组成一个新的RSA解密,e=7,n=q1q2
但是用这个实际操作的时候就发现
那么可以直接用第二和第四两个式子求出x(m**2)
随后常规RSA解密后开方,即可得到flag
成功拿到flag!!!