HITCTF2020 ezRSA - The learing or Coppersmith attack
关于出去玩只能在手机上用Sage Cell Server做题那件事
也是好久没写博客了, 刚好学习一下coppersmith attack
先把题目放上来吧
1 | #! /bin/bash python2 |
做这个之前, 先来看看coppersmith attack(直接翻CTF wiki
对于单变量的方程(多变量的还没接触过, 能否使用coppersmith attack 就看变量是否满足上面这部分所提到的约束.
来分析一下这些约束, 对于一般的RSA列出模N意义下的多项式方程求解根的时候, 因为N往往是两个大素数的乘积, 那么N必定会有一个因子
但是有需要注意的是, 有时候求解根并不是在模N的意义下进行的, 这个时候就需要慎重的考虑一下
而对于
所以, 判断是否可以使用coppersmith attack, 就看需要解的根是否足够小(一般通过题目所给的信息来判断根的位数, 再通过e 和 N 的位数,来判断是否可以使用coppersmith attack
需要注意的是!由于LLL是启发式算法, 所以有的时候解出来的根会不满足约束, 也就是说当需要解的根近乎足够小就可以试试coppersmith了
现在回到题目, 先来分析一下题目
这题先对flag进行了一次填充flag = flag+os.urandom(32)
, 如果flag太小是可能直接解出来的.
然后就是对明文进行加密,再进行一次填充再加密, 写成式子就是
其实可以令M=2^64^m 和
两个方程, 两个未知数, 肯定是可以解出根来的, 只不过是难不难解出来的问题了. 注意到这里的
事实上解
Coppersmith’s short-pad attack
wiki上说的也很清楚了, 在对明文进行填充的时候, 如果填充的
我们先把两个方程化成只有一个未知数
然后用small_root()
求解
1 | C1 = 80653989110793139102855968265870741534421660712327094406252902072101613222389965470648960909763762225046314865847982289607336162281576790259047039000290839621007818742162307587677505606906923990312494483089046762906753345262127057162580025978324312642501118741099945205580088180943278903718853065363662232083 |
这里的small_root()
的参数很重要, X是设置根的上界的, 这个要尽可能的接近根的大小, 这样求解出来的可能性才高. 而beta一般0.4~0.6就行了.
接下来就是算M了, 这个又是另外一个method - Franklin-Reiter related-message attack
Franklin-Reiter related-message attack
先来看看wiki上怎么说
通俗一点就是, 当两个明文满足线性关系
的一个公因式, 因此可以利用在多项式的欧几里得算法算出这个公因式
1 | x = PRx.gen() |
M算出来了别忘了除一个2^64(一开始为了方便计算所以把m放大了, 还好不影响解题, 以后做的时候要小心为了方便计算导致算不出根来, 所以最后的代码是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
42C1 = 80653989110793139102855968265870741534421660712327094406252902072101613222389965470648960909763762225046314865847982289607336162281576790259047039000290839621007818742162307587677505606906923990312494483089046762906753345262127057162580025978324312642501118741099945205580088180943278903718853065363662232083
C2 = 5400424653941721880728309040044485787870754570249463205700803061685717472238274158687499478247752712211743180931379853481727502849946080245130393042405383007613277703993980940893569303012323853427216643473698166348237252515222556282004058588218846910754415888401275689026778751805826968590155607937830708498
n = 92782661709340169703868140576276816382956055756557631391697803785121887338308072309948803413610339884338861040226250478895118923994109662815448681629315227440953320952623296140315432654804940766553284237954507627610922864055435652884184926768295740697589798180602153344302964255974935777945481843144629875127
C1=(C1*2**192)%n
e = 3
n1 = n
PRxy.<x,y> = PolynomialRing(Zmod(n1))
PRx.<xn> = PolynomialRing(Zmod(n1))
PRZZ.<xz,yz> = PolynomialRing(Zmod(n1))
g1 = x**e - C1
g2 = (x + y)**e - C2
q1 = g1.change_ring(PRZZ)
q2 = g2.change_ring(PRZZ)
h = q2.resultant(q1)
h = h.univariate_polynomial()
h = h.change_ring(PRx).subs(y=xn)
h = h.monic()
roots = h.small_roots(X=2**64, beta=0.4)
diff = roots[0]
x = PRx.gen()
g1 = x**e - C1
g2 = (x + diff)**e - C2
while g2:
g1, g2 = g2, g1 % g2
g = g1.monic()
M = -g[0]
h =hex(M*inverse_mod(2**64,n))[2:]
s=""
for i in range(0,len(h),2):
s+=chr(int(h[i:i+2],16))
print(s)
# s = HITCTF2020{dde65d8adf22b5e1a0c0c10eff23c24c}
一下子学了两个方法好爽啊, 在看到e很小的时候, 一定要想起coppersmith来.
不过这些应该都算是基础的, 特别是coppersmith的使用感觉还有很多很深奥的地方,