第七届蓝帽杯全国大学生网络安全技能大赛
我只是赛后看看题而已^^
初赛-DHRSA
第一部分利用n1ctf2022的背包格和ph算法求参数,第二部分参考论文里的backdoor进行分解。
s=
'''
'''
from Crypto.Util.number import *
s=eval('['+s.replace('[+] Try ','').replace('\n',',')+']')
M=Matrix(ZZ,62,63)
cc=[s[i][0] for i in range(62)]
C=[s[i][1] for i in range(62)]
for i in range(62):
M[i,0]=cc[i]<<40
M[i,i+1]=1
res=M.LLL()
r1=res[0][1:]
r2=res[1][1:]
xx = product([ZZ(y) ^ x for x, y in zip(r1, C)])
yy = product([ZZ(y) ^ x for x, y in zip(r2, C)])
r = gcd(xx.numer() - xx.denom(), yy.numer() - yy.denom())
X=197551296081022143608034360606381334253374533627365455002683616928330857539205836504075700389569213696043700490195977045586318090211726350917451410932216
W=10625560347436147537644301075885059900758953251551866239435327407977591190018531918316486861730777808988185029637608372445416280896280058313924537678128258
x = 10661668070998584360419309727765572397096868781636098095295487404295848193280503932533547717105939587559768619286290065762620186259047850096911244235337628
w = 4906271112282365731782355718975954883681410512144653038967637004076216581811845789271674832502423740658483643339407781551392926100321199924692149941796591
c = 61040814411609979711931510878805548760848686739454567580358315369154260598969544907138563610735920809370306294050956464828615417082277087799410050319871691154003766481799397897519555113273982347768485719165972634089532894585256662433949694618032747408071953491187718726218120284389638124624152241321006634774
n = 66022752859576751705544115674843820574619778139841743306742674741819040147745776264697779394213058328572691946505564202779552568613562176486470653760142864852745249430164256770469301179840812051842363261404790355057115296671805975126795017665392798621718740402876024901551851638786170466127104615340863081593
# discrete_log(G(n%r),G(g))
r=10667924450645948100608927157603781268991945924055943816082403476371801785989561454936076097627912279097114498936308342036099904242687703932444772733243819
G=GF(r)
g=6019887080267290264230260653584196278384320835640816590398803560025633855808434001764263669714920086295176455397726166743099512294951861972283858355052731
assert ZZ(pow(g,w,r))==W
assert ZZ(pow(g,x,r))==X
# extension://bfdogplmndidlpjfhoijckpakkdjkkil/pdf/viewer.html?file=http%3A%2F%2Fmyweb.scu.edu.tw%2F~mn%2Fpaper%2FA%2520Comprehensive%2520Study%2520of%2520Backdoors%2520for%2520RSA%2520Key%2520Generation.pdf
p = ZZ(pow(n * pow(g,w,r),(x+1),r))
print(p)
q=n//p
print(q)
print(p*q)
print(p*q == n)
d=inverse(65537,(p-1)*(q-1))
long_to_bytes(ZZ(pow(c,d,n)))
# b'god, you hack my backdoor!!! flag{a_trivial_r5a_bbbbbbackd00r_***712***_c3nt5}'
半决赛-ezrsa
根据给的分数结合n=pq
可以化简得到:$$\small \frac{p-q+1}{n+q} = \frac{-X-2Y}{S+Y}$$
因此有\(\small p-q+1=k(-X-2Y)\),k为1即可。
x = 153801856029563198525204130558738800846256680799373350925981555360388985602786501362501554433635610131437376183630577217917787342621398264625389914280509
y = 8086061902465799210233863613232941060876437002894022994953293934963170056653232109405937694010696299303888742108631749969054117542816358078039478109426
n = 161010103536746712075112156042553283066813155993777943981946663919051986586388748662616958741697621238654724628406094469789970509959159343108847331259823125490271091357244742345403096394500947202321339572876147277506789731024810289354756781901338337411136794489136638411531539112369520980466458615878975406339
c = 15380535750650959213679345560658190067564859611922563753882617419201718847747207949211621591882732604480600745000879508274349808435529637573773711729853565120321608048340424321537282281161623712479117497156437792084977778826238039385697230676340978078264209760724043776058017336241110097549146883806481148999
from Crypto.Util.number import *
p,q = var('p','q')
solve([p*q == n, p-q == -x-2*y-1], p, q)
p = 12604273285023995463340817959574344558787108098986028639834181397979984443923512555395852711753996829630650627741178073792454428457548575860120924352450409
q = n//p
phi = (p-1)*(q-1)
d = inverse_mod(65537,phi)
print(long_to_bytes(ZZ(pow(c,d,n))))
半决赛-Dual ECDSA
看题目名就知道是Dual EC,然后迅速找到了去年的nepctf-badkey,先看看去年这题,了解一下这个后门的基本原理。实际上这个伪随机生成数的原理很容易理解,基本看图都能懂:
nep这题的adin固定是0,就相当于直接没有异或了,并且r的取值方式也没有像论文里丢掉一些比特,后面 do_schnorr_identification
一堆代码的唯一作用就是告诉我们加密flag的key是r2,因此利用后门恢复一轮的递推就好了。
p = 115792089210356248762697446949407573530086143415290314195533631308867097853951
n = 115792089210356248762697446949407573529996955224135760342422259061068512044369
b = 0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b
E= EllipticCurve(GF(p), [-3,b])
d = 66604141534275704476445937214374130642068729921454877238730830814793201802544
Q = E(48439561293906451759052585252797914202762949526041747995844080717082404635286 , 36134250956749795798585127919587881956611106672985015071877198253568414405109)
r1 = 59100197418944667413449341413044666843726352095054393072750502893110293231642
ct = 25645992443585671366815910836517434170297823176311632150463962979581372384075859802765045877741181123347569267185176
P=d*Q
def do_next(s):
sP = s * P
r = Integer(sP[0])
s_new = Integer((r * P)[0])
rQ = r * Q
return Integer(rQ[0]), s_new
def do_guess(r1):
try:
rQ1 = E.lift_x(r1)
except ValueError:
return None
sP2 = d * rQ1
s2 = Integer(sP2[0])
r2, s3 = do_next(s2)
return r2, s3
r2,s3=do_guess(r1)
print(r2>>(128))
from Crypto.Cipher import AES
from Crypto.Util.number import *
def encrypt_flag(c,key):
cipher = AES.new(key, AES.MODE_ECB)
ct = cipher.decrypt(c)
return ct
ct = long_to_bytes(25645992443585671366815910836517434170297823176311632150463962979581372384075859802765045877741181123347569267185176)
key=long_to_bytes(127452153710767463567686578700133367453)
print(encrypt_flag(ct,key))
蓝帽杯这题在套用基础的Dual EC的同时需要先用LLL去恢复dsa的私钥,然后利用基于中间相遇的bsgs去爆破一下私钥n,因为是按照论文实现的后门所以随机数有损失16比特,所以还得再爆破一部分,具体过程有师傅写的很详细我就只贴个exp了。
from hashlib import sha256
from tqdm import tqdm
from Crypto.Util.number import *
pub_key = (1284057549640164959065310299974715949780883842543987295579845101714329490371866414620403984059688256268916840753322634228189993387677187086805910608913877240, 2871828286437266324077547225563521746454811466060839307814808187038977339931268294634407454097422974392263009902452840007777204947601588882408605940896033213)
P = (44709432769601533647164055172337077577197388971405441067408648552120273899439, 5146142757398992761089276624845497246953677849813524410717292563307277646248)
Q = (79560279623532866071675257110279687192436171302512534366260446974055296569775, 26859165885861631636190724510665269671005299628857498631278393159264950495322)
r1, s1 = (5089140070991418866765317340224488883853896999535207637664248575094162436344850602488004304731596114325990969313189073305315747359692187240695087335320008392, 2992276069467527712690275343211346442634209004250088074729707123246604474164141954635893526085370984681060737605953014207436859072640690696867665537702633916)
r2, s2 = (2872033002190388322518484598506887434919678523735730644910370844671443735688758643453429779989693237887466003372385925789250465970691404896872113423303038969, 6723990832715616500336095376073676701350917549865164961917998759715703447465536431516566237824694270482046698060410301496792150963281602144685882679390639901)
emb_flag = (3956409056364638168400543181298452742239103965766830338476029710731353557119679043260892196298159250455141959488613009091004454622819349680688797299967002549, 2951776604917486290836695572957027106817487586162444507028471362837490084205243361576174502575216282250806141358680269076670568688622463255476309019517775311)
# NIST P-256
NIST_256 = (
NIST_256_P := 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff,
NIST_256_K := GF(NIST_256_P),
NIST_256_A := NIST_256_K(0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc),
NIST_256_B := NIST_256_K(0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b),
NIST_256_CURVE := EllipticCurve(NIST_256_K, (NIST_256_A, NIST_256_B)),
NIST_256_GEN := NIST_256_CURVE(0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296, 0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5),
NIST_256_ORDER := 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551 * 0x1
)
NIST_256_CURVE.set_order(NIST_256_ORDER)
# NIST P-521
NIST_521 = (
NIST_521_P := 0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff,
NIST_521_K := GF(NIST_521_P),
NIST_521_A := NIST_521_K(0x01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc),
NIST_521_B := NIST_521_K(0x0051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00),
NIST_521_CURVE := EllipticCurve(NIST_521_K, (NIST_521_A, NIST_521_B)),
NIST_521_GEN := NIST_521_CURVE(0x00c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66, 0x011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650),
NIST_521_ORDER := 0x01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409 * 0x1
)
e1 = int(sha256(b"AN INFAMOUS PRNG NAMED DUAL_EC BACKDOORED BY NSA, FINALLY CONFIRMED BY SNOWDEN IN 2013.").hexdigest(), 16)
e2 = int(sha256(b"NO ONE CAN EXTRACT THE BACKDOOR! UNLESS YOU CAN BREAK THE ECDSA SIGNATURE SCHEME / ECDLP!").hexdigest(), 16)
g = 2^512
ni = inverse_mod(r1*s2, NIST_521_ORDER)
L = matrix(ZZ, [[1, 0, r2*s1*ni],
[0, 2^256, (e1*r2-e2*r1)*ni],
[0, 0, NIST_521_ORDER]])
basis = L.LLL()
for _ in basis:
if abs(_[-2]) == 2^256:
print(abs(int(_[0])).bit_length())
if abs(int(_[0])).bit_length() < 257 and abs(int(_[-1])).bit_length() <257:
k1 = abs(int(_[0]))
k2 = abs(int(_[-1]))
x1 = (k1*s1-e1)*inverse_mod(r1, NIST_521_ORDER)%NIST_521_ORDER
x2 = (k2*s2-e2)*inverse_mod(r2, NIST_521_ORDER)%NIST_521_ORDER
#d = 31415926535
d = 18159149320158605242937658533192205255908256510625616254946992862480865015765341725
E = EllipticCurve(NIST_521_K, (NIST_521_A, NIST_521_B))
E2 = EllipticCurve(NIST_256_K, (NIST_256_A, NIST_256_B))
P = E2(P)
Q = E2(Q)
assert x1 == x2
print(x1.nbits())
rand1 = x1>>(521-240)
rand2 = (x1>>(521-480))&(2^240-1)
#print(rand2.bit_length())
#d = 31415926535
print(rand2.nbits())
rand1 = rand1<<16
lsb = 0
for _ in tqdm(range(2^16)):
try:
seed = rand1+_
Q0 = E2.lift_x(seed)
state = ZZ((d*Q0).xy()[0])
r2 = ZZ((state*Q).xy()[0])>>16
if int(rand2) == int(r2):
lsb = _
break
except:
continue
seed = rand1+lsb
Q0 = E2.lift_x(seed)
state = ZZ((d*Q0).xy()[0])
for _ in range(7):
state = ZZ((state*P).xy()[0])
print(state)
k = 0
for _ in range(3):
print("state", state)
state = ZZ((state*P).xy()[0])
out = ZZ((state * Q).xy()[0])>>16
print("out", out)
k += out
k = k<<240
k = k>>240
k = k>>(240*3-521)
#print(k.bit_length())
print(k)
emb_flag = E(emb_flag)
M = inverse_mod(k, NIST_521_ORDER)*emb_flag
print(M.xy()[0])
m = long_to_bytes(int(M.xy()[0]))
print(m)