This vulnerability has now been fixed by the official team. Sui mainnet_v1.6.3 (August 1, 2023) has addressed this vulnerability.
Previously, our team discovered several vulnerabilities related to public blockchains. One of them was particularly interesting, so we are publicly disclosing the details. It is a denial of service vulnerability in the Sui blockchain's p2p protocol that could cause nodes in the Sui network to crash due to memory exhaustion. This denial of service vulnerability was caused by an old attack technique - the "memory bomb".
Through an introduction to this vulnerability, we hope to raise awareness and understanding of "memory bomb" attacks and defenses against them. As a leading blockchain security company, Beosin continuously monitors the security of public blockchain platforms.
The earliest memory bomb was the zip bomb, also called the zip of death, which is a malicious computer file designed to crash or incapacitate programs that read it. A zip bomb does not hijack the operation of a program, but exploits the time, disk space, or memory required to unzip a compressed file. See wikipedia--Zip_bomb
An example of a zip bomb is the file 42.zip, which is a 42KB zip file containing 16 nested zip files 5 levels deep, each bottom-level archive containing a 4.3 GB (4,294,967,295 bytes; 4 GiB - 1 B) file for a total of 4.5 PB (4,503,599,626,321,920 bytes; 4 PiB - 1 MiB) of uncompressed data.
The basic principle of a zip bomb is that we generate a very large file filled with 0s (or other values), then compress it into a zip file. Due to the high compression ratio for files with the same content, the resulting zip file is very small. When the victim decompresses the zip file, it needs to consume a huge amount of memory to store the decompressed file, quickly exhausting available memory and causing the target to crash from an out of memory error.
We can do a simple demo of this on Windows:
1. We can generate a 1GB file filled with 0s using the following command:
2. We can compress the file into a zip using 7zip:
3. The compressed file size is: 1.20 MB
From this we can see the compression ratio for a file of all 0s using zip is close to 851:1
In fact, any compression format can potentially become a memory bomb, not just zip files.
We can continue the experiment by compressing the 1GB file filled with 0s into different formats using 7zip on Windows. This gives us the following compression ratios:
Different file formats support different compression algorithms. For example, zip files can use Deflate, Deflate64, BZIP2, LZMA, PPMd etc., each with different compression ratios. The above table shows test results using the default algorithm for 7zip.
We can defend against "memory bomb" attacks by limiting the decompressed file size. The following methods can restrict the decompressed size:
- Include the decompressed data size in the archive. Read this value from the compressed file and check if the size meets requirements.
- The first method can't fully solve the problem, since the decompressed size can be spoofed. So we can pass a fixed size buffer for decompression. If the data exceeds the buffer boundary during decompression, stop and return a failure.
- Another approach is streaming decompression. Pass small chunks of the compressed data, decompressing each chunk and accumulating the decompressed size. If the size exceeds a threshold at any point, stop and return a failure.
Historical "Memory Bomb" Vulnerabilities:
This was a vulnerability in the OKHttp library. OKHttp supports the Brotli compression algorithm. If an HTTP response specified Brotli compression, due to lack of defenses against "memory bomb" attacks in OKHttp, the client could crash from memory exhaustion.
We can see the vulnerability fix limits the compression ratio.
This was a vulnerability in the Rust package manager Cargo. When downloading packages from source code repositories, Cargo did not have defenses against “memory bomb” zip files, allowing maliciously crafted zips to fill up disk space during extraction.
As we can see, the vulnerability fix limits the decompressed file size to a maximum of 512 MB.
This was a vulnerability in the popular network tool curl. The versions curl < 7.84.0 supported "chain" HTTP compression, meaning the server response could be compressed multiple times, possibly using different algorithms. The number of accepted "links" in this "decompression chain" was unlimited, allowing a malicious server to insert nearly unlimited compression steps. Using such a decompression chain could result in a "memory bomb", causing curl to ultimately spend huge amounts of memory and error due to insufficient memory.
Sui Vulnerability Description
1. In Sui's p2p protocol, some RPC messages are compressed with the snappy algorithm to reduce bandwidth pressure.
2. Every Sui node (validator or fullnode) provides node discovery ("/sui.Discovery/GetKnownPeers") and data sync ("/sui.StateSync/PushCheckpointSummary") RPC services in the p2p network. The node discovery and data sync RPC messages are actually snappy compressed data. During RPC message processing, the node first decompresses the data entirely into memory, then deserializes with the bcs algorithm, and finally releases the decompressed data and original data. The RPC data processing code is in the "crates/mysten-network/src/codec.rs" file.
3. The maximum size for RPC messages is hardcoded to 2G in the "crates/sui-node/src/lib.rs" file.
4. We can create a 1.97G snappy compressed file that decompresses to 42 G, with all file content as 0s.
5. We choose the "/sui.Discovery/GetKnownPeers" p2p RPC as the target interface, and send a 1.97G RPC message to it. The node then needs at least 42 + 1.97 = 43.97G of memory to decompress this message.
6. If the Sui node (validator or fullnode) has >43.97G of available memory, we can send n RPC messages simultaneously, so that at some point the sui node needs m (usually m < n) * 43.97G memory to process our attack payloads.
7. If memory is insufficient, the sui node will crash.
Here are the test results:
We can see the node was killed by the system due to "Out of memory".
1. Creating a "memory bomb" based on the snappy algorithm:
2. Attacking the node:
Code Analysis of the Patch
We can see the patch code utilizes streaming decompression, and limits the maximum decompressed size to 1G. It also reduces the RPC message size limit from 2G to 1G.
This vulnerability could cause individual nodes (validators and fullnodes) to crash. Exploiting it is very simple - just start multiple threads sending payloads to the node to trigger a crash, without needing to spend any gas fees. Versions before Sui mainnet_v1.6.3 (excluding) are affected.
Sui mainnet_v1.6.3 (August 1, 2023) has addressed this vulnerability.