Coppersmith 相关攻击
基本原理
Coppersmith 相关攻击与Don Coppersmith 紧密相关,他提出了一种针对于模多项式(单变量,二元变量,甚至多元变量)找所有小整数根的多项式时间的方法。
这里我们以单变量为主进行介绍,假设
模数为 N ,N 具有一个因子 $b\geq N^{\beta},0< \beta \leq 1$
多项式 F 的次数为 $\delta$
那么该方法可以在$O(c\delta^5log^9(N))$ 的复杂度内找到该多项式所有的根$x_0$,这里我们要求 $|x_0|<cN^{\frac{\beta^2}{\delta}}$ 。
在这个问题中,我们的目标是找到在模 N 意义下多项式所有的根,这一问题被认为是复杂的。Coppersmith method 主要是通过 Lenstra–Lenstra–Lovász lattice basis reduction algorithm(LLL)方法找到
与该多项式具有相同根 $x_0$
更小系数
定义域为整数域
的多项式 g,由于在整数域上找多项式的根是简单的(Berlekamp–Zassenhaus),从而我们就得到了原多项式在模意义下的整数根。
那么问题的关键就是如何将 f 转换到 g 呢?Howgrave-Graham 给出了一种思路

也就是说我们需要找到一个具有“更小系数”的多项式 g,也就是下面的转换方式

在 LLL 算法中,有两点是非常有用的
只对原来的基向量进行整数线性变换,这可以使得我们在得到 g 时,仍然以原来的 $x_0$ 为根。
生成的新的基向量的模长是有界的,这可以使得我们利用 Howgrave-Graham 定理。
在这样的基础之上,我们再构造出多项式族 g 就可以了。
关于更加细节的内容,请自行搜索。同时这部分内容也会不断更新。
需要注意的是,由于 Coppersmith 根的约束,在 RSA 中的应用时,往往只适用于 e 较小的情况。
Basic Broadcast Attack
攻击条件
如果一个用户使用同一个加密指数 e 加密了同一个密文,并发送给了其他 e 个用户。那么就会产生广播攻击。这一攻击由 Håstad 提出。
攻击原理
这里我们假设 e 为 3,并且加密者使用了三个不同的模数 $n_1,n_2,n_3$ 给三个不同的用户发送了加密后的消息 m,如下
这里我们假设 $n_1,n_2,n_3$ 互素,不然,我们就可以直接进行分解,然后得到 d,进而然后直接解密。
同时,我们假设 $m<n_i, 1\leq i \leq 3$。如果这个条件不满足的话,就会使得情况变得比较复杂,这里我们暂不讨论。
既然他们互素,那么我们可以根据中国剩余定理,可得$m^3 \equiv C \bmod n_1n_2n_3$。
此外,既然 $m<n_i, 1\leq i \leq 3$,那么我们知道 $m^3 < n_1n_2n_3$ 并且 $C<m^3 < n_1n_2n_3$,那么 $m^3 = C$,我们对 C 开三次根即可得到 m 的值。
对于较大的 e 来说,我们只是需要更多的明密文对。
SCTF RSA3 LEVEL4
参考 http://ohroot.com/2016/07/11/rsa-in-ctf。
这里我们以 SCTF RSA3 中的 level4 为例进行介绍,首先编写代码提取 cap 包中的数据,如下
其次,利用得到的数据直接使用中国剩余定理求解。
得到密文,然后再次解密即可得到 flag。
题目
2017 WHCTF OldDriver
2018 N1CTF easy_fs
Broadcast Attack with Linear Padding
对于具有线性填充的情况下,仍然可以攻击,这时候就会使用 Coppersmith method 的方法了,这里暂不介绍。可以参考
https://en.wikipedia.org/wiki/Coppersmith%27s_attack#Generalizations
Related Message Attack
攻击条件
当 Alice 使用同一公钥对两个具有某种线性关系的消息 M1 与 M2 进行加密,并将加密后的消息 C1,C2 发送给了 Bob 时,我们就可能可以获得对应的消息 M1 与 M2。这里我们假设模数为 N,两者之间的线性关系如下
其中 f 为一个线性函数,比如说 $f=ax+b$。
在具有较小错误概率下的情况下,其复杂度为 $O(elog^2N)$。
这一攻击由 Franklin,Reiter 提出。
攻击原理
首先,我们知道 $C_1 \equiv M_1 ^e \bmod N$,并且 $M_1 \equiv f(M_2) \bmod N$,那么我们可以知道 $M_2$ 是 $f(x)^e \equiv C_1 \bmod N$ 的一个解,即它是方程 $f(x)^e-C_1$ 在模 N 意义下的一个根。同样的,$M_2$ 是 $x^e - C_2$ 在模 N 意义下的一个根。所以说 $x-M_2$ 同时整除以上两个多项式。因此,我们可以求得两个多项式的最大公因子,如果最大公因子恰好是线性的话,那么我们就求得了 $M_2$。需要注意的是,在 $e=3$ 的情况下,最大公因子一定是线性的。
这里我们关注一下 $e=3$,且 $f(x)=ax+b$ 的情况。首先我们有
那么我们有
我们需要明确一下我们想要得到的是消息 m,所以需要将其单独构造出来。
首先,我们有式 1
再者我们构造如下式 2
根据式 1 我们有
继而我们有式 3
那么我们根据式 2 与式 3 可得
进而我们有
进而
进而
上面的式子中右边所有的内容都是已知的内容,所以我们可以直接获取对应的消息。
有兴趣的可以进一步阅读 A New Related Message Attack on RSA 以及 paper 这里暂不做过多的讲解。
SCTF RSA3
这里我们以 SCTF RSA3 中的 level3 为例进行介绍。首先,跟踪 TCP 流可以知道,加密方式是将明文加上用户的 user id 进行加密,而且还存在多组。这里我们选择第 0 组和第 9 组,他们的模数一样,解密脚本如下
得到明文
当然,我们也可以直接使用 sage 来做,会更加简单一点。
结果如下
题目
hitcon 2014 rsaha
N1CTF 2018 rsa_padding
Coppersmith’s short-pad attack
攻击条件
目前在大部分消息加密之前都会进行 padding,但是如果 padding 的长度过短,也有可能被很容易地攻击。
这里所谓 padding 过短,其实就是对应的多项式的根会过小。
攻击原理
我们假设爱丽丝要给鲍勃发送消息,首先爱丽丝对要加密的消息 M 进行随机 padding,然后加密得到密文 C1,发送给鲍勃。这时,中间人皮特截获了密文。一段时间后,爱丽丝没有收到鲍勃的回复,再次对要加密的消息 M 进行随机 padding,然后加密得到密文 C2,发送给 Bob。皮特再一次截获。这时,皮特就可能可以利用如下原理解密。
这里我们假设模数 N 的长度为 k,并且 padding 的长度为 $m=\lfloor \frac{k}{e^2} \rfloor$。此外,假设要加密的消息的长度最多为 k-m 比特,padding 的方式如下
消息 M2 的 padding 方式类似。
那么我们可以利用如下的方式来解密。
首先定义
其中 $y=r_2-r_1$。显然这两个方程具有相同的根 M1。然后还有一系列的推导。
Known High Bits Message Attack
攻击条件
这里我们假设我们首先加密了消息 m,如下
并且我们假设我们知道消息 m 的很大的一部分 $m_0$,即 $m=m_0+x$,但是我们不知道 $x$。那么我们就有可能通过该方法进行恢复消息。这里我们不知道的 x 其实就是多项式的根,需要满足 Coppersmith 的约束。
可以参考 https://github.com/mimoo/RSA-and-LLL-attacks。
Factoring with High Bits Known
攻击条件
当我们知道一个公钥中模数 N 的一个因子的较高位时,我们就有一定几率来分解 N。
攻击工具
请参考 https://github.com/mimoo/RSA-and-LLL-attacks。上面有使用教程。关注下面的代码
其中,
必须满足 $q\geq N^{beta}$,所以这里给出了$beta=0.5$,显然两个因数中必然有一个是大于的。
XX 是 $f(x)=q'+x$ 在模 q 意义下的根的上界,自然我们可以选择调整它,这里其实也表明了我们已知的 $q'$ 与因数 q 之间可能的差距。
2016 HCTF RSA2
这里我们以 2016 年 HCTF 中的 RSA2 为例进行介绍。
首先程序的开头是一个绕过验证的,绕过即可,代码如下
这里我们也已经得到 n,e,e2,加密后的 flag 了,如下
接下来我们来分析主程序。可以看出
我们得到的 $n=p \times q$。而 p,q 以及我们已知的 e 都在 gen_key 函数中生成。看一看 gen_key 函数
其中我们已知如下参数
首先,程序先得到了 1024 比特位的素数 p,并且 gcd(2,p-1)=1。
然后,程序又得到了一个 1024 比特位的素数 $q_t$,并且计算 $n_t=p \times q_t$。
下面多次调用了 get_bit 函数,我们来简单分析一下
可以看出根据 dire(ction) 的不同,会得到不同的数
dire=1时,程序首先计算number的二进制位数sn,如果不是 8 的整数倍的话,就将sn增大为 8 的整数倍,然后返回number右移sn-n_bit的数字。其实 就是最多保留number的n_bit位。dire=0时,程序直接获取number的低n_bit位。
然后我们再来看程序
这三个操作分别做了如下的事情
t为n_t的最多高 k/16 位,即 128 位,位数不固定。y为n_t的低 5*k/8 位,即 1280 位,位数固定。p4为 p 的最多高 5*k/16 位,即 640 位,位数不固定。
此后,程序有如下操作
利用 pi_b 对 p4 进行了加密
其中,我们已知了密钥 key,所以只要我们有密文就可以解密。此外,可以看到的是程序是对传入的消息进行 8 字节分组,采用密码本方式加密,所以密文之间互不影响。
下面
程序将 t,u,y 拼接在一起得到 n,进而,程序得到了 q,并对 q 的低 k/16 位做了抑或,然后返回 q'。
在主程序里,再一次得到了 n'=p*q'。这里我们仔细分析一下
而 p 是 k/2 位的,所以说,random 的部分最多可以影响原来的 n 的最低的 $k/2+k/16=9k/16$ 比特位。
而,我们还知道 n 的最低的 5k/8=10k/16 比特为其实就是 y,所以其并没有影响到 u,即使影响到也就最多影响到一位。
所以我们首先可以利用我们得到的 n 来获取 u,如下
虽然,这样可能会获得较多位数的 u,但是这样并不影响,我们对 u 解密的时候每一分组都互不影响,所以我们只可能影响最高位数的 p4。而 p4 的的高 8 位也有可能是填充的。但这也并不影响,我们已经得到了因子 p 的的很多部分了,我们可以去尝试着解密了。如下
解密结果如下
下面,我们直接使用 sage 来解密,这里 sage 里面已经实现了这个攻击,我们直接拿来用就好
关于 small_roots 的使用,可以参考 SAGE 说明。
结果如下
题目
2016 湖湘杯 简单的 RSA
2017 WHCTF Untitled
Boneh and Durfee attack
攻击条件
当 d 较小时,满足 $d < N^{0.292}$ 时,我们可以利用该攻击,比 Wiener's Attack 要强一些。
攻击原理
这里简单说一下原理。
首先
进而有
即
又
所以
假设 $A=\frac{N+1}{2}$,$y=\frac{-p-q}{2}$ ,原式可化为
其中
$|k|<\frac{2ed}{\varphi(N)}<\frac{3ed}{N}=3*\frac{e}{N}d<3\frac{e}{N}*N^{delta}$
$|y|<2*N^{0.5}$
y 的估计用到了 p、q 比较均匀的假设。这里 delta 为预估的小于 0.292 的值。
如果我们求得了该二元方程的根,那么我们自然也就可以解一元二次方程 $N=pq,p+q=-2y$ 来得到 p 与 q。
更加具体的推导,参考 New Results on the Cryptanalysis of Low Exponent RSA.
攻击工具
请参考 https://github.com/mimoo/RSA-and-LLL-attacks 。上面有使用教程。
2015 PlaidCTF Curious
这里我们以 2015 年 PlaidCTF Curious 为例进行介绍。
首先题目给了一堆 N,e,c。简单看一下可以发现该 e 比较大。这时候我们可以考虑使用 Wiener's Attack,这里我们使用更强的目前介绍的攻击。
核心代码如下
结果如下
2019 Defcon Quals ASRybaB
题目大概意思是,我们接收三对 RSA ,然后需要求出 d,然后对给定的数字 v[i] 加密,发送给服务器,只要时间在一定范围内,940s,即可。那难点自然在 create_key 函数了。
我们可以简单看看这个到底是在干啥
基本可以猜出来这是在生成 n,e,d,其实和我们最初的预期也差不多。我们来直接反编译一下
可以发现 STOP_CODE,有点猫腻,如果仔细看最初的反汇编的话,我们可以发现最前面的那部分代码是在混淆
一直到
前面的都没有什么作用,感觉是出题者故意修改了代码。仔细分析一下这部分代码,感觉像是两部分
正好是第 25 行和第 26 行,大概猜一猜,感觉两个都是 x=7/0,所以就想办法把这部分的代码修复一下,接下来就是定位这部分代码了。根据手册可以知道 STOP_CODE 是 0,从而我们可以定位第 25 行语句到 26 行语句为 t[6:26],他们分别都是 10 字节(6-15,16-25)。
从而我们可以修复原 code
可以看到生成的 d 是故意超了 0.292 的,不过我们可以发现 ppp 范围很小,实际上我们可以测试得到这个范围的素数为 125 个。并且
所以其实这里就乘了一个数,那么我们其实就可以枚举一下乘了什么,并修改 e1=e*ppp,其实就回归到标准的 Boneh and Durfee attack。
但是,如果我们直接使用 https://github.com/mimoo/RSA-and-LLL-attacks 的脚本也不行,必须得提高 m,基本得提到 8,这样仍然不是很稳定。
如果仔细尝试尝试的话,就会发现 e1>N,这看起来问题不大,但是原脚本里假设的数值是 e<N 的,所以我们需要进行适当的修改预估的上下界
根据上述推导,上下界应该为
$|k|<\frac{2ed}{\varphi(N)}<\frac{3ed}{N}=3*\frac{e}{N}d<3\frac{e}{N}*N^{delta}$
$|y|<2*N^{0.5}$
最后主要修改了 m 和 X 的上界
最后可以得到结果
不得不说这个题目,真的是需要多核服务器。。
参考资料
Survey: Lattice Reduction Attacks on RSA
An Introduction to Coppersmith’s method and Applications in Cryptology
Last updated