Mobile wallpaper 1Mobile wallpaper 2Mobile wallpaper 3Mobile wallpaper 4Mobile wallpaper 5Mobile wallpaper 6
1448 words
7 minutes
DASCTF 2026 夏季赛 WriteUp
2026-05-31
统计加载中...

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 * q
n2 = q * r
n3 = 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 = 110479112338979326841231465480900311437095583241804968504367003268478785311645575853029227541889465070127417880290972698509502098875302777600751062235679028180932171554996023850242418398546147652141811910224228666917788640895453721648601609529326886128507435254380985821439510394329605362511800619781782498829
n2 = 95225891725804035729098697183853172993650305271540351260130976375990969994680256179992972429701670943885218431291657615581872984046365977866046911929212400122026478512046580419614160900113488336302811792780327677539930592604198331529856760869923384410189400614767668529075682332352478496830621674767765967989
n3 = 111603865467493745511917065096450766019551858630764507502030413922630178420561431122201021143404521026218410173550594126191240832822627851633700772093095150654117699219949636045712687320990198957564564857885138504872560550777788915442814980338401072475446362026076893466520135409327492048388030114969050367401
e = 65537
c1 = 83456548767677952158133165776385438048214812740470347872014544040241661979735585698444752238351578159480247608435786172021153411975720140472715451216442036398970558532828923787921375318802867775369825882219621531795085442575971814645729572790836415339290407608988460626504016819536559945368010686567075802413
c2 = 55598291653542627898994967211126815679185160762475277667203320398466974811147081936849639204784572327753766773503264941715352990434513737784771805183050575481575095545922660276426069697449001567347723946016416649932633528235458091960122921036028416845355866656581114844470311590282808396786169332755296721792
c3 = 99617304265145206462280689337024202287720390645940568836285315412577937662785727570612881726190729195621460858194592258472873348744392240254689998279616123901037173010035977506212880680604466077172284894508163086916852071659627506881093976971048133795462670278664801263633610021626528113016267024450025017002
"""

n1 = p * q, n2 = q * r, n3 = p * rgcd打出公因子pqr即可:p = gcd(n1, n2), q = gcd(n1, n3), r = gcd(n2, n3)

exp.py

from math import gcd
from 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 = 110479112338979326841231465480900311437095583241804968504367003268478785311645575853029227541889465070127417880290972698509502098875302777600751062235679028180932171554996023850242418398546147652141811910224228666917788640895453721648601609529326886128507435254380985821439510394329605362511800619781782498829
n2 = 95225891725804035729098697183853172993650305271540351260130976375990969994680256179992972429701670943885218431291657615581872984046365977866046911929212400122026478512046580419614160900113488336302811792780327677539930592604198331529856760869923384410189400614767668529075682332352478496830621674767765967989
n3 = 111603865467493745511917065096450766019551858630764507502030413922630178420561431122201021143404521026218410173550594126191240832822627851633700772093095150654117699219949636045712687320990198957564564857885138504872560550777788915442814980338401072475446362026076893466520135409327492048388030114969050367401
e = 65537
c1 = 83456548767677952158133165776385438048214812740470347872014544040241661979735585698444752238351578159480247608435786172021153411975720140472715451216442036398970558532828923787921375318802867775369825882219621531795085442575971814645729572790836415339290407608988460626504016819536559945368010686567075802413
c2 = 55598291653542627898994967211126815679185160762475277667203320398466974811147081936849639204784572327753766773503264941715352990434513737784771805183050575481575095545922660276426069697449001567347723946016416649932633528235458091960122921036028416845355866656581114844470311590282808396786169332755296721792
c3 = 99617304265145206462280689337024202287720390645940568836285315412577937662785727570612881726190729195621460858194592258472873348744392240254689998279616123901037173010035977506212880680604466077172284894508163086916852071659627506881093976971048133795462670278664801263633610021626528113016267024450025017002
q = 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 AES
import hashlib, os, json, random
flag = b"?"
n = 6
q = 97
m = 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) % 16
enc = 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 = 6
q = 97
m = 30
A = [[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 = 4096s,对每个候选s计算:

vi=Ai,smodq,eibivi(modq)v_i=\langle A_i,s\rangle \bmod q,e_i\equiv b_i-v_i\pmod{q}

筛选满足所有误差e ∈ {-1, 0, 1}的解即可。

exp.py

import json, hashlib
from itertools import product
from 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)
break
key = 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, json
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from Crypto.Util.number import long_to_bytes, bytes_to_long
p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F
a = 0
b = 7
n = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
Gx = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798
Gy = 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 签名。签名公式为:

siki1(hi+dri)(modn)s_i \equiv k_i^{-1}(h_i + d \cdot r_i) \pmod{n}

其中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 签名公式可得:

sikihi+dri(modn)s_i\cdot k_i \equiv h_i + d \cdot r_i \pmod{n}

两边乘以s_i^{-1}

kihisi1+drisi1(modn)k_i \equiv h_i s_i^{-1} + d \cdot r_i \cdot s_i^{-1} \pmod{n}

令:

airisi1(modn),bihisi1(modn)a_i \equiv r_i\cdot s_i^{-1} \pmod{n}, b_i \equiv h_i\cdot s_i^{-1} \pmod{n}

得到:

kiaid+bi(modn)k_i \equiv a_i \cdot d + b_i \pmod{n}

由于所有k_i都小于2 ** 248,所以可以将其转化为 Hidden Number Problem,使用 LLL 格规约恢复私钥d

exp.py

# SageMath 10.7
from sage.all import *
import json
import hashlib
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
from 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 ** 248
a = []
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 * n
for i in range(m):
M[m, i] = a[i] * n
M[m, m] = K
for i in range(m):
M[m + 1, i] = b[i] * n
M[m + 1, m + 1] = n * K
L = M.LLL()
d = None
for 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)
break
assert d is not None
print("[+] 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/
Author
Q1uJu
Published at
2026-05-31
License
CC BY-NC-SA 4.0

Some information may be outdated