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

背景
JFrog安全研究团队最近披露了两个拒绝服务问题(cve - 2021 - 37136,cve - 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文件= 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函数,接收输入缓冲区和一个输出列表,以插入解压缩的数据。在大多数解码器中,decode函数在每个数据块之后停止并返回,允许调用者处理已解码的数据块,但在某些解码器中,这不是这种行为。
在检查Bzip2解码器时,我们注意到它包含循环的代码,并试图在将其添加到输出缓冲区之前解压缩整个文件:
for(;;){//循环直到EOF -有问题…switch (currentState){…case DECODE_HUFFMAN_DATA: blockDecompressor = this.blockDecompressor;...final int blockLength = blockdecompresor .blockLength();final ByteBuf uncompressed = ctx.alloc().buffer(blockLength);布尔成功= false;try {int uncByte;while ((uncByte = blockDecompressor.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维护人员对这些问题的验证和及时修复。
