from Crypto.Util.number import * e = 3 n = 8250871280281573979365095715711359115372504458973444367083195431861307534563246537364248104106494598081988216584432003199198805753721448450911308558041115465900179230798939615583517756265557814710419157462721793864532239042758808298575522666358352726060578194045804198551989679722201244547561044646931280001 c = 945272793717722090962030960824180726576357481511799904903841312265308706852971155205003971821843069272938250385935597609059700446530436381124650731751982419593070224310399320617914955227288662661442416421725698368791013785074809691867988444306279231013360024747585261790352627234450209996422862329513284149
p = 225933944608558304529179430753170813347 q = 260594583349478633632570848336184053653 r = 218566259296037866647273372633238739089 t = 223213222467584072959434495118689164399
# sage from Crypto.Util.number import * from itertools import product
# Given parameters e = 3 n = 8250871280281573979365095715711359115372504458973444367083195431861307534563246537364248104106494598081988216584432003199198805753721448450911308558041115465900179230798939615583517756265557814710419157462721793864532239042758808298575522666358352726060578194045804198551989679722201244547561044646931280001 c = 945272793717722090962030960824180726576357481511799904903841312265308706852971155205003971821843069272938250385935597609059700446530436381124650731751982419593070224310399320617914955227288662661442416421725698368791013785074809691867988444306279231013360024747585261790352627234450209996422862329513284149
# Prime factors p = 225933944608558304529179430753170813347 q = 260594583349478633632570848336184053653 r = 218566259296037866647273372633238739089 t = 223213222467584072959434495118689164399
# Create polynomial rings and find roots in each field R.<x> = Zmod(p)[] f = x^e - c res_p = f.monic().roots()
R.<x> = Zmod(q)[] f = x^e - c res_q = f.monic().roots()
R.<x> = Zmod(r)[] f = x^e - c res_r = f.monic().roots()
R.<x> = Zmod(t)[] f = x^e - c res_t = f.monic().roots()
# Iterate through all possible combinations of roots for (m_p, _) in res_p: for (m_q, _) in res_q: for (m_r, _) in res_r: for (m_t, _) in res_t: # Combine using CRT in stages # First combine p and q m_pq = crt(int(m_p), int(m_q), p, q) # Then combine r and t m_rt = crt(int(m_r), int(m_t), r, t) # Finally combine the two results m = crt(m_pq, m_rt, p*q, r*t) mes = long_to_bytes(m) print(mes) # b'flag{Fear_can_hold_you_prisoner_Hope_can_set_you_free}\x06\x06\x06\x06\x06\x06'
在这个脚本下我们能解决大部分问题,但是当太大的时候我们就得考虑其他的方法来处理了
根据题型,我们有几种应付的思路
UCSCCTF2025—EzCalculate
题面
1 2 3 4 5 6 7 8 9 10 11 12 13 14
p = 9586253455468582613875015189854230646329578628731744411408644831684238720919107792959420247980417763684885397749546095133107188260274536708721056484419031 q = 8998523072192453101232205847855618180700579235012899613083663121402246420191771909612939404791268078655630846054784775118256720627970477420936836352759291 n = p * q e = 65536 c = 74962027356320017542746842438347279031419999636985213695851878703229715143667648659071242394028952959096683055640906478244974899784491598741415530787571499313545501736858104610426804890565497123850685161829628373760791083545457573498600656412030353579510452843445377415943924958414311373173951242344875240776
# sage defAM1M(residue, e, p): """ 返回 x^e ≡ residue mod p 的所有解 """ if (p-1) % e != 0: raise ValueError(f"e={e} 不能整除 p-1={p-1},AMM 不适用")
# 分解 p-1 = e^t * s t = valuation(p - 1, e) s = (p - 1) // (e^t) # 计算 d = e^{-1} mod s d = inverse_mod(e, s) # 简单情况:t=1 if t == 1: x = power_mod(residue, d, p) F = GF(p) zeta = F.zeta(e) return [ (x * zeta**i) % p for i inrange(e) ] # 寻找 e 次非剩余(生成元) F = GF(p) g = F.multiplicative_generator() noresidue = g while (noresidue^((p-1)//e)) == 1: noresidue *= g # 计算单位根和辅助变量 a = power_mod(noresidue, e^(t-1) * s, p) b = power_mod(residue, e * d - 1, p) c = power_mod(noresidue, s, p) h = 1 # Hensel 提升 for i inrange(1, t): d_i = power_mod(b, e^(t-1-i), p) if d_i == 1: j = 0 else: j = -discrete_log(d_i, a) b = (power_mod(c, e, p)^j * b) % p h = (power_mod(c, j, p) * h) % p c = power_mod(c, e, p) x0 = (power_mod(residue, d, p) * h) % p ω = F.zeta(e) # e 阶单位根 return [ (x0 * ω^i) % p for i inrange(e) ] # 返回所有解
这里能得到所有模p下的解,再整合起来打CRT就解决了
来个实战例子
NCTF2019—EzRSA
1 2 3 4 5 6 7 8 9 10 11 12
e = 0x1337 p = 199138677823743837339927520157607820029746574557746549094921488292877226509198315016018919385259781238148402833316033634968163276198999279327827901879426429664674358844084491830543271625147280950273934405879341438429171453002453838897458102128836690385604150324972907981960626767679153125735677417397078196059 q = 112213695905472142415221444515326532320352429478341683352811183503269676555434601229013679319423878238944956830244386653674413411658696751173844443394608246716053086226910581400528167848306119179879115809778793093611381764939789057524575349501163689452810148280625226541609383166347879832134495444706697124741 n = p * q c = 10562302690541901187975815594605242014385201583329309191736952454310803387032252007244962585846519762051885640856082157060593829013572592812958261432327975138581784360302599265408134332094134880789013207382277849503344042487389850373487656200657856862096900860792273206447552132458430989534820256156021128891296387414689693952047302604774923411425863612316726417214819110981605912408620996068520823370069362751149060142640529571400977787330956486849449005402750224992048562898004309319577192693315658275912449198365737965570035264841782399978307388920681068646219895287752359564029778568376881425070363592696751183359
from Crypto.Util.number import * import itertools from multiprocessing import Pool, cpu_count from tqdm import tqdm from sage.allimport *
e = 0x1337 p = 199138677823743837339927520157607820029746574557746549094921488292877226509198315016018919385259781238148402833316033634968163276198999279327827901879426429664674358844084491830543271625147280950273934405879341438429171453002453838897458102128836690385604150324972907981960626767679153125735677417397078196059 q = 112213695905472142415221444515326532320352429478341683352811183503269676555434601229013679319423878238944956830244386653674413411658696751173844443394608246716053086226910581400528167848306119179879115809778793093611381764939789057524575349501163689452810148280625226541609383166347879832134495444706697124741 n = p * q c = 10562302690541901187975815594605242014385201583329309191736952454310803387032252007244962585846519762051885640856082157060593829013572592812958261432327975138581784360302599265408134332094134880789013207382277849503344042487389850373487656200657856862096900860792273206447552132458430989534820256156021128891296387414689693952047302604774923411425863612316726417214819110981605912408620996068520823370069362751149060142640529571400977787330956486849449005402750224992048562898004309319577192693315658275912449198365737965570035264841782399978307388920681068646219895287752359564029778568376881425070363592696751183359
cp = c % p cq = c % q
inv_p = pow(p, -1, q) inv_q = pow(q, -1, p)
defAMM(residue, e, p): if (p-1) % e != 0: raise ValueError(f"e={e} does not divide p-1={p-1}")
t = valuation(p - 1, e) s = (p - 1) // (e**t) d = inverse_mod(e, s) if t == 1: x = power_mod(residue, d, p) F = GF(p) zeta = F.zeta(e) return [ (x * zeta**i) % p for i inrange(e) ] F = GF(p) g = F.multiplicative_generator() noresidue = g while (noresidue**((p-1)//e)) == 1: noresidue *= g a = power_mod(noresidue, e**(t-1) * s, p) b = power_mod(residue, e * d - 1, p) c = power_mod(noresidue, s, p) h = 1 for i inrange(1, t): d_i = power_mod(b, e**(t-1-i), p) if d_i == 1: j = 0 else: j = -discrete_log(d_i, a) b = (power_mod(c, e, p)**j * b) % p h = (power_mod(c, j, p) * h) % p c = power_mod(c, e, p) x0 = (power_mod(residue, d, p) * h) % p ω = F.zeta(e) return [ (x0 * ω**i) % p for i inrange(e) ]
defcompute_crt(args): m1, m2 = args m1_int = int(m1) # Convert to Python int m2_int = int(m2) # Convert to Python int x = (m1_int * q * inv_q + m2_int * p * inv_p) % n return x
deffind_flag(): resp = AMM(cp, e, p) resq = AMM(cq, e, q)
print(f"[+] Solutions in GF(p): {len(resp)}") print(f"[+] Solutions in GF(q): {len(resq)}") print(f"[+] Total combinations: {len(resp) * len(resq)}")
with Pool(cpu_count()) as pool: combinations = itertools.product(resp, resq) for x in tqdm( pool.imap_unordered(compute_crt, combinations, chunksize=10000), total=len(resp) * len(resq), desc="Brute-forcing CRT" ): flag = long_to_bytes(x) ifb'NCTF{'in flag: print(f"\n[+] Flag: {flag.decode()}") pool.terminate() return