DASCTFxGFCTF2022 RSA
Analyze
from Crypto.Util.number import *
from secret import flag
def encrypt1(n):
n1 = hex(n>>200).encode()
n2 = str(hex(n))[20:].encode()
return n1,n2
def encrypt2(m , n_1):
c_1 = pow(m,e_1,n_1)
print('c_1 = '+str(c_1))
def encrypt3(m , n_2):
c_2 = pow( m , e_2 , n_2)
print('c_2 = '+str(c_2))
def encrypt4(m):
k = getPrime(512)
m = m % k
c_3 = pow(m, e_2, n_3)
print('c_3 = ' + str(c_3))
print('m = ' + str(m))
print('k = ' + str(k))
m1,m2 = encrypt1(flag)
m1 = bytes_to_long(m1)
m2 = bytes_to_long(m2)
print('n_2 = ' + str(n_2))
print('n_3 = ' + str(n_3))
print('e_1 = ' + str(e_1))
print('e_2 = ' + str(e_2))
encrypt2(m1,n_1)
encrypt3(n_1,n_2)
encrypt4(m2)
有四个encrypt函数,先看看这四个函数分别干了什么
- encrypt1:这里n1将参数取高200比特位再转为16进制,n2将取参数16进制的后20位,这里可能刚开始不知道函数干了个什么事情,可以自己找数据运行一下,可以猜测这个函数其实就是将flag分成了两半
- encrypt2:\(c_1 \equiv m ^ {e_1} \mod n_1\)
- encrypt3:\(c_2 \equiv m ^ {e_2} \mod n_2\)
- encrypt4:首先生成了一个512bit的素数,然后m对k取余,然后\(c_3 \equiv m ^ {e_2} \mod n_3\)
第二步,看一看数据
n_2 = 675835056744450121024004008337170937331109883435712066354955474563267257037603081555653829598886559337325172694278764741403348512872239277008719548968016702852609803016353158454788807563316656327979897318887566108985783153878668451688372252234938716250621575338314779485058267785731636967957494369458211599823364746908763588582489400785865427060804408606617016267936273888743392372620816053927031794575978032607311497491069242347165424963308662091557862342478844612402720375931726316909635118113432836702120449010
n_3 = 91294511667572917673898699346231897684542006136956966126836916292947639514392684487940336406038086150289315439796780158189004157494824987037667065310517044311794725172075653186677331434123198117797575528982908532086038107428540586044471407073066169603930082133459486076777574046803264038780927350142555712567
e_1 = 65537
e_2 = 3
c_1 = 47029848959680138397125259006172340325269302342762903311733700258745280761154948381409328053449580957972265859283407071931484707002138926840483316880087281153554181290481533
c_2 = 332431
c_3 = 11951299411967534922967467740790967733301092706094553308467975774492025797106594440070380723007894861454249455013202734019215071856834943490096156048504952328784989777263664832098681831398770963056616417301705739505187754236801407014715780468333977293887519001724078504320344074325196167699818117367329779609
m = 9530454742891231590945778054072843874837824815724564463369259282490619049557772650832818763768769359762168560563265763313176741847581931364
k = 8139616873420730499092246564709331937498029453340099806219977060224838957080870950877930756958455278369862703151353509623205172658012437573652818022676431
可以看到e_2=3,并且给了m,k
由e_2=3,可以联想到小明文攻击
encrypt3(n_1,n_2)
可以发现encryt3正是可以利用小明文攻击,得到n_1
for i in tqdm(range(200000000)):
if gmpy2.iroot(n_2 * i + c_2 , e_2)[1]:
n_1 = gmpy2.iroot(n_2 * i + c_2 , e_2)[0]
print(f"\nn_1={n_1}\n")
break
拿到n_1
n_1=70406706457855863712635967741447303613971473150228480705119773604469794649140239446237334040048504811343327173817296308781190911727763110615393368497803655390445303946160971
根据
encrypt2(m1,n_1)
现在拿到了n_1,就可以去尝试求m1了,也就是flag的前半段
n_1可以通过分解得到三个因子,那么就可以求得
n_1 = 70406706457855863712635967741447303613971473150228480705119773604469794649140239446237334040048504811343327173817296308781190911727763110615393368497803655390445303946160971
p_1 = 2224243981
q_1 = 2732337821
r_1 = 11585031296201346891716939633970482508158508580350404805965250133832632323150440185890235814142601827544669601048550999405490149435265122374459158586377571
phi_n_1 = (p_1 - 1) * (q_1 - 1) * (r_1 - 1)
d_1 = gmpy2.invert(e_1, phi_n_1)
m1 = pow(c_1 , d_1 , n_1)
print(libnum.n2s(m1))
flag1 = libnum.n2s(int(libnum.n2s(m1) , 16))
#0x666c61677b3230366538353964
得到一串十六进制数0x666c61677b3230366538353964
,即flag{206e859d
剩下encrypt4,由于
m = m % k
m,k题目已知,假设\(m = m2 + T \cdot k\),由
\(c = m ^ {e_2} \mod n_3\)
即\(c = (m2 + T \cdot k) ^ {e_2} \mod n_3\)
#sage
from Crypto.Util.number import *
m = 9530454742891231590945778054072843874837824815724564463369259282490619049557772650832818763768769359762168560563265763313176741847581931364
k = 8139616873420730499092246564709331937498029453340099806219977060224838957080870950877930756958455278369862703151353509623205172658012437573652818022676431
c_3 = 11951299411967534922967467740790967733301092706094553308467975774492025797106594440070380723007894861454249455013202734019215071856834943490096156048504952328784989777263664832098681831398770963056616417301705739505187754236801407014715780468333977293887519001724078504320344074325196167699818117367329779609
n_3 = 91294511667572917673898699346231897684542006136956966126836916292947639514392684487940336406038086150289315439796780158189004157494824987037667065310517044311794725172075653186677331434123198117797575528982908532086038107428540586044471407073066169603930082133459486076777574046803264038780927350142555712567
e = 3
R.<x> = PolynomialRing(Zmod(n_3))
g = (m + k * x) ** e - c_3
g = g.monic()
r = g.small_roots()[0]
flag = k * r + m
print(long_to_bytes(int(flag)))
得到一串十六进制383539643865383534633466363030636231323735376262663966357d
,发现和前半段flag的十六进制有重叠,故最后得到flagflag{206e859d8e854c4f600cb12757bbf9f5}
又水一篇wp XD