1448 words
7 minutes
DASCTF 2026 夏季赛 WriteUp
Crypto
three_friends
题目:
from Crypto.Util.number import *
flag = b"***********"
L = len(flag)m1 = bytes_to_long(flag[:L//3])m2 = bytes_to_long(flag[L//3:2*L//3])m3 = bytes_to_long(flag[2*L//3:])
p = getPrime(512)q = getPrime(512)r = getPrime(512)
e = 65537
n1 = p * qn2 = q * rn3 = p * r
c1 = pow(m1, e, n1)c2 = pow(m2, e, n2)c3 = pow(m3, e, n3)
print(f"n1 = {n1}")print(f"n2 = {n2}")print(f"n3 = {n3}")print(f"e = {e}")print(f"c1 = {c1}")print(f"c2 = {c2}")print(f"c3 = {c3}")
"""n1 = 110479112338979326841231465480900311437095583241804968504367003268478785311645575853029227541889465070127417880290972698509502098875302777600751062235679028180932171554996023850242418398546147652141811910224228666917788640895453721648601609529326886128507435254380985821439510394329605362511800619781782498829n2 = 95225891725804035729098697183853172993650305271540351260130976375990969994680256179992972429701670943885218431291657615581872984046365977866046911929212400122026478512046580419614160900113488336302811792780327677539930592604198331529856760869923384410189400614767668529075682332352478496830621674767765967989n3 = 111603865467493745511917065096450766019551858630764507502030413922630178420561431122201021143404521026218410173550594126191240832822627851633700772093095150654117699219949636045712687320990198957564564857885138504872560550777788915442814980338401072475446362026076893466520135409327492048388030114969050367401e = 65537c1 = 83456548767677952158133165776385438048214812740470347872014544040241661979735585698444752238351578159480247608435786172021153411975720140472715451216442036398970558532828923787921375318802867775369825882219621531795085442575971814645729572790836415339290407608988460626504016819536559945368010686567075802413c2 = 55598291653542627898994967211126815679185160762475277667203320398466974811147081936849639204784572327753766773503264941715352990434513737784771805183050575481575095545922660276426069697449001567347723946016416649932633528235458091960122921036028416845355866656581114844470311590282808396786169332755296721792c3 = 99617304265145206462280689337024202287720390645940568836285315412577937662785727570612881726190729195621460858194592258472873348744392240254689998279616123901037173010035977506212880680604466077172284894508163086916852071659627506881093976971048133795462670278664801263633610021626528113016267024450025017002"""n1 = p * q, n2 = q * r, n3 = p * r,gcd打出公因子p,q,r即可:p = gcd(n1, n2), q = gcd(n1, n3), r = gcd(n2, n3)。
exp.py:
from math import gcdfrom Crypto.Util.number import long_to_bytes, inverse
def dec(c, p, q): phi = (p - 1) * (q - 1) d = inverse(e, phi) return long_to_bytes(pow(c, d, p * q))
n1 = 110479112338979326841231465480900311437095583241804968504367003268478785311645575853029227541889465070127417880290972698509502098875302777600751062235679028180932171554996023850242418398546147652141811910224228666917788640895453721648601609529326886128507435254380985821439510394329605362511800619781782498829n2 = 95225891725804035729098697183853172993650305271540351260130976375990969994680256179992972429701670943885218431291657615581872984046365977866046911929212400122026478512046580419614160900113488336302811792780327677539930592604198331529856760869923384410189400614767668529075682332352478496830621674767765967989n3 = 111603865467493745511917065096450766019551858630764507502030413922630178420561431122201021143404521026218410173550594126191240832822627851633700772093095150654117699219949636045712687320990198957564564857885138504872560550777788915442814980338401072475446362026076893466520135409327492048388030114969050367401e = 65537c1 = 83456548767677952158133165776385438048214812740470347872014544040241661979735585698444752238351578159480247608435786172021153411975720140472715451216442036398970558532828923787921375318802867775369825882219621531795085442575971814645729572790836415339290407608988460626504016819536559945368010686567075802413c2 = 55598291653542627898994967211126815679185160762475277667203320398466974811147081936849639204784572327753766773503264941715352990434513737784771805183050575481575095545922660276426069697449001567347723946016416649932633528235458091960122921036028416845355866656581114844470311590282808396786169332755296721792c3 = 99617304265145206462280689337024202287720390645940568836285315412577937662785727570612881726190729195621460858194592258472873348744392240254689998279616123901037173010035977506212880680604466077172284894508163086916852071659627506881093976971048133795462670278664801263633610021626528113016267024450025017002q = gcd(n1, n2)p = gcd(n1, n3)r = gcd(n2, n3)flag = dec(c1, p, q) + dec(c2, q, r) + dec(c3, p, r)print(flag.decode())# DASCTF{thr33_fri3nds_sh@r3_pr1m3s!!}lattice_oracle
题目:
from Crypto.Cipher import AESimport hashlib, os, json, random
flag = b"?"
n = 6q = 97m = 30
s = [random.randint(0, 3) for _ in range(n)]
A = []b = []for _ in range(m): a_i = [random.randint(0, q - 1) for _ in range(n)] e_i = random.randint(-1, 1) b_i = (sum(x * y for x, y in zip(a_i, s)) + e_i) % q A.append(a_i) b.append(b_i)
key = hashlib.sha256(str(s).encode()).digest()[:16]iv = os.urandom(16)pad_len = 16 - len(flag) % 16enc = AES.new(key, AES.MODE_CBC, iv).encrypt(flag + bytes([pad_len]) * pad_len)
print(f"n = {n}")print(f"q = {q}")print(f"m = {m}")print(f"A = {A}")print(f"b = {b}")print(f"iv = '{iv.hex()}'")print(f"enc = '{enc.hex()}'")
"""n = 6q = 97m = 30A = [[94, 13, 86, 94, 69, 11], [54, 4, 3, 11, 27, 29], [77, 3, 71, 25, 91, 83], [69, 53, 28, 57, 75, 35], [20, 89, 54, 43, 35, 19], [43, 13, 11, 48, 12, 45], [77, 33, 5, 93, 58, 68], [48, 10, 70, 37, 80, 79], [73, 24, 90, 8, 5, 84], [37, 10, 29, 12, 48, 35], [81, 46, 20, 47, 45, 26], [34, 89, 87, 82, 9, 77], [21, 68, 93, 31, 20, 59], [34, 81, 88, 71, 28, 87], [77, 29, 4, 40, 51, 34], [27, 72, 91, 40, 27, 83], [50, 82, 58, 18, 33, 17], [95, 71, 68, 33, 95, 74], [74, 51, 46, 28, 17, 65], [11, 96, 6, 14, 19, 80], [87, 54, 76, 8, 49, 48], [59, 67, 32, 70, 1, 87], [14, 87, 68, 96, 34, 82], [14, 37, 55, 20, 58, 0], [92, 33, 64, 22, 64, 13], [38, 81, 64, 77, 25, 19], [20, 69, 67, 0, 76, 41], [2, 14, 46, 39, 30, 7], [72, 10, 10, 93, 62, 8], [16, 16, 84, 60, 70, 21]]b = [56, 74, 51, 28, 10, 30, 34, 45, 82, 56, 62, 52, 5, 71, 35, 41, 86, 47, 8, 27, 64, 29, 57, 92, 34, 55, 57, 70, 87, 28]iv = 'bcdad772f7a0ec967887f7b8f36234c8'enc = '00ac1bac207e84d91c6243c4aead3576a20f996a5420eea7bfa0df3b61d68c83f283bd31f1fedf7465b6445d7a58dcdc'"""s只有 6 维,每维0 ~ 3,直接爆破4 ** 6 = 4096种s,对每个候选s计算:
筛选满足所有误差e ∈ {-1, 0, 1}的解即可。
exp.py:
import json, hashlibfrom itertools import productfrom Crypto.Cipher import AES
data = json.load(open("data.txt"))A = data["A"]b = data["b"]q = data["q"]n = data["n"]for s in product(range(4), repeat=n): ok = True for ai, bi in zip(A, b): v = sum(x * y for x, y in zip(ai, s)) % q e = (bi - v) % q if e > q // 2: e -= q if e not in (-1, 0, 1): ok = False break if ok: s = list(s) print("s =", s) breakkey = hashlib.sha256(str(s).encode()).digest()[:16]iv = bytes.fromhex(data["iv"])enc = bytes.fromhex(data["enc"])cipher = AES.new(key, AES.MODE_CBC, iv)pt = cipher.decrypt(enc)pt = pt[:-pt[-1]]print(pt.decode())# s = [0, 0, 2, 1, 1, 1]# DASCTF{LWE_l4tt1c3_r3duct10n_i5_p0w3rful!}phantom_sign
题目:
import os, hashlib, jsonfrom Crypto.Cipher import AESfrom Crypto.Util.Padding import padfrom Crypto.Util.number import long_to_bytes, bytes_to_long
p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2Fa = 0b = 7n = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141Gx = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798Gy = 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8
def inv_mod(val, mod): return pow(val, -1, mod)
def point_add(P, Q): if P is None: return Q if Q is None: return P x1, y1 = P x2, y2 = Q if x1 == x2 and y1 != y2: return None if P == Q: lam = (3 * x1 * x1 + a) * inv_mod(2 * y1, p) % p else: lam = (y2 - y1) * inv_mod(x2 - x1, p) % p x3 = (lam * lam - x1 - x2) % p y3 = (lam * (x1 - x3) - y1) % p return (x3, y3)
def point_mul(k, P): R = None Q = P while k > 0: if k & 1: R = point_add(R, Q) Q = point_add(Q, Q) k >>= 1 return R
G = (Gx, Gy)
flag = b"DASCTF{************************************}"d = bytes_to_long(os.urandom(32)) % n
Q = point_mul(d, G)
NUM_SIGS = 40
messages = []sigs = []
for i in range(NUM_SIGS): msg = f"transaction_{i:04d}".encode() h_i = int(hashlib.sha256(msg).hexdigest(), 16) % n k_i = bytes_to_long(os.urandom(31)) R_i = point_mul(k_i, G) r_i = R_i[0] % n s_i = inv_mod(k_i, n) * (h_i + d * r_i) % n messages.append(msg.decode()) sigs.append((h_i, r_i, s_i))
key = hashlib.sha256(long_to_bytes(d)).digest()[:16]iv = os.urandom(16)enc = AES.new(key, AES.MODE_CBC, iv).encrypt(pad(flag, 16))
output = { "curve": {"p": p, "a": a, "b": b, "n": n, "Gx": Gx, "Gy": Gy}, "Q": [Q[0], Q[1]], "messages": messages, "signatures": [(h, r, s) for h, r, s in sigs], "iv": iv.hex(), "enc": enc.hex(),}
with open("data.json", "w") as f: json.dump(output, f, indent=2)题目实现了 secp256k1 上的 ECDSA 签名。签名公式为:
其中d是私钥,k_i是每次签名使用的 nonce。正常情况下,k_i应该在[1, n)中均匀随机选取,但题目中使用了:
k_i = bytes_to_long(os.urandom(31))因此每个 nonce 只有 31 字节,即0 <= k_i < 2^248。而 secp256k1 的阶n约为 256 bit,所以 nonce 的最高 8 bit 恒为 0,存在明显偏置。由 ECDSA 签名公式可得:
两边乘以s_i^{-1}:
令:
得到:
由于所有k_i都小于2 ** 248,所以可以将其转化为 Hidden Number Problem,使用 LLL 格规约恢复私钥d。
exp.py:
# SageMath 10.7from sage.all import *import jsonimport hashlibfrom Crypto.Cipher import AESfrom Crypto.Util.Padding import unpadfrom Crypto.Util.number import long_to_bytes
with open("data.json", "r") as f: data = json.load(f)n = data["curve"]["n"]sigs = data["signatures"]m = len(sigs)K = 2 ** 248a = []b = []for h, r, s in sigs: inv_s = inverse_mod(s, n) a.append((r * inv_s) % n) b.append((h * inv_s) % n)# 构造格# 目标短向量形如:# (n*k_1, n*k_2, ..., n*k_m, d*K, n*K)M = Matrix(ZZ, m + 2, m + 2)for i in range(m): M[i, i] = n * nfor i in range(m): M[m, i] = a[i] * nM[m, m] = Kfor i in range(m): M[m + 1, i] = b[i] * nM[m + 1, m + 1] = n * KL = M.LLL()d = Nonefor row in L.rows(): if abs(row[m + 1]) == n * K: c = row[m + 1] // (n * K) cand = (row[m] // K) * inverse_mod(c, n) cand %= n d = int(cand) breakassert d is not Noneprint("[+] d =", d)key = hashlib.sha256(long_to_bytes(d)).digest()[:16]iv = bytes.fromhex(data["iv"])enc = bytes.fromhex(data["enc"])cipher = AES.new(key, AES.MODE_CBC, iv)flag = unpad(cipher.decrypt(enc), 16)print("[+] flag =", flag.decode())# [+] d = 69733894115169365517439430123407937761015055472912247236884018827222720875663#abs [+] flag = DASCTF{3cd5a_b1as3d_n0nc3_HNP_l4tt1c3_4ttack!} DASCTF 2026 夏季赛 WriteUp
https://q1uju.cc/posts/dasctf2026summer_writeup/ Some information may be outdated









