Misay's blog

Back

Intro#

比赛地址https://ctf.xidian.edu.cn/ ↗

很棒的新生赛,去年这个时候还看不懂题,今年成功akCrypto了 大致本文就密码方向的题来进行一个Write的Up


Challenge#

密码学入门指北#

ElGamal非对称 给你了私钥 如下计算

y≡gx  mod  py\equiv g^x\;mod\;p c1≡gkmod  pc_1\equiv g^k mod\;p S≡yk  mod  pS\equiv y^k\;mod\;p c2≡mS  mod  pc_2\equiv mS\;mod\;p S≡gkx≡c1x  mod  pS\equiv g^{kx}\equiv c_1^x\;mod\;p

exp

p =
g = 2
y =
c1 =
c2 =
x =
from Crypto.Util.number import long_to_bytes
S=pow(c1,x,p)
m = inverse_mod(S,p) * c2 % p
print(long_to_bytes(m))
# b'moectf{th1s_1s_y0ur_f1rst_ElG@m@l}'
py

ez_DES#

DES作为一组对称的分组密码 使用相同的密钥进行加密解密 密钥组成是”ezdes???”我们直接穷举爆破密钥即可

exp

实际上多个不同的key都能解出一样的flag

baby-next#

pp是随机512位素数 qq是p∼p+114514p\sim p+114514后的下一个素数 直接搜索即可 这个数量级我们基本就有

p≈q≈np\approx q\approx\sqrt{n}

exp

ezBSGS#

即求解DLP

13x≡114514mod  10000000000009913^{x}\equiv 114514\mod100000000000099

sagemath有自带模数域下的离散对数方法 这里可以直接用

a = 13
b = 114514
p = 100000000000099
F = GF(p)
a = F(a)
b = F(b)
x = discrete_log(b,a)
print(x)
# 18272162371285
py

说回BSGS算法本身 是一种用空间换时间的搜索策略

对于生成元为gg,模pp的乘法群,当pp为素数 我们想求解离散对数问题

gx≡hmod  pg^{x}\equiv h \mod p

我们把想求的xx设为

x=im−jx=im-j

其中

m=nm=\sqrt{n}

nn是当前群的阶,我们想找到i  ji\;j实际上搜索上界是O(n)O(\sqrt{n})

我们有

gim≡h⋅gjmod  pg^{im}\equiv h\cdot g^{j}\mod p

注意到i  ji\;j都是相对独立的,我们可以提前计算好所有的

h⋅gj  ;  j∈(0,1,⋯ ,m−1)h\cdot g^j\;;\;j\in(0,1,\cdots,m-1)

然后对所有的

i∈(0,1,⋯ ,m−1)i\in(0,1,\cdots,m-1)

我们都可以计算gimg^{im},查哈希表 即可

ez_square#

我们需要解形似

hint=p2+q2mod  nhint=p^2+q^2\mod n

的丢番图方程 sagemath实际上有对应的方法 貌似Mini-L CTF和DASCTF2024-8 ↗都出过这种的 exp如下

方法比较多 我们来讲几个经典的

首先我们的RSA解密加密都是在模nn环上进行的 我们可以用p2p^2代掉pp 考虑构造一个解

x=p2    or    x=q2x=p^2\;\;or\;\;x=q^2

的方程 利用对称性来解 这里就和给出s=p+qs=p+q 我觉得是没有区别的

其余方法如下

sagemath里面有这种判断并且恢复nn的平方和分解的接口two_squares(),源码大致如下

大致思路是任何形如4k+34k+3的数无法表示为两个数的平方和,通过这种方式来实现快速剪枝,分类讨论

n  ≡1  mod  4n  ≡3  mod  4n\;\equiv1\;mod\;4\\n\;\equiv3\;mod\;4

的情况,在p,qp,q大小相近的时候能够快速的返回答案,因此很适合RSA问题

同时还存在一种复数域下的因数分解

还想到另一种在高斯整数环(复数域)下的分解

n=(p+qi)  ⋅  (p−qi)n = (p+qi)\;\cdot\;(p-qi)

下面的exp还是最简单的解方程的手法

直接造方程也可以 这里是简单搜索出p+qp+q 没有本质区别

ez_AES#

简化后的AES对称 直接交给GPT梭了

exp

ez_det#

给出的明文矩阵形似

M=[n11n12n13n14n15n21n22n23n24n25n31n32n33n34n35n41n42n43n44n45m0000]M = \begin{bmatrix} n_{11} & n_{12} & n_{13} & n_{14} & n_{15} \\ n_{21} & n_{22} & n_{23} & n_{24} & n_{25} \\ n_{31} & n_{32} & n_{33} & n_{34} & n_{35} \\ n_{41} & n_{42} & n_{43} & n_{44} & n_{45} \\ \color{red}{m} & \color{red}{0} & \color{red}{0} & \color{red}{0} & \color{red}{0} \end{bmatrix}

前四行是没有用的noise 后一行的第一列是我们的flag

给出密文矩阵

C=AMC=AM

且保证

det(A)=1det(A)=1

我们分析这里的代数结构

Step 1: 利用后 4 列恢复 ( A ) 的前 4 列

观察 ( M ) 的后 4 列(列 1~4,索引从 0 开始):

  • 第 5 行全为 0
  • 所以前 4 行构成了一个 4×4 子矩阵 MsubM_{\text{sub}},且已知

设:Csub=C[:,1:5]C_{\text{sub}} = C[:, 1:5](后 4 列);Msub=M[0:4,1:5]M_{\text{sub}} = M[0:4, 1:5](前 4 行,后 4 列)

由于C=AMC=AM,所以:

Csub=A⋅MsubpadC_{\text{sub}} = A \cdot M_{\text{sub}}^{\text{pad}}

但由于MsubpadM_{\text{sub}}^{\text{pad}}是 5×4 矩阵,第 5 行为 0。

因此,后 4 列的乘法实际上只涉及AA的前44列!
令 Asub=A[:,0:4]A_{\text{sub}} = A[:, 0:4] (5×4),则:

Csub=Asub⋅MsubC_{\text{sub}} = A_{\text{sub}} \cdot M_{\text{sub}}

其中MsubM_{\text{sub}} 是 4×4 可逆矩阵(题中已保证 det ≠ 0)。

于是可解:

Asub=Csub⋅Msub−1A_{\text{sub}} = C_{\text{sub}} \cdot M_{\text{sub}}^{-1}

Step 2: 利用第一列关系提取含mm向量

现在看CC的第一列(对应MM的第一列):

C[:,0]=A⋅M[:,0]=A⋅[n11n21n31n41m]=Asub⋅[n11n21n31n41]+m⋅A[:,4]C[:, 0] = A \cdot M[:, 0] = A \cdot \begin{bmatrix} n_{11} \\ n_{21} \\ n_{31} \\ n_{41} \\ m \end{bmatrix} = A_{\text{sub}} \cdot \begin{bmatrix} n_{11} \\ n_{21} \\ n_{31} \\ n_{41} \end{bmatrix} + m \cdot A[:, 4]

移项得:

m⋅A[:,4]=C[:,0]−Asub⋅[n11n21n31n41]m \cdot A[:, 4] = C[:, 0] - A_{\text{sub}} \cdot \begin{bmatrix} n_{11} \\ n_{21} \\ n_{31} \\ n_{41} \end{bmatrix}

令右边为向量vv,即:

v=C[:,0]−Asub⋅mcol1v = C[:, 0] - A_{\text{sub}} \cdot m_{\text{col1}}

此时我们有:AsubA_{\text{sub}}(5×4);v=m⋅a5v = m \cdot a_5 ,其中 a5=A[:,4] a_5 = A[:, 4] 是 AA 的第 5 列

Step 3: 构造矩阵 A′=[a1,a2,a3,a4,v]A' = [a_1, a_2, a_3, a_4, v],并计算行列式

现在构造新矩阵:

A′=[a1a2a3a4v]=[Asubv]A' = \begin{bmatrix} a_1 & a_2 & a_3 & a_4 & v \end{bmatrix} = \begin{bmatrix} A_{\text{sub}} & v \end{bmatrix}

但 v=m⋅a5v = m \cdot a_5,所以有

A′=[a1a2a3a4ma5]A' = \begin{bmatrix} a_1 & a_2 & a_3 & a_4 & m a_5 \end{bmatrix}

根据行列式性质:

det⁡(A′)=m⋅det⁡([a1a2a3a4a5])=m⋅det⁡(A)\det(A') = m \cdot \det\left( \begin{bmatrix} a_1 & a_2 & a_3 & a_4 & a_5 \end{bmatrix} \right) = m \cdot \det(A)

而题目中 make_mask 保证了:

det⁡(A)=1\det(A) = 1

因此:

m=det⁡(A′)\boxed{m = \det(A')}

exp

ezlegendre#

和去年的一样 利用二次剩余逐比特恢复即可

n≡(a+bd)emod  pn\equiv(a+bd)^emod\;p

当bb为0

n≡  aemod  pn\equiv\;a^emod\;p (np)=(aep)=(ap)e=1(\frac{n}{p})=(\frac{a^e}{p})=(\frac{a}{p})^e=1

exp

ChallengeMore#

杂交随机数#

杂糅lcg与lfsr的prng,我们梳理一下逻辑

xx是flag转二进制补全到8的倍数长,随后分成L R两个块

m是一个掩码位,b是参数 给lcg用的,随后用R对L进行LFSR处理,R自身进行一个LCG,seed是原本的L,随后交换LR,最后告诉你末态

lsfr

DFS剪枝的脚本by GPT5老师

sandtea姐姐的fufu#

背包问题 让GPT老师梭了 就不放exp了()

半^3部电台#

一个对称问题,类似魔改的DES加密Fesitel网格,块加密的思路为

block

我们能得到

R2⊕R0=f(L2,K2)R_2\oplus R_0=f(L_2,K_2) L2⊕L0=f(R0,K1)L_2\oplus L_0=f(R_0,K_1)

DES的轮函数是

f(X,K)=P(S(E(X)  ⊕  K))f(X,K)=P(S(E(X)\;\oplus\;K))

EE是一个32→4832\rightarrow48的映射,PP是一个32→3232\rightarrow32的原地置换,我们已知PP,可以得到

P−1(R2⊕R0)=S(E(L2)⊕K2)P^{-1}(R_2\oplus R_0)=S(E(L_2)\oplus K_2) P−1(L2⊕L0)=S(E(R0)⊕K1)P^{-1}(L_2\oplus L_0)=S(E(R_0)\oplus K_1)

在DES中我们的操作SS是一种对应盒中的查表操作即

Si:{0,1}6→{0,1}4S_i:\{0,1\}^6\rightarrow\{0,1\}^4

也就是对于我们这里的E:32→48E:32\rightarrow48的延展和4848位的密钥KK异或后,我们可以考虑把它分为88组,每组66位,对应到SS盒中进行一个查表,得到最终4×8=324\times8=32的输出空间

对于已知的SS,我们完全可以由已知的明文块计算出可能的E(M)⊕KE(M)\oplus K,它的可能性最多有44种,对于多个明文我们取交集即可找到这里的密钥KK,恢复我们的密钥后就正常解密即可

这里的关键点就是二轮Fesitel网络的安全性太低 我们可以通过简单的推导从已知的明文块密文块泄露大部分有关密钥的信息

同样的,exp by GPT5老师

简单分析输出后得到flagmoectf{1eEkSN!y3}

Ez_wiener#

基于连分数的Wiener攻击,思路如下

当

d<13N14d<\frac{1}{3}N^{\frac{1}{4}}

由于我们有

ed  =  1+k  ϕed\;=\;1+k\;\phi

即

eϕ−kd=1dϕ\frac{e}{\phi}-\frac{k}{d}=\frac{1}{d\phi}

我们引入Legendre's theorem

如果存在

  α∈Q,  c,d∈  Z\;\alpha\in Q,\;c,d\in\;Z

满足

∣  α−cd  ∣<12d2|\;\alpha-\frac{c}{d}\;|<\frac{1}{2d^2}

我们称cd\frac{c}{d}是α\alpha的一个有理近似

故这里,我们想想,在RSA中

N≈ϕ(N)N\approx\phi(N)

而e,Ne,N我们往往已知,能否说eN\frac{e}{N}就近似eϕ\frac{e}{\phi},是kd\frac{k}{d}的一个有理近似呢?

我们来算一下

N−ϕ=p+q−1≤3NN-\phi=p+q-1\le3\sqrt{N} ∣  eN−kd∣=ed−kNNd|\;\frac{e}{N}-\frac{k}{d}|=\frac{ed-kN}{Nd}

而

ed=1+kϕed=1+k\phi

故

∣eN−kd∣=∣1−k(N−ϕ)Nd∣≤∣k(N−ϕ)Nd∣≤∣3kdN∣|\frac{e}{N}-\frac{k}{d}|=|\frac{1-k(N-\phi)}{Nd}| \le|\frac{k(N-\phi)}{Nd}| \le|\frac{3k}{d\sqrt{N}}|

我们又知道必有kϕ<ed<dϕk\phi<ed<d\phi e<ϕe<\phi是能计算dd的前提

所以d>kd>k 推出误差限为

3N\frac{3}{\sqrt{N}}

且要满足

3N<12d2\frac{3}{\sqrt{N}}<\frac{1}{2d^2}

大概就是卡这个d∼  N14d\sim\;N^{\frac{1}{4}}

思路明确了,在这种情况下我们计算eN\frac{e}{N},就能得到一个kd\frac{k}{d}的有理近似,然后对它连分数展开

得到若干组可能的ki,dik_i,d_i,还是因为

edi=1+kiϕed_i=1+k_i\phi

那么

edi  ≡  1  mod  kied_i\;\equiv\;1\;mod\;k_i

挨个验证就能找出我们需要的dd了

exp

prime-in-prime#

我们有

p=2ga+1    q=2gb+1    h=2gab+a+bp=2ga+1\;\; q=2gb+1\;\; h=2gab+a+b

已知

n  e  gn\;e\;g

不难得到

n=pq=(4g2ab+2ga+2gb+1)=2gh+1n=pq=(4g^2ab+2ga+2gb+1)=2gh+1 h=n−12gh=\frac{n-1}{2g}

我们考虑

S=a+b≡hmod  gS=a+b \equiv h \mod g

同时

a+b=S+kga+b= S+kg

kk可以搜索,应该不大的

如果有

g  ∣  h−(a+b)g\;\mid\;h-(a+b)

说明找到了a  ba\;b

exp

貌似是RSA Common Prime Attack

ez_lattice#

矩阵运算的左乘不会影响格基的线性关系 我们的flag总是保持是最优的这个线性组合 ,题目相当于对flag矩阵进行线性组合得到C,而我们的基却直接是CC直接考虑对CC做格基归约即可

exp

p=
C=
C = Matrix(ZZ,C)
C = C.LLL()
v = C[0]
flag = b''
for i in v:
    flag += long_to_bytes(abs(i))
print(flag)
# b'moectf{h0w_P0werfu1_7he_latt1ce_1s}'
py

happyRSA#

s=p+q−1s=p+q-1

x≡(p+q)(p+q)⋯mod  (p+q−1)3x\equiv (p+q)^{(p+q)^{\cdots}}\mod (p+q-1)^3

幂塔是123456层深

尝试有

x≡(s+1)↑↑rmod  s3x\equiv (s+1)\uparrow\uparrow r\mod s^3

我们视为一个二项式的形式,也就是

x≡(s+1)Emod  s3(1)x\equiv(s+1)^E\mod s^3\tag{1}

其中我们的EE是(s+1)↑↑(r−1)(s+1)\uparrow\uparrow (r-1)

我们先考虑对(1)来展开,超过3次幂的都会被约去,也就是

x≡1+Es+E(E−1)2s2mod  s3x\equiv1+Es+\frac{E(E-1)}{2}s^2\mod s^3

我们接下来想知道EE模ss,s2s^2的值 方便我们把这里的模往下去换

显然有

s+1≡1mod  ss+1\equiv1\mod s

那么就有

E≡(s+1)↑↑(r−1)≡1mod  sE\equiv(s+1)\uparrow\uparrow(r-1)\equiv1\mod s

然后对于大于2的n∈Zn\in Z,也不难得到

(s+1)n≡1+nsmod  s2(s+1)^n\equiv1+ns\mod s^2 E≡(s+1)↑↑(r−1)≡(1+s)(s+1)↑↑(r−2)≡1+E′smod  s2E\equiv(s+1)\uparrow\uparrow(r-1)\equiv(1+s)^{(s+1)\uparrow\uparrow(r-2)}\equiv1+E^{'}s\mod s^2

我们又已经有

E′≡1mod  sE^{'}\equiv1\mod s

也就是

E′=ks+1E^{'}=ks+1

带入即可得

E≡1+smod  s2E\equiv1+s\mod s^2

从我们已有的信息 有

E=1+ksE=1+s+ts2E=1+ks\\E=1+s+ts^2

带入上式 大于3的次方消掉 就得到了

x≡1+s+s2mod  s3x\equiv1+s+s^2\mod s^3

然后解ss,求p  qp\;q,exp

ezhalf_gcd#

给了你

encd≡demod  nenc_d\equiv d^e \mod n encϕ≡ϕemod  nenc_{\phi}\equiv {\phi}^e \mod n

考虑恢复出我们的dd

我们已知

ed=1+kϕed=1+k\phi

也就是说dd,ϕ\phi之间存在线性关系,我们不妨设

ϕ=f(d)\phi=f(d)

那题目就变成了

c1≡demod  nc2≡f(d)emod  nc_1\equiv d^e\mod n\\c_2\equiv {f(d)}^e\mod n

这里有k<ek<e,直接爆破,发现kk取0∼90\sim9的时候都只返回了一个常数项,带入发现解不出flag,kk取1010的时候给我们返回了一个一次多项式,sage解有点麻烦 ,手动提系数出来处理即可,exp

解方程

k1 = 13956969191637195871632957505406117751565360403440829727249072761352047425739750866240599441725739309449282190348085360109677584507525554127026445196148893160857286022203801997873156811960571737271597472086993749971283966198697191943628862781066725335706690253538900770669084526246573003464456817905257894602490888900824860753149136591999728629106864099281400347411046856634802687971218504308172469580264497048520451583896989424545232463140527591539153615957817302334587761071546151380508318892302985208301605902883263311183702458763989755391843198670020891760809561155674454979493217081297358303315754142647867287413
k2 = 17608846521747499227247968154910171731843801156227555409194280778664071883264366214940238190095425116113057138491957289339384506579980194769451841153928528442505720494339582748962879927154787429060456888699871619817359888932353097693698140571527638555084889587814391101653933403674692802280381912990231017047722784101787449714956539028428195425358869511831219379267775628816285643329918029273198098018020166399500224247055896233457476227184648878532488798022601672987527850189642016707592877060843958894268793661605698870282835092803537046968215660983366498922624712685432673765041272654998087422047424791161022662127
inv = inverse_mod(k1,n)
# print(inv)
pd = (-k2 * inv) % n
print(pd)
m = pow(enc_flag,pd,n)
print(long_to_bytes(m))
# b'moectf{N0w_y0u_kn0w_h0w_t0_g3t_th1s_fl@G__!!!!!!!!!!}'
py

神秘数字太多了#

转化为带NN的幂式求解即可

即

10N−19≡114514mod  10000000000099\frac{10^N-1}{9}\equiv114514 \mod 10000000000099

没什么区别

p = 10000000000099
a = 114514
t = a*9 + 1
b = 10
F = GF(p)
b = F(b)
t = F(t)
N = discrete_log(t,b)
flag = "moectf{" + str(N) + "}"
print(flag)
# moectf{7718260004383}
py

wiener++#

三元ExtendWienerAttack 直接梭别的师傅的板子

湾区杯2025出过一道非常诡异的8802048\frac{880}{2048}的二元EWA 还没看到预期解(草

ledengre_revenge#

系统比较繁,整理一下就是

part1.

给出32字节的flag,两个字节两个字节的切片,切出16块放到一个4×44\times4的矩阵中,对每个矩阵中的数,计算它对p_的勒让德符号,如果是二次剩余,代表1,不是二次剩余,代表0,最终拼起来得到一个16位的key,由这个key构造AES加密器,同时还给出了

k2e≡bmod  p_k^{2e}\equiv b\mod p_{\_}

part2.

把flag拆成左右各16字节两个块,作为text数组的初始值,

随后的操作进行10轮

​ 对块中16字节进行加密后得到enc密文,拆成16份放到4*4矩阵中,构造出matrix, 每份1字节,同时我们定义一个标记矩阵lis用来记录我们比较的结果,

​ 对于加密矩阵matrix中的每一个值,和给定的矩阵a进行一个比较,如果满足给定的大小关系,我们就给lis标记矩阵的这一个元素的这一位是1,否则是0

​ 最后对每个元素,我们丢入function,构造出一个处理后的矩阵matrix,

最后给你的是两轮比较的结果lis 以及初始的a矩阵 两端text的计算处理结果


信息很多 很杂 我们来分析一下我们有什么

  • e

  • p ,也就是function

  • p_

  • k2e≡bmod  p_k^{2e}\equiv b\mod p_{\_},考虑试试离散对数?

  • flag的长度

  • 用于比较的标准矩阵a

  • 两轮比较结果lis

  • 密文处理结果text

我们先尝试能不能通过离散对数求出kk,p_ - 1很光滑,还已知key的范围是0∼655350\sim65535,即解,exp

p_ = 71583805456773770888820224577418671344500223401233301642692926000191389937709
b = 1679283667939124174051653611794421444808492935736643969239278575726980681302
e = 65537
P = GF(p_)
b = P(b)
roots = b.nth_root(n, all=True)
for i in roots:
    if i < 65536:
        key = i
assert pow(key,2*e,p_) == b
print(key)
# 60679
py

求出来key后 我们有两点突破,首先是AES加密器相当于白盒了,其次我们会看key的生成过程,看看能不能推导出原本flag的某些信息

我们看向key的生成过程

text_=[[pow(bytes_to_long(flag[(row+col*4)*2:(row+col*4)*2+2]),-2,p_)+1 for row in range(4)] for col in range(4)]
key = 0
for row in range(4):
    for col in range(4):
        key*=2
        key+=(pow(text_[row][col],(p_-1)//2,p_)+1)%p_//2
py

把flag拆成16个块,每个块2字节,对于每两个字节的块 ,我们可以去算它的text,也就是

f_i = bytes_to_long(flag_block_i)
text_i = pow(f_i,-2,p_) + 1
py

然后key在这一位的比特说明了text_i对p_是否是二次剩余,我们很难逆向求flag 但是保留了验证flag的一个思路

随后我们分析后面的比较以及矩阵构造的过程,key已知 ,而且注意到这里的AES是ECB模式,也就是说flag的块与块之间的加密是互不干扰的,加上我们已知了

flag第一个块是moectf{?????????,此时爆破就具备一定可行性了,接着往下看,lis实际就是flag放进去验证的过程 ,但是实际中我们组合的时候满足条件的二次剩余&二次非剩余的取值还是太多 不能爆破


而且上述做法实际上没有用到题目给定的text ,于是还是尝试从终态的text结构逆向来求解这个问题

最关键的点在于函数function是否可逆?

题目给我们的素数p=251实际上满足

p=4k1+3p=3k2+2p=4k_1+3\\p=3k_2+2

因此对于function,这里计算的结果对于任何输入的x∈(0∼255)x\in(0\sim255)都是一一对应的,也就是双射

当pp取到剩下的227 239 233的时候,也都满足

p=3k+2p=3k+2

此时对于取立方的情况,是一个双射,而且我们还有一个lis数组用来限定我们,也就是说你逆向这个函数,只需要在0∼2550\sim255的范围内枚举然后带进去算即可,基本上是一一对应的,我们实现了function的逆向 实际上也就实现了系统的逆向,下面分阶段编写exp


首先根据最终的text还原我们末态的text状态

text = P(text)
roots = text.nth_root(2, all = True)
roots = [long_to_bytes(int(i)) for i in roots]
# 2 results
py

接着 我们逆向function函数

def inv_function(x,p):
    for i in range(0,256):
        if function(i,p) == x:
            return i
py

接下来只需要从终态出发,逆着走一遍过程即可,让G老师结合已有信息写了个脚本

End#

时间过的好快啊 做题的时候似乎去年那个刚刚接触CTF,接触CS的自己就在眼前,页面还是一样的 机子还是一样的 已经从下不了手逐渐到现在的ak Crypto/Reverse了,或许从单纯的加分来说,CTF的获奖难度不算是什么很有”性价比”去值得做的事情吧,但是单纯享受密码学的优雅,享受用严谨的数学推导追根溯源的过程,有时候生活,学习不就是这些简单的正反馈支撑着我们一路走来嘛

Moe年年都在办 师傅们也是一轮一轮的换代 成长 DAWN2025的新生力量们非常强 这次合力打下了rk3 加油啊

一年能让人成长很多,期待下一个一年,祝moe和西电Sec越办越好!我们明年再见!

MoeCTF2025
https://www.zt2misay2.cn/blog/moectf2025
Author Misay
Published at 2025年10月9日