CRIME 攻击:一种压缩预言攻击,由 Juliano Rizzo 和 Thai Duong 发现,编号为 CVE-2012-4929。
在压缩预言攻击中,对选定明文和未知明文的混合体使用自适应数据压缩,会导致压缩文本的长度发生内容敏感的变化,即使压缩文本本身随后被加密,这种变化也能被检测到。这可用于协议攻击,以检测注入的已知明文与消息秘密部分中的未知内容是否甚至部分相似,从而大大降低搜索秘密文本匹配项的复杂度。CRIME 和 BREACH 攻击就是利用这一现象的协议攻击示例。
CRIME 攻击允许你利用加密数据的长度,恢复客户端发送给服务器的加密数据。它不允许你恢复用于加密消息或 HTTP 请求的私钥。
许多文章解释了 CRIME 攻击的工作原理,但以下是我在互联网上找到的最佳解释:
这种攻击其实并不复杂,真正有趣的部分在于其实现与“理论”略有不同。
让我们看看文章中描述的朴素方法,这是理解其工作原理的好方法:
攻击者可以控制客户端发送的请求(例如使用 JavaScript)。目标是从秘密 Cookie 中获取信息。攻击者发送多个类似这样的请求,并检查加密数据长度:
| 请求 | 长度 |
|---|---|
| GET /cookie= DATA cookie=quokkalight | 80 |
| GET /cookie=a DATA cookie=quokkalight | 81 |
| GET /cookie=b DATA cookie=quokkalight | 81 |
| GET /cookie=. DATA cookie=quokkalight | 81 |
| GET /cookie=q DATA cookie=quokkalight | 80 |
由于 cookie=q 与秘密 Cookie 中的 cookie=quokkalight 匹配,加密数据的长度将相同,攻击者得知他已找到一个字节。
但这种方法有时会失败,并不可靠,因此我们将改用另一种方法。
首先,我们发送一个请求,其中包含我们要查找的字符,后跟一些在初始请求中不可能出现的字符,比如一些特殊字符:chr(i) + "#:/[@/&"。然后,我们再发送第二个请求,但将有效载荷反转,如下所示:"#:/[@/&" + chr(i),并比较两者的长度。如果 len(enc(req1)) < len(enc(req2)),则找到了一个字节。这种方法称为 two_tries,而且可靠得多:
攻击者找到了一个字节!
if len(enc(request1)) < len(enc(request2)):
print("found byte")
我实现的 two_tries 方法完全是递归的,但为什么呢?有时,因为压缩会匹配多个模式,所以可能会找到多个字节。
以秘密值 cookie=quokkalight 为例,如果我们运行 two_tries 算法,将得到以下结果:
result 1: cookie=quokie=quokie=quokie=quokie=quokie=
result 2: cookie=quokkalight
该算法需要遍历树中的所有路径,才能找到所有可能的解。 我们可以将所有结果看作一棵树,如下所示:

针对流密码模式的 CRIME 攻击概念验证代码位于文件 CRIME-RC4-poc.py 中。这是对先前解释的 Python 实现。
python3 CRIME-RC4-poc.py
完整演示和结果:
当 CBC 密码模式与 AES 或 DES 一起使用时,攻击不像 RC4 那样简单。由于所有内容都被分成块,攻击会稍微棘手一些(但不会太复杂)。
例如,假设我们使用带 CBC 密码模式的 AES,块将被分成 16 字节长度,如果 len(data)%16 != 0,则会在末尾添加填充。
在 CBC 模式下,务必注意,有效载荷 payload=rand 将产生 16 的长度而不是 12,因为填充会在加密之前添加到数据末尾。因此,我们之前的攻击无法奏效。
示例:
在此示例中,长度将始终相同,因为如果我们添加或删除一个字节,长度将始终相同,只有填充会改变。攻击者只能看到加密数据,他无法通过加密数据得知填充。
解决方案:利用 CBC 模式的规范,通过在 GARB 变量(位于 GET 参数中,因为攻击者控制 GET 和 POST 数据)中添加随机值,使填充长度为 1。
如果字节匹配某个模式,长度将相同;如果不匹配,长度将不同。
接下来,我们只需使用 RC4 部分中介绍的相同方法,只需在前面增加一步。
adjust_padding() 函数,以便得到长度为 1 的填充。two_tries_recursive() 函数,就能找到秘密 FLAG!python3 CRIME-cbc-poc.py
即将推出…
\ /
\ _ /
----/_\----
x--------------( . )--------------x
x|x | |_|\_/|_| | x|x
x x x x
https://www.nccgroup.trust/globalassets/our-research/us/whitepapers/ssl_attacks_survey.pdf https://github.com/cloudflare/cf-nocompress https://www.ekoparty.org/archive/2012/CRIME_ekoparty2012.pdf https://security.stackexchange.com/questions/19911/crime-how-to-beat-the-beast-successor/19914#19914
| 检索字节 q 的请求 | 长度 |
|---|
| GET /cookie=a~#:/[@/& DATA cookie=quokkalight | 81 |
| GET /cookie=~#:/[@/&a DATA cookie=quokkalight | 81 |
| GET /cookie=b~#:/[@/& DATA cookie=quokkalight | 81 |
| GET /cookie=~#:/[@/&b DATA cookie=quokkalight | 81 |
| GET /cookie=q~#:/[@/& DATA cookie=quokkalight | 80 |
| GET /cookie=~#:/[@/&q DATA cookie=quokkalight | 81 |
| 块1 | 块2 | 块3 | 长度 |
|---|
| GET /cookie= DA | TA cookie=quokka | light + PAD(11) | 48 |
| GET /cookie=a DA | TA cookie=quokka | light + PAD(10) | 48 |
| GET /cookie=b DA | TA cookie=quokka | light + PAD(10) | 48 |
| GET /cookie=. DA | TA cookie=quokka | light + PAD(10) | 48 |
| GET /cookie=q DA | TA cookie=quokka | light + PAD(11) | 48 |
| 块1 | 块2 | 块3 | 块4 | 长度 |
|---|
| GET /GARBc | ookie= DATA coo | kie=quokkalight + PAD(1) | 48 | |
| GET /GARBc | ookie=a DATA coo | kie=quokkalight | PAD(16) | 64 |
| GET /GARBc | ookie=b DATA coo | kie=quokkalight | PAD(16) | 64 |
| GET /GARBc | ookie=. DATA coo | kie=quokkalight | PAD(16) | 64 |
| GET /GARBc | ookie=q DATA coo | kie=quokkalight + PAD(1) | 48 |