CVE-2021-37136和CVE-2021-37137 - Netty解压器中的拒绝服务(DoS)

Netty解压缩器中的拒绝服务(DoS)

背景

JFrog安全研究小组最近披露了两个拒绝服务问题(cve - 2021 - 37136cve - 2021 - 37137)网状的是一种流行的客户端/服务器框架,可以快速轻松地开发网络应用程序,如协议服务器和客户端。在这篇文章中,我们将详细阐述其中一个问题——CVE-2021-37136。

谁真正受到了影响?

Netty版本4.1.0到4.1.67是脆弱的(包括)。

这些问题只影响使用Netty来解压缩用户提供的Bzip2或Snappy数据流的应用程序,例如:

public static void main(String[] args)抛出异常{Bzip2Decoder decoder = new Bzip2Decoder();//创建解压缩器final ByteBufAllocator allocator = new PooledByteBufAllocator(false);FileInputStream file = new FileInputStream("C:\\temp\\100GB.bz2");//外部输入int inputChunks = 64 * 1024;ByteBuf buf = allocator.heapBuffer(inputChunks);ChannelHandlerContext ctx = new StubChannelHandlerContext(allocator);而(缓冲区。writeBytes(file, buf.writableBytes()) >= 0) {System.out。println("Input: " + buf.capacity());译码器。channelRead (ctx, buf); // BUG, No internal resource release! buf = allocator.heapBuffer(inputChunks); decoder.channelReadComplete(ctx); }

技术故障- CVE-2021-37136

Netty使用几个解压缩器来允许开发人员解压缩来自IO通道的数据,主要是网络套接字。解压缩程序都导出类似的API:一个解码函数,接收输入缓冲区和一个输出列表,以插入解压缩的数据。在大多数解码器中,decode函数在每个数据块之后停止并返回,允许调用者处理已解码的块,但在某些解码器中不是这样的行为。

在检查Bzip2解码器时,我们注意到它包含循环并尝试在将整个文件添加到输出缓冲区之前解压缩整个文件的代码:

for(;;){//循环直到EOF -有问题…switch (currentState){…case DECODE_HUFFMAN_DATA: blockDecompressor = this.blockDecompressor;...final int blockLength = blockdecompression .blockLength();final ByteBuf uncompressed = ctx.alloc().buffer(blockLength);布尔值success = false;try {int uncByte;while ((uncByte = blockdecompression .read()) >= 0) {uncompressed.writeByte(uncByte);//读取整个块}…打破; case EOF: in.skipBytes(in.readableBytes()); // Return on EOF, not end-of-block return; } }

这种行为允许攻击者创建Bzip2zip炸弹然后让系统崩溃。

使用Bzip2文件对代码进行了测试,该文件会导致100 GB的内存使用,从而触发内存耗尽并最终导致进程崩溃。

修复问题和解决方法

没有解决这个问题的方法。Netty用户被鼓励升级到版本4.1.68这完全修补了漏洞。

Netty维护者选择通过编辑解码器函数来解决这个问题,并使其在每个块之后返回,从而允许调用者对每个小块采取所需的操作。JFrog能够验证修复后,我们的PoC无法重现崩溃(不需要从用户端调用额外的api)。

致谢

我们要感谢Netty维护者及时验证问题并修复它们。