已知d高位攻击(未知位数过多)

题目

  • ! SUCTF2025-SU_rsa
from Crypto.Util.number import *
from hashlib import sha256
flag = open("flag.txt").read()
p = getPrime(512)
q = getPrime(512)
e = getPrime(256)
n = p*q
d = inverse(e,(p-1)*(q-1))
d_m = ((d >> 512) << 512)
print("d_m = ",d_m)
print("n = ",n)
print("e = ",e)

assert flag[6:-1] == sha256(str(p).encode()).hexdigest()[:32]
# d_m =  54846367460362174332079522877510670032871200032162046677317492493462931044216323394426650814743565762481796045534803612751698364585822047676578654787832771646295054609274740117061370718708622855577527177104905114099420613343527343145928755498638387667064228376160623881856439218281811203793522182599504560128
# n =  102371500687797342407596664857291734254917985018214775746292433509077140372871717687125679767929573899320192533126974567980143105445007878861163511159294802350697707435107548927953839625147773016776671583898492755338444338394630801056367836711191009369960379855825277626760709076218114602209903833128735441623
# e =  112238903025225752449505695131644979150784442753977451850362059850426421356123

解题思路

  • 这是一个已知 $d$ 高位攻击类型的题目,但是这个 $d$ 未知的位数达到了总体的一半

解答

from tqdm import trange
from Crypto.Util.number import inverse
from multiprocessing import Pool
from hashlib import sha256
import gmpy2

d_m = 54846367460362174332079522877510670032871200032162046677317492493462931044216323394426650814743565762481796045534803612751698364585822047676578654787832771646295054609274740117061370718708622855577527177104905114099420613343527343145928755498638387667064228376160623881856439218281811203793522182599504560128
n = 102371500687797342407596664857291734254917985018214775746292433509077140372871717687125679767929573899320192533126974567980143105445007878861163511159294802350697707435107548927953839625147773016776671583898492755338444338394630801056367836711191009369960379855825277626760709076218114602209903833128735441623
e = 112238903025225752449505695131644979150784442753977451850362059850426421356123

# 计算 k
k = (e*d_m) // n + 1

# 计算p mod e的值
k_inv = inverse(k,e)
s = (n + 1 + k_inv) % e
R.<x> = PolynomialRing(Zmod(e))
f = x^2 - s*x + n
res = f.roots()
may_p_mod_e = [int(res[0][0]),int(res[1][0])]

def attack(range):
    low = range[0]
    up = range[1]
    for pl in may_p_mod_e:
        R.<x> = PolynomialRing(Zmod(n))
        for i in trange(low,up):
            f = (x * 2^14 + i) * e + pl
            res = f.monic().small_roots(X=2^242,beta=0.49,epsilon=0.02)
            if res != []:
                print(f"res = {res}")
                print(f"i = {i}")
            for root in res:
                p = (int(root) * 2^14 + i) * e + pl
                if n % p == 0:
                    flag1 = "SUCTF{" + sha256(str(p).encode()).hexdigest()[:32] + "}"
                    flag2 = "SUCTF{" + sha256(str(n // p).encode()).hexdigest()[:32] + "}"
                    print(flag1)
                    print(flag2)
                    return 
                
ranges = [(i,i + 512) for i in range(0,2^14,512)]

with Pool(32) as pool:  
    r = list(pool.imap(attack,ranges))
'''
res = [4905784199556797483981650640778180846920923535274112964972302055716194418]
i = 2126
SUCTF{1c56d344aba19600db3956abebc34425}
SUCTF{c1864501fab1841178177d4f15af4ad8}
'''
from multiprocessing import Pool
from tqdm import trange
import sys

def attack(range_):
    n = 102371500687797342407596664857291734254917985018214775746292433509077140372871717687125679767929573899320192533126974567980143105445007878861163511159294802350697707435107548927953839625147773016776671583898492755338444338394630801056367836711191009369960379855825277626760709076218114602209903833128735441623
    e = 112238903025225752449505695131644979150784442753977451850362059850426421356123
    res = [(68696458789499884692247635135148296989030879976312427541751994081257774325189,1),(56220299912083199824680953877514275031991586299490111910943821482768735249418,1)]
    R.<k3h> = Zmod(n)[]
    low = range_[0]
    high = range_[1]
    for pl in res:
        for i in trange(low, high):
            bits = int(pl[0]).bit_length()
            f = (2 ^ 14 * k3h + i) * e + pl[0]
            root =  f.monic().small_roots(X = 2 ^ (512 - bits - 14), beta = 0.49, epsilon = 0.02)
            if root:
                p = (2 ^ 14 * int(root[0]) + i) * e + pl[0]
                assert n % p == 0
                print(p)
                sys.exit()


if __name__ == "__main__":   
    ranges = [(i, i + 1024) for i in range(0, 2 ^ 14, 1024)]
    with Pool(16) as pool:    #2 ^ 14 // 16 = 1024
        try: 
            list(pool.imap(attack, ranges))
        except:
            pool.terminate()  # 强制终止线程池
            pool.join()  # 等待线程清理
'''
9021355410009950348639875237199118006505512170606972234278412660410503971242219008091386834585426483874880261151641622040094401795529954768919085685089663
'''
from Crypto.Util.number import *  
  
d_m = 54846367460362174332079522877510670032871200032162046677317492493462931044216323394426650814743565762481796045534803612751698364585822047676578654787832771646295054609274740117061370718708622855577527177104905114099420613343527343145928755498638387667064228376160623881856439218281811203793522182599504560128  
n = 102371500687797342407596664857291734254917985018214775746292433509077140372871717687125679767929573899320192533126974567980143105445007878861163511159294802350697707435107548927953839625147773016776671583898492755338444338394630801056367836711191009369960379855825277626760709076218114602209903833128735441623  
e = 112238903025225752449505695131644979150784442753977451850362059850426421356123  

k = e*d_m // n + 1  
# s=p+q  
# ed_l+ks+[ed_h-1-k(n+1)]=0  
#(d_l,s,1)*L=(d_l,s,1)  

L = Matrix(ZZ, [  
	[1, 0, e],  
	[0, 1, k],  
	[0, 0, e*d_m - 1 - k*(n+1)],  
])  

# 配平目标向量  
# 513就行了(512也不行),至于为啥,我不清楚  
L[:, -1:] *= 2^513  

L = L.LLL()  
# L[0]:(-k,e,0)  
# L[1]:(d_l-t*k,s+t*e,0)  
# 理解:e和k只有256bit,比我们想要的d_l(512bit)和s(512bit)都要短  
# LLL之后肯定是前者这个较短的向量,所以从第二小的向量入手  

res=L[1] # s+t*e  
s=res[1]%e  
PR.<x> = PolynomialRing(Zmod(e))  
f = x^2 + n - s*x #p*p+p*q-p*s  
res = f.roots()  
pl = int(res[0][0]) # p%e  

import multiprocessing  
import tqdm  
from hashlib import sha256  

def copper_attack(i):  
	PR.<x> = PolynomialRing(Zmod(n))  
	f = e*(2^12*x + i) + pl  
	f = f.monic()  
	res = f.small_roots(X=2^244, beta=0.499, epsilon=0.02)  
	if(res != []):  
		t = int(res[0])  
		p = e*(2^12*t + i) + pl  
		q = n // p  
		assert p * q == n and isPrime(p) and isPrime(q)  
		print(sha256(str(p).encode()).hexdigest()[:32])  
		print(sha256(str(q).encode()).hexdigest()[:32])  
		return True  

with multiprocessing.Pool(processes=16) as pool:  
	for _ in tqdm.tqdm(pool.imap(copper_attack, range(2^12)), total=int(2^12)):  
		if(_):  
			break  
"""  
1c56d344aba19600db3956abebc34425  
c1864501fab1841178177d4f15af4ad8  
"""
posted @ 2025-07-25 19:42  sevensnight  阅读(24)  评论(0)    收藏  举报