Misay's blog

Back

复现了一下后面的几道题目,前面的题写的时间有点久远了,主要是我懒

Ezmatirx#

题干

LFSR问题 考虑使用BM算法 来恢复抽头Secret_T,板子如下

然后lfsr逆不出来,美美不会了 ,仔细一想BM算法好像要求你有的输出序列是状态n的至少两倍,这里只有251个,估计不够的,反正输出也就是01串,直接爆破这五位不就行啦 然后检测一下 下标有小于0或者大于128的丢掉就行 然后对获得的taps拿来逆lfsr exp

b'e4sy_lin3ar_sys!'
b'e4sy_lin3ar_sys!'
b'e4sy_lin3ar_sys!'
plaintext

moectf{e4sy_lin3ar_sys!} 这是我们自己的方法 官方也给了用矩阵思路来求解的wp 话说标题都是Matrix确实该这样做的)

这里我们分析这个128位的线性反馈寄存器 把问题拓宽 在一个GF(2)GF(2)域中我们对于一个n级的lfsr 我们设它的递推公式是

ai+n=∑k=0n−1ai+kck+1 a_{i+n}=\sum\limits^{n-1}_{k=0}a_{i+k}c_{k+1} Si=(ai,ai+1,…,ai+n−1) S_i=(a_i,a_{i+1},\dots,a_{i+n-1})

对应的次态是

Si+1=(ai+1,ai+2,…,ai+n) S_{i+1}=(a_{i+1},a_{i+2},\dots,a_{i+n})

可以构建矩阵运算式

(ai,ai+1,⋯ ,ai+n−1)⋅(00⋯0c110⋯0c201⋯0c3⋮⋮⋱⋮⋮00⋯1cn)=(ai+1,ai+2,⋯ ,ai+n) (a_i, a_{i+1}, \cdots, a_{i+n-1}) \cdot \begin{pmatrix} 0 & 0 & \cdots & 0 & c_1 \\ 1 & 0 & \cdots & 0 & c_{2} \\ 0 & 1 & \cdots & 0 & c_{3} \\ \vdots & \vdots & \ddots & \vdots & \vdots \\ 0 & 0 & \cdots & 1 & c_{n} \end{pmatrix} = (a_{i+1}, a_{i+2}, \cdots, a_{i+n})

简记为

SiC=Si+1 S_{i}C = S_{i+1}

可见我们把这里的列放在一个无限长的直线上,对这个序列右乘矩阵CC就能实现我们的“线性移位”,同时对于每一个输出,我们都有

ai+n=Si∗(c1,c2,…,cn)T a_{i+n}=S_i*(c_{1},c_{2},\dots,c_{n})^{T}

我们把这里的

(c1,c2,…,cn) (c_{1},c_{2},\dots,c_{n})

视为未知量,当我们收集到了

a1∼a2n a_{1}\sim a_{2n}

的所有数据,我们就能构造出nn个方程

\begin{flalign} a_{1+n} &= S_1 \cdot (c_{1}, c_{2}, \dots, c_{n})^{T} & \\ a_{2+n} &= S_2 \cdot (c_{1}, c_{2}, \dots, c_{n})^{T} & \\ & \vdots & \\ a_{2n} &= S_n \cdot (c_{1}, c_{2}, \dots, c_{n})^{T} & \end{flalign}

现在我们构造满秩方程组

(S1S2⋮Sn)(c1c2⋮cn)=(an+1an+2⋮a2n) \begin{pmatrix} S_{1} \\ S_2 \\ \vdots \\ S_{n}\end{pmatrix}\begin{pmatrix}c_{1} \\ c_{2} \\ \vdots \\ c_n\end{pmatrix}=\begin{pmatrix}a_{n+1} \\ a_{n+2} \\ \vdots \\ a_{2n}\end{pmatrix}

显然左边是满秩的,乘逆矩阵就能计算出CC了 回到这题,收集的过程是不是就理所当然了呢? 来点脚本

注意这里的lfsr新位在放在后面,是左移加放位的 成功找到CC之后,我们就能

Si−1=SiC−1 S_{i-1}=S_{i}C^{-1}

美美运算找回初态,板子如下

说实话推导向右移 放最低位的也是类似的思路,这里就不多写了主要是懒

EzPack#

背包问题 题目加密流程为把flag编码为二进制01串mm 然后生成背包序列keykey,满足

ki>ki−1+ki−2+⋯+k1 k_i>k_{i-1}+k_{i-2}+\dots+k_1

然后根据这个mm串,构建

s=∑i=1nmiki s=\sum\limits^{n}_{i=1}m_ik_i

再返回

c≡  7s  mod  p c\equiv\;7^{s}\;mod\;p

那么很显然,我们先想办法解决这个离散对数问题,求解ss 对p-1进行分解,结果如下

factors = [2, 2, 2, 3, 7, 636277, 677857, 682777, 735809, 860059, 903949, 908441, 954851, 1017139, 1032341, 1163131, 1190737, 1227157, 1341323, 1395671, 1463611, 1556201, 1569401, 1713749, 1930931, 2219563, 2476283, 2477281, 2590633, 2756587, 2833643, 3095713, 3281449, 3688063, 4008793, 4285993, 5443981, 5720053, 5822981, 6201869, 6892217, 7093841, 7319857, 8227237, 9381107, 9477463, 10078729, 10084297, 10764907, 12416167, 14095651, 14294663, 14788051]
text

可见十分的光滑,直接使用sage内置的Pohlig-Hellman算法解就行,几乎是秒出

c = 1210552586072154479867426776758107463169244511186991628141504400199024936339296845132507655589933479768044598418932176690108379140298480790405551573061005655909291462247675584868840035141893556748770266337895571889128422577613223452797329555381197215533551339146807187891070847348454214231505098834813871022509186

p = 2050446265000552948792079248541986570794560388346670845037360320379574792744856498763181701382659864976718683844252858211123523214530581897113968018397826268834076569364339813627884756499465068203125112750486486807221544715872861263738186430034771887175398652172387692870928081940083735448965507812844169983643977

g = 7

R = GF(p)

x = R(c).log(g)

print("解得的 x =", x)
python

官方也给了使用Pohlig-Hellman算法的板子,在这里贴一下

F = GF(p)
a = F(7)
X = F(cipher)
n = a.order()
primes = [2^3,3,7,636277,677857,682777,735809,860059,903949,908441,954851, 1017139, 1032341, 1163131, 1190737, 1227157, 1341323, 1395671, 1463611, 1556201, 1569401, 1713749, 1930931, 2219563, 2476283, 2477281, 2590633, 2756587, 2833643, 3095713, 3281449, 3688063, 4008793, 4285993, 5443981, 5720053, 5822981, 6201869, 6892217, 7093841, 7319857, 8227237, 9381107, 9477463, 10078729, 10084297, 10764907, 12416167, 14095651, 14294663,14788051] dlogs = []
for fac in primes: 
	t = int(n//fac) 
	dlog = discrete_log(X**t, a**t) 
	dlogs += [dlog] 
	print("factor:"+str(fac)+",Discrete Log:"+str(dlog))
	
nc = crt(dlogs,primes)
print(nc)
assert pow(7,nc,p) == cipher
python

大致思路就是转化到模小因子下进行求解对数,再对结果打CRT,这里不细讲 然后就是求解这个背包了,这里是线性的,我们可以考虑如下思路 背包密码 | DexterJie’Blog ↗

OneMoreBit#

这里用的是getStrongPrime来生成的素数,具体就是pp为素数

p−12 \frac{p-1}{2}

也是大素数 而 p−1;p+1p-1;p+1光滑度很低 那么我们生成两个512位强素数p,qp,q 然后生成258位的私钥dd 保证(d,ϕ)=1(d,\phi)=1,然后反过来生成公钥指数ee 告诉你公钥(e,n)(e,n) 这里肯定不让你分解nn的 这里注意到dd不是256位而是258位,而且是由dd这样生成ee的,结合题目名字,有什么思路吗🤔 如果dd小一点我们考虑拓展维纳攻击,但是这里刚好大了一些 简单搜索之后找到了Boneh-Durfee攻击方法 mimoo/RSA-and-LLL-attacks: attacking RSA via lattice reductions (LLL) (github.com) ↗ sir,this way 梭一下脚本就能轻松解出d了,但是呢实际上标答使用的是The Verheul and van Tilborg attack 论文在这里 0811.0063 (arxiv.org) ↗ 可见就算是泄露私钥位数也是非常非常危险的

EzLCG#

xx构建了一个生成器LCG与签名系统DSA然后告诉这个的公钥(g,h)(g,h)与好几组签名的结果,(r,s)p,q,m,H(m),g,h(r,s)p,q,m,H(m),g,h,也就是说给出kik_{i},我们能快速算出rir_{i},再根据ziz_{i}我们能构建一个有关,x,k1,k2,…,k5x,k_{1},k_{2},\dots,k_{5},的方程想办法从其中恢复xx ? 我们该代入的代入,不难得到

kisi≡  (zi+ri    x)  mod  q k_{i}s_{i}\equiv\;(z_{i}+r_{i}\;\;x)\;mod\;q ki+1si+1≡  (zi+1+ri+1    x)  mod  q k_{i+1}s_{i+1}\equiv\;(z_{i+1}+r_{i+1}\;\;x)\;mod\;q

结合LCG的简易线性关系

ki+1≡  aki+b  mod  q k_{i+1}\equiv\;ak_{i}+b\;mod\;q

我们先消去bb,考虑

ki≡  aki−1+b  mod  q k_{i}\equiv\;ak_{i-1}+b\;mod\;q

即

ki+1−ki  ≡  a(ki−ki−1)  mod  q k_{i+1}-k_{i}\;\equiv\;a(k_{i}-k_{i-1})\;mod\;q

又

ki≡  si−1(zi+ri    x)  mod  q k_{i}\equiv\;s_{i}^{-1}(z_{i}+r_{i}\;\;x)\;mod\;q

代入

si+1−1(zi+1+ri+1    x)  −si−1(zi+rix)  ≡  a(si−1(zi+ri    x)  −si−1−1(zi−1+ri−1x))  mod  q s_{i+1}^{-1}(z_{i+1}+r_{i+1}\;\;x)\;-s_{i}^{-1}(z_{i}+r_{i}x)\;\equiv\;a(s_{i}^{-1}(z_{i}+r_{i}\;\;x)\;-s_{i-1}^{-1}(z_{i-1}+r_{i-1}x))\;mod\;q

我们把所有和xx有关的都放到左边,其他的放到右边,但是在这样的话,同时就有了a,xa,x两个未知量…

呃呃,好像不是这样构造的,看一下wp,

(ki+2−ki+1)(ki−ki−1)  ≡  (ki+1−ki)2  mod  q (k_{i+2}-k_{i+1})(k_{i}-k_{i-1})\;\equiv\;(k_{i+1}-k_{i})^{2}\;mod\;q

而我们又知道

ki  ≡  ui+vix  mod  p k_{i} \;\equiv\;u_{i}+v_{i}x\;mod\;p

所以由上式,我们可以得到关于xx的二次方程,考虑用coppersmith

(ui+2−ui+1+(vi+2−vi+1)x)((ui−ui−1+(vi−vi−1)x))  ≡  ((ui+1−ui+(vi+1−vi)x))2  mod  p (u_{i+2}-u_{i+1}+(v_{i+2}-v_{i+1})x)((u_{i}-u_{i-1}+(v_{i}-v_{i-1})x))\;\equiv\;((u_{i+1}-u_{i}+(v_{i+1}-v_{i})x))^2\;mod\;p

取i=1i=1即可

))

babelifting#

dd的位数的泄露,已知低400位,搜索找到博客 d低位攻击 & d高位攻击-CSDN博客 ↗ 【CTF-RSA】sage脚本_d 低位攻击 - 哔哩哔哩 (bilibili.com) ↗ 思路简述如下 已知

ed  ≡  1  mod  ϕ(n) ed\;\equiv\;1\;mod\;\phi(n)

即

ed  =1+k(p−1)(q−1)  ,(k<e) ed\;=1+k(p-1)(q-1)\;,(k<e)

两边对24002^{400}取模,得到

edl  ≡  1+k(p−1)(q−1)  mod  2400 ed_{l}\;\equiv\;1+k(p-1)(q-1)\;mod\;2^{400}

消去qq可得

edl  ≡  1+k(p−1)(np−1)  mod  2400 ed_{l}\;\equiv\;1+k(p-1)(\frac{n}{p}-1)\;mod\;2^{400}

展开一下就是

kp2+(edl−1−k(n+1))p+kn  ≡  0  mod  2400 kp^{2}+(ed_{l}-1-k(n+1))p+kn\;\equiv\;0\;mod\;2^{400}

我们枚举所有可能的k<ek<e 能得到一个关于pp的二次方程,也就是说我们能解出来p  mod  2400p\;mod\;2^{400} 再考虑coppersmith即可 注意到这里400位太高,而且nn也不大,结合题干,我们考虑HenselLifting的方法来求解 模p^k的同余方程和离散对数求解_同余多项式与crypto-CSDN博客 ↗

p = 2
k = 100
m = pow(p, k)

x = var('x')
fx = 31635333913961551790218176796 * x ^ 2 + 343355432375781642567844278672 * x + 569420970791634503307822359156

# solve the equation f(x)=0 over m=p^k
solutions = solve_mod([fx == 0], m)  
for solution in solutions:
    print(int(fx(int(solution[0]))) % m == 0) # True
python

官方的脚本貌似有点小问题,我这里跑的话会炸内存,没法按照预期跑出来,我的exp修改后如下

大概两分钟吧,全跑完数据要十分钟多

HiddenPoly#

给你了

f=∑i=015ai  rooti f=\sum\limits ^{15}_{i=0}a_{i}\;root^{i}

而且有

f≡  0  mod  q f\equiv\;0\;mod\;q

也就是

∑i=015ai  rooti  ≡  0  mod  q \sum\limits ^{15}_{i=0}a_{i}\;root^{i}\;\equiv\;0\;mod\;q

接下来我们由这个式子要尝试恢复出keykey 考虑这里的aia_{i}十分滴小,我们造个格子,先整一个运算式出来

(a0,a1,…,a15,−k)(10⋯0root001⋯0root1⋮⋮⋱⋮⋮00⋯1root1500⋯0q)=(a0,a1,…,a15,0) (a_0,a_1,\dots,a_{15},-k) \begin{pmatrix} 1 & 0 & \cdots & 0 & root^0 \\ 0 & 1 & \cdots & 0 & root^1 \\ \vdots & \vdots & \ddots & \vdots & \vdots \\ 0 & 0 & \cdots & 1 & root^{15} \\ 0 & 0 & \cdots & 0 & q \end{pmatrix}=(a_0,a_1,\dots,a_{15},0)

我们可以给格向量最后一列配一个大一点的系数,来使得右边落在最小向量中 实验一下你取k>128k>128就够用了 得到了keykey 后面就是喜闻乐见的解密了,exp如下

至此历经前前后后大几个月,moectf2024已经全部复现,写完这篇blog之后就得去准备期末了))

MoeCTF2024-复现
https://www.zt2misay2.cn/blog/moectf2024-%E5%A4%8D%E7%8E%B0
Author Misay
Published at 2025年5月12日