DASCTF2025-Fall

Above

Team : Dawn-DAMN

Score : 4733

Rank : 13

Crypto Solved 2 of 3

lost LFSR key

task.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
from Crypto.Util.number import *
from secret import flag
from random import *

flag = flag.strip(b"DASCTF{").strip(b"}")
assert len(flag) == 64

class myRNG():

def init(self,seed=None):
if(seed):
self.seed = seed
else:
self.seed = getrandbits(64)
self.mask = getrandbits(64)

def next(self):
i = self.seed & self.mask
Out = 0
while i != 0:
Out = Out ^ (i & 1)
i = i >> 1
self.seed = ((self.seed << 1) | Out) & ((1 << 64) - 1)
return Out

def get_myRNG_randbits(self,n):
temp = 0
for i in range(n):
temp = (temp << 1) | self.next()
return temp

generator = myRNG()
key = generator.get_myRNG_randbits(64*8)

print("mask =", generator.mask)
print("c =", key ^ bytes_to_long(flag))
'''
mask = 9319439021858903464
c = 8882504877732087312989345828667663333297225833982945014279010438327750150593504327259176959316943362605442206624947923157363187067410478202161873663103506
'''

LFSR的题 关键洞在

1
2
key = generator.get_myRNG_randbits(64*8) 
c = key ^ bytes_to_long(flag)

flag是给定的64字节 与key的8*64bits重合 而且flag的内部全是可视ASCII 意味着每8个bits中的最高位都一定是0 那我们就得到了64个已知的信息Bit

也就是说就是我们的key 也就是LFSR的输出 而LFSR的运算可以转化为上的线性运算 所以说64个已知位结合我们已知的64位mask ,可以构造64组方程 足矣解出我们初始的64位State 也就是Seed 获得Seed之后直接解出key 然后求flag即可

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
from Crypto.Util.number import long_to_bytes
from itertools import product

# 题目给出的参数
mask = 9319439021858903464
c = 8882504877732087312989345828667663333297225833982945014279010438327750150593504327259176959316943362605442206624947923157363187067410478202161873663103506

# PRNG 类(用于验证和解密)
class myRNG:
def __init__(self, seed, mask):
self.seed = seed
self.mask = mask

def next(self):
i = self.seed & self.mask
Out = 0
while i != 0:
Out = Out ^ (i & 1)
i = i >> 1
self.seed = ((self.seed << 1) | Out) & ((1 << 64) - 1)
return Out

def get_myRNG_randbits(self, n):
temp = 0
for i in range(n):
temp = (temp << 1) | self.next()
return temp

def solve():
print("正在分析并求解线性方程组...")
N = 64

# 1. 收集约束条件
# Flag 为 64 字节,假定为 ASCII,则每字节最高位(MSB)为 0
# 对应关系: Key_bit ^ Flag_bit = C_bit => Key_bit = C_bit
targets = {}
for i in range(64):
# 512位整数中,第 i 个字节的 MSB 位置 (从高到低)
pos = 511 - 8 * i
# 该位是由 RNG 的第 step 步产生的
step = 8 * i
# 提取密文对应位
val = (c >> pos) & 1
targets[step] = val

# 2. 建立方程组
# state[k] 表示当前状态第 k 位受哪些初始 seed 位(x0...x63)的影响
state = [1 << k for k in range(N)]
equations = []

max_step = max(targets.keys())

for step in range(max_step + 1):
out_mask = 0
for k in range(N):
if (mask >> k) & 1:
out_mask ^= state[k]

if step in targets:
equations.append((out_mask, targets[step]))

new_state = [0] * N
new_state[0] = out_mask
for k in range(1, N):
new_state[k] = state[k-1]
state = new_state

M = [(eq[0] << 1) | eq[1] for eq in equations]

pivot_row = 0
pivots = {} # col -> row

for col in range(N):
pivot_idx = -1
for r in range(pivot_row, len(M)):
if (M[r] >> (col + 1)) & 1:
pivot_idx = r
break

if pivot_idx == -1:
continue
M[pivot_row], M[pivot_idx] = M[pivot_idx], M[pivot_row]

for r in range(len(M)):
if r != pivot_row:
if (M[r] >> (col + 1)) & 1:
M[r] ^= M[pivot_row]

pivots[col] = pivot_row
pivot_row += 1

# 4. 识别自由变量并遍历解空间
free_vars = [k for k in range(N) if k not in pivots]
print(f"矩阵秩: {len(pivots)}, 自由变量数量: {len(free_vars)}")
print(f"自由变量索引: {free_vars}")

for free_vals in product([0, 1], repeat=len(free_vars)):
seed_val = 0

# 设置自由变量的值
for i, k in enumerate(free_vars):
if free_vals[i]:
seed_val |= (1 << k)


for k in range(N):
if k in pivots:
r = pivots[k]
row = M[r]
rhs = row & 1
coeffs = row >> 1

# 排除 x_k 自身
coeffs &= ~(1 << k)

# 计算已知部分的异或和
p = 0
temp = coeffs & seed_val
while temp:
p ^= 1
temp &= (temp - 1)

if rhs ^ p:
seed_val |= (1 << k)

try:
gen = myRNG(seed_val, mask)
key = gen.get_myRNG_randbits(64*8)

flag_int = c ^ key
flag_bytes = long_to_bytes(flag_int)

if len(flag_bytes) < 64:
flag_bytes = b'\x00' * (64 - len(flag_bytes)) + flag_bytes

if all(0x20 <= b <= 0x7E for b in flag_bytes):
print("\n[+] 找到有效 Flag!")
print(f"Recovered Seed: {seed_val}")
try:
flag_content = flag_bytes.decode()
print(f"Flag: DASCTF{{{flag_content}}}")
return
except:
print(f"Flag Bytes: {flag_bytes}")
except Exception:
continue


if __name__ == "__main__":
solve()

'''

正在分析并求解线性方程组...
矩阵秩: 63, 自由变量数量: 1
自由变量索引: [62]

[+] 找到有效 Flag!
Recovered Seed: 15343720169816213745
Flag: DASCTF{f1nd_th3_hidden_Linear_R3lat1onShip_@nd_th3n_F1nd_My_Lo5t_KEY!!!}

'''

Two_Examples

task.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
from Crypto.Util.number import *
import json
from hashlib import *
from gmpy2 import *
from flag import flag
n= 20
m = 30
p = getPrime(160)

A = [random_vector(GF(p),m) for _ in range(n)]
B = [random_vector(GF(p),m) for _ in range(n)]
A = matrix(GF(p),A)
B = matrix(GF(p),B)

s1 = random_vector(GF(p),n)
s2 = random_vector(GF(p),n)

e1 = vector(GF(p),[choice([-1,0,1]) for _ in range(m)])
e2 = vector(GF(p),[choice([-1,0,1]) for _ in range(m)])

b1 = s1*A + s2*B + e1
b2 = s2*A + s1*B + e2

with open('M.matrix','w') as f:
json.dump({"A": str(list(A)),"B": str(list(B)),"p":str(p)}, f)

with open('v.vector','w') as f:
json.dump({"b1": str(list(b1)),"b2": str(list(b2))}, f)

def vector_to_sha512_hex(vector):

vector_str = ''.join(str(i) for i in vector)
res = sha512(vector_str.encode()).hexdigest()
res = int(res,16)
return res

d = vector_to_sha512_hex(s1) + vector_to_sha512_hex(s2)
P = getPrime(512)
Q = getPrime(512)
N = P*Q
phi = (P-1)*(Q-1)
while gcd(d,phi) != 1:
d += 1

e = inverse(d,phi)
flag = bytes_to_long(flag)
c = power_mod(flag,e,N)

with open('RSA.enc','w') as f:
json.dump({"N": str(N),"c": str(c)}, f)

很经典的LWE问题了 choice的选取也非常小 在WMCTF的Lwe出过比这个更近一步的 我们直接参考鸡块师傅的板子 LWE | 糖醋小鸡块的blog (tangcuxiaojikuai.xyz)

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
import json
from hashlib import sha512
from Crypto.Util.number import long_to_bytes
from sage.all import *

print("[*] Loading data...")


try:
with open('M.matrix', 'r') as f:
data_m = json.load(f)
p = int(data_m["p"])
A_list = eval(data_m["A"])
B_list = eval(data_m["B"])

with open('v.vector', 'r') as f:
data_v = json.load(f)
b1_list = eval(data_v["b1"])
b2_list = eval(data_v["b2"])

with open('RSA.enc', 'r') as f:
data_rsa = json.load(f)
N = int(data_rsa["N"])
c = int(data_rsa["c"])
except FileNotFoundError:
print("[-] Error: Data files not found.")
exit()

# 初始化参数
n = 20
m = 30
F = GF(p)

A = matrix(F, A_list)
B = matrix(F, B_list)
b1 = vector(F, b1_list)
b2 = vector(F, b2_list)

print(f"[*] Parameters: n={n}, m={m}, p={p.bit_length()} bits")

M_plus = A + B
b_plus = b1 + b2
M_minus = A - B
b_minus = b1 - b2

# 3. 定义 Primal Attack 函数
def solve_primal_attack(M, b, modulus):
m_dim = M.ncols() # 30
n_dim = M.nrows() # 20

block1 = matrix.identity(m_dim) * modulus
block2 = M.change_ring(ZZ)
block3 = matrix(ZZ, -b)

col_zeros_m = matrix.zero(m_dim, 1)
col_zeros_n = matrix.zero(n_dim, 1)
col_one = matrix.identity(1)

# 组装
row1 = block1.augment(col_zeros_m) # 30 x 31
row2 = block2.augment(col_zeros_n) # 20 x 31
row3 = block3.augment(col_one) # 1 x 31

L = block_matrix([[row1], [row2], [row3]])

print(f" Running LLL on lattice dimension {L.nrows()}x{L.ncols()}...")
L_reduced = L.LLL()

e_vec = None

for row in L_reduced:
last_val = row[-1]
vec_part = row[:-1]

if last_val == 1:
e_candidate = vector(F, [-x for x in vec_part])
try:
target = b - e_candidate
s_sol = M.solve_left(target)
e_vec = e_candidate
print(" [+] Error recovered (row end 1).")
return s_sol, e_vec
except ValueError:
continue

elif last_val == -1:
# row = (e, -1) => e = vec_part
e_candidate = vector(F, [x for x in vec_part])
try:
target = b - e_candidate
s_sol = M.solve_left(target)
e_vec = e_candidate
print(" [+] Error recovered (row end -1).")
return s_sol, e_vec
except ValueError:
continue

raise ValueError("Failed to recover e using Primal Attack")

print("[*] Solving for s_plus (s1+s2)...")
s_plus, e_plus = solve_primal_attack(M_plus, b_plus, p)

print("[*] Solving for s_minus (s1-s2)...")
s_minus, e_minus = solve_primal_attack(M_minus, b_minus, p)

inv_2 = F(2).inverse()
s1 = (s_plus + s_minus) * inv_2
s2 = (s_plus - s_minus) * inv_2

print("[+] s1 and s2 reconstructed.")

def vector_to_sha512_hex(vec):
vector_str = ''.join(str(i) for i in vec)
res = sha512(vector_str.encode()).hexdigest()
res = int(res, 16)
return res

d_base = vector_to_sha512_hex(s1) + vector_to_sha512_hex(s2)
print(f"[*] Base d: {d_base}...")

print("[*] Searching for valid flag...")
for i in range(500):
d_guess = d_base + i

m_int = power_mod(c, d_guess, N)
try:
m_bytes = long_to_bytes(int(m_int))
if b'flag{' in m_bytes or b'CTF{' in m_bytes:
print("\n" + "#"*50)
print(f"FLAG FOUND with d_offset={i}:")
print(m_bytes.decode())
print("#"*50 + "\n")
break
except:
pass
else:
print("[-] Flag not found in range.")


'''

[*] Loading data...
[*] Parameters: n=20, m=30, p=160 bits
[*] Solving for s_plus (s1+s2)...
Running LLL on lattice dimension 51x31...
[+] Error recovered (row end 1).
[*] Solving for s_minus (s1-s2)...
Running LLL on lattice dimension 51x31...
[+] Error recovered (row end 1).
[+] s1 and s2 reconstructed.
[*] Base d: 15829519161807649604997063627428333703080852958448411437324803691092722399601763346879632976849254515081077292041342199672094869180782512862924423581282470...
[*] Searching for valid flag...

##################################################
FLAG FOUND with d_offset=3:
DASCTF{Y0U_Can_S01ve_The_lwe!!!!}
##################################################

'''

Serration

main.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
from Crypto.Util.number import *
from hashlib import sha256
import socketserver
import signal
import os
import string
import random
from sympy.ntheory.modular import crt
from line_profiler import LineProfiler


flag = os.getenv('DASFLAG')

def euclide_ext(a, b):
x, xx, y, yy = 1, 0, 0, 1
while b:
q = a // b
a, b = b, a % b
x, xx = xx, x - xx * q
y, yy = yy, y - yy * q
return x, y, a

class Montgomery:
n: int
k: int
r: int
r_inv: int
n_inv: int

def __init__(self, n, k):
self.n = n
self.k = k
self.r = 2 ** k
self.r_inv, self.n_inv, gcd = euclide_ext(self.r, self.n)
self.n_inv = -self.n_inv
if gcd != 1:
raise ValueError("gcd(r,n) must be 1")
if self.r * self.r_inv - self.n * self.n_inv != 1:
raise ValueError(
f"For ({self.r} that created from {2} ** {k},{n}) doesn't exists diophantine equation decision"
)
self.r_inv = self.r_inv % self.n

def mon_pro(self, a_n, b_n):
t = a_n * b_n
u = (t + (t * self.n_inv % self.r) * self.n) >> self.k
if u > self.n:
u -= self.n
return u

def mon_exp(self, a: int, e: int):
a = a * self.r % self.n
x = self.r % self.n
for i in reversed(range(0, e.bit_length())):
x= self.mon_pro(x, x)
if (e & (1 << i)) :
x= self.mon_pro(x, a)
return self.mon_pro(x, 1)


class Task(socketserver.BaseRequestHandler):
def _recvall(self):
BUFF_SIZE = 2048
data = b''
while True:
part = self.request.recv(BUFF_SIZE)
data += part
if len(part) < BUFF_SIZE:
break
return data.strip()

def send(self, msg, newline=True):
try:
if newline:
msg += b'\n'
self.request.sendall(msg)
except:
pass

def recv(self, prompt=b'> '):
self.send(prompt, newline=False)
return self._recvall()

def handle(self):
bits=1024
p=getPrime(bits)
q=getPrime(bits)
e=getPrime(bits-10)
n=p*q
print(p,",",q)
print(flag)
P=Montgomery(p,bits)
Q=Montgomery(q,bits)
self.send(str((n,e)).encode())
signal.alarm(300)
for i in range(600):
lp = LineProfiler()
lp.add_function(Q.mon_pro)
lp_exp = lp(P.mon_exp)
lq_exp = lp(Q.mon_exp)
self.send(b"leave message 4 me",newline=False)
m=int(self.recv())
cp=lp_exp(m,e)
cq=lq_exp(m,e)
c=crt([p,q],[cp,cq])
d={}
for i in lp.code_map:
for j in lp.code_map[i]:
d[j]=(lp.code_map[i][j]['total_time'],lp.code_map[i][j]['nhits'])
self.send(str(d).encode())
self.send(b"can you break me?",newline=False)
guess=int(self.recv())
if guess in {p,q}:
self.send(flag.encode())
else:
self.send(b"sorry~")
exit

class ThreadedServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
pass


class ForkedServer(socketserver.ForkingMixIn, socketserver.TCPServer):
pass


if __name__ == "__main__":
HOST, PORT = '0.0.0.0', 9999
print("HOST:POST " + HOST+":" + str(PORT))
server = ForkedServer((HOST, PORT), Task)
server.allow_reuse_address = True
server.serve_forever()

题目构造了一个基于蒙哥马利额外约简的RSA靶机 在生成1024位的p q后要求你进行选择明文攻击 以RSA-CRT的形式对传入的m进行加密 随后告知你有关加密过程中某一个模数因子p的侧信道

1
d[j]=(lp.code_map[i][j]['total_time'],lp.code_map[i][j]['nhits'])

参考Paper https://link.springer.com/chapter/10.1007/3-540-44499-8_8

关键漏洞在我们的

1
2
3
4
5
6
7
def mon_pro(self, a_n, b_n):
t = a_n * b_n
u = (t + (t * self.n_inv % self.r) * self.n) >> self.k
if u > self.n:
u -= self.n
return u

我们梳理一下

随后再考虑对进行约简 ,我们可以控制的是输入的 ,后续的 都是由第一次的计算结果递推而来,同时由于

1
2
P=Montgomery(p,bits)
Q=Montgomery(q,bits)

我们实际上用的是模数 所以说我们很难做到通过控制的来直接简单的估计最终进行约简比较的的范围 这计算很复杂 但是我们侧信道主要的时间开销差异也就是在

1
2
if u > self.n:
u -= self.n

而我们获得的total_time统计是混在一起的 所以说第一步我们需要把这里的Reduction_Line找出来 也就是剥离其他无关操作的影响

我们传入一个很小的数 0就不错 然后再一个很大的数 建议和的数量级接近 这样我们就能找到对大小最敏感的这一行的取值

剥离了噪音的影响 接下来我们的每次选择明文攻击都能直接揭示输入明文和其中模数之间的大小关系

也就是 guessbit为0或者1会对我们的产生巨大的影响 从而在我们的约简行中产生巨大的开销变化 但是这里不能精确观察到每一位Bit对我们的数据的影响 但是可以通过反复的假设来确定某一位的比特 600次轮询足够我们获取到超过550位的比特信息 剩下的地位交给CopperSmith

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209

from pwn import *
import ast
import time

HOST = '117.21.200.176'
PORT = 26057
RECOVER_BITS = 590
THRESHOLD = -80

context.log_level = 'info'

def solve():
# [Init] 连接
try:
io = remote(HOST, PORT)
except Exception as e:
log.error(f"连接失败: {e}")
return

log.info("接收公钥中...")
while True:
line = io.recvline().decode().strip()
if line.startswith('('):
n, e = ast.literal_eval(line)
break
log.success(f"N bits: {n.bit_length()}")

r_inv = inverse_mod(1 << 1024, n)
interaction_count = 0

def probe(val_int):
nonlocal interaction_count
try:
io.recvuntil(b"> ", timeout=5)
io.sendline(str(val_int).encode())

line = io.recvline().decode().strip()
interaction_count += 1

if not line: return {}
if '{' in line:
line = line[line.find('{'):]

return ast.literal_eval(line)
except Exception as e:
return {}

log.info("校准侧信道...")

d0 = probe(0)
payload_max = ((n - 1) * r_inv) % n
d1 = probe(payload_max)

leak_line = None
highest_diff = -1

unique_lines = set(d0.keys()) | set(d1.keys())
for k in unique_lines:
h0 = d0.get(k, (0,0))[1]
h1 = d1.get(k, (0,0))[1]
diff = h1 - h0
if diff > highest_diff:
highest_diff = diff
leak_line = k

baseline_hits = d0.get(leak_line, (0,0))[1]

log.success(f"Leak Line: {leak_line}")
log.info(f"Base Hits (Zero): {baseline_hits}")
log.info(f"Max Diff: {highest_diff}")

if highest_diff < 50:
log.warning("信噪比过低,可能失败")

log.info(f"开始恢复高位...")

recovered = 0
current_hits = baseline_hits

pbar = log.progress('Recovering')

for b in range(1023, 1023 - RECOVER_BITS, -1):
cand = recovered | (1 << b)
payload = (cand * r_inv) % n

stats = probe(payload)
obs_hits = stats.get(leak_line, (0, 0))[1]

diff = obs_hits - current_hits

if diff > THRESHOLD:
recovered = cand
current_hits = obs_hits
else:
pass

if (1023 - b) % 20 == 0:
pbar.status(f"Bits: {1023-b} | Hex: {hex(recovered)}...")

pbar.success("Done")
log.info(f"Recovered: {hex(recovered)}")

left = 600 - interaction_count
if left > 0:
log.info(f"消耗剩余 {left} 次查询...")
for _ in range(left):
probe(0)

log.info("运行 Coppersmith...")

p_high = recovered
unknown_bits = 1024 - RECOVER_BITS

P = PolynomialRing(Zmod(n), 'x')
x = P.gen()
f = p_high + x
f = f.monic()

try:
roots = f.small_roots(X=2**(unknown_bits + 15), beta=0.49, epsilon=0.03)

if roots:
p_cand = int(p_high + roots[0])
log.success(f"找到 p: {p_cand}")

if n % p_cand == 0:
log.success("验证成功,获取 Flag...")
io.recvuntil(b"can you break me?")
io.sendline(str(p_cand).encode())
flag = io.recvall().decode().strip()
print("\n" + "="*40)
print(flag)
print("="*40 + "\n")
else:
log.failure("p 验证失败")
else:
log.failure("未找到根,请检查恢复的高位是否正确 (是否为 0xee...)")

except Exception as e:
log.error(f"Coppersmith Error: {e}")

io.close()

if __name__ == "__main__":
solve()

'''

[x] Opening connection to 117.21.200.176 on port 26057
[x] Opening connection to 117.21.200.176 on port 26057: Trying 117.21.200.176
[+] Opening connection to 117.21.200.176 on port 26057: Done
[*] 接收公钥中...
[+] N bits: 2048
[*] 校准侧信道...
[+] Leak Line: 48
[*] Base Hits (Zero): 0
[*] Max Diff: 1042
[*] 开始恢复高位...
[x] Recovering
[x] Recovering: Bits: 0 | Hex: 0x8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...
[x] Recovering: Bits: 20 | Hex: 0xf58c100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...
[x] Recovering: Bits: 40 | Hex: 0xf58c1458f5800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...
[x] Recovering: Bits: 60 | Hex: 0xf58c1458f5d43538000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...
[x] Recovering: Bits: 80 | Hex: 0xf58c1458f5d4353d738e80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...
[x] Recovering: Bits: 100 | Hex: 0xf58c1458f5d4353d738ec00ef800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...
[x] Recovering: Bits: 120 | Hex: 0xf58c1458f5d4353d738ec00efb69ab8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...
[x] Recovering: Bits: 140 | Hex: 0xf58c1458f5d4353d738ec00efb69abbcac380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...
[x] Recovering: Bits: 160 | Hex: 0xf58c1458f5d4353d738ec00efb69abbcac3fd10e800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...
[x] Recovering: Bits: 180 | Hex: 0xf58c1458f5d4353d738ec00efb69abbcac3fd10edf2ee8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...
[x] Recovering: Bits: 200 | Hex: 0xf58c1458f5d4353d738ec00efb69abbcac3fd10edf2eef26af00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...
[x] Recovering: Bits: 220 | Hex: 0xf58c1458f5d4353d738ec00efb69abbcac3fd10edf2eef26af72184000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...
[x] Recovering: Bits: 240 | Hex: 0xf58c1458f5d4353d738ec00efb69abbcac3fd10edf2eef26af72184115340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...
[x] Recovering: Bits: 260 | Hex: 0xf58c1458f5d4353d738ec00efb69abbcac3fd10edf2eef26af72184115344eeaf80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...
[x] Recovering: Bits: 280 | Hex: 0xf58c1458f5d4353d738ec00efb69abbcac3fd10edf2eef26af72184115344eeafe63b9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...
[x] Recovering: Bits: 300 | Hex: 0xf58c1458f5d4353d738ec00efb69abbcac3fd10edf2eef26af72184115344eeafe63b92f65d8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...
[x] Recovering: Bits: 320 | Hex: 0xf58c1458f5d4353d738ec00efb69abbcac3fd10edf2eef26af72184115344eeafe63b92f65dc442180000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...
[x] Recovering: Bits: 340 | Hex: 0xf58c1458f5d4353d738ec00efb69abbcac3fd10edf2eef26af72184115344eeafe63b92f65dc4421d4bd4800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...
[x] Recovering: Bits: 360 | Hex: 0xf58c1458f5d4353d738ec00efb69abbcac3fd10edf2eef26af72184115344eeafe63b92f65dc4421d4bd48ad4f8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...
[x] Recovering: Bits: 380 | Hex: 0xf58c1458f5d4353d738ec00efb69abbcac3fd10edf2eef26af72184115344eeafe63b92f65dc4421d4bd48ad4fe9ff780000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...
[x] Recovering: Bits: 400 | Hex: 0xf58c1458f5d4353d738ec00efb69abbcac3fd10edf2eef26af72184115344eeafe63b92f65dc4421d4bd48ad4fe9ff78b5cc000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...
[x] Recovering: Bits: 420 | Hex: 0xf58c1458f5d4353d738ec00efb69abbcac3fd10edf2eef26af72184115344eeafe63b92f65dc4421d4bd48ad4fe9ff78b5cc263958000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...
[x] Recovering: Bits: 440 | Hex: 0xf58c1458f5d4353d738ec00efb69abbcac3fd10edf2eef26af72184115344eeafe63b92f65dc4421d4bd48ad4fe9ff78b5cc2639594d6980000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...
[x] Recovering: Bits: 460 | Hex: 0xf58c1458f5d4353d738ec00efb69abbcac3fd10edf2eef26af72184115344eeafe63b92f65dc4421d4bd48ad4fe9ff78b5cc2639594d69fa2cd800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...
[x] Recovering: Bits: 480 | Hex: 0xf58c1458f5d4353d738ec00efb69abbcac3fd10edf2eef26af72184115344eeafe63b92f65dc4421d4bd48ad4fe9ff78b5cc2639594d69fa2cdb0f920000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...
[x] Recovering: Bits: 500 | Hex: 0xf58c1458f5d4353d738ec00efb69abbcac3fd10edf2eef26af72184115344eeafe63b92f65dc4421d4bd48ad4fe9ff78b5cc2639594d69fa2cdb0f9206f4c80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...
[x] Recovering: Bits: 520 | Hex: 0xf58c1458f5d4353d738ec00efb69abbcac3fd10edf2eef26af72184115344eeafe63b92f65dc4421d4bd48ad4fe9ff78b5cc2639594d69fa2cdb0f9206f4ce0943800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...
[x] Recovering: Bits: 540 | Hex: 0xf58c1458f5d4353d738ec00efb69abbcac3fd10edf2eef26af72184115344eeafe63b92f65dc4421d4bd48ad4fe9ff78b5cc2639594d69fa2cdb0f9206f4ce09438f1198000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...
[x] Recovering: Bits: 560 | Hex: 0xf58c1458f5d4353d738ec00efb69abbcac3fd10edf2eef26af72184115344eeafe63b92f65dc4421d4bd48ad4fe9ff78b5cc2639594d69fa2cdb0f9206f4ce09438f119b03c700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...
[x] Recovering: Bits: 580 | Hex: 0xf58c1458f5d4353d738ec00efb69abbcac3fd10edf2eef26af72184115344eeafe63b92f65dc4421d4bd48ad4fe9ff78b5cc2639594d69fa2cdb0f9206f4ce09438f119b03c7085a1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...
[+] Recovering: Done
[*] Recovered: 0xf58c1458f5d4353d738ec00efb69abbcac3fd10edf2eef26af72184115344eeafe63b92f65dc4421d4bd48ad4fe9ff78b5cc2639594d69fa2cdb0f9206f4ce09438f119b03c7085a16f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
[*] 消耗剩余 8 次查询...
[*] 运行 Coppersmith...
[+] 找到 p: 172429097507410753749360324069434774573326056285643619159530839220089684384284358252227573873460944498379010389385877801096996482383940540323712964002238748452591206174311356557104350281715335630645695769432958177929339447767743089610062182703951377113392046400256995866469372313962751823450782043260038939907
[+] 验证成功,获取 Flag...
[x] Receiving all data
[x] Receiving all data: 2B
[x] Receiving all data: 47B
[+] Receiving all data: Done (47B)
[*] Closed connection to 117.21.200.176 port 26057

========================================
> DASCTF{2f3d777c-b2c3-488b-8740-2b8c1689a3a3}
========================================



'''

All Done