Apache Killer (CVE-2011-3192): How It Works and How to Test

A tiny sliver of input ballooning into a huge stack of swollen memory blocks, illustrating the memory amplification behind Apache Killer

· 13 min read

Apache Killer is the rare denial-of-service attack that needs almost no traffic to work. One small GET request, carrying a Range header that asks for dozens of overlapping slices of the same file, can push a vulnerable Apache HTTP Server to allocate the response body in memory over and over until the process runs out of room. The flaw is old and it has a name and a number: CVE-2011-3192, disclosed in August 2011.

That age is why it still belongs in a testing programme. The vulnerability is patched in every current Apache build, so the question is no longer “can this hurt me” but “am I actually running what I think I am running, everywhere, including the forgotten appliance and the vendor box nobody has rebuilt in years.” Apache Killer is a clean way to ask, because the server’s own reply is the answer.

The short version

  • It is a memory attack, not a volume attack. The damage is per-request amplification of heap and resident memory, not gigabits or requests per second, so a low request rate can exhaust an unpatched server.
  • The weapon is a forced Range header. Each request asks for many overlapping byte ranges of one file, and a vulnerable server allocates a separate copy of the body for every range.
  • The affected versions are specific and known. Apache HTTP Server 1.3.x, 2.0.x through 2.0.64, and 2.2.x through 2.2.19. The fix shipped in 2.2.20 on 30 August 2011.
  • This is the one attack in the series a WAF can genuinely catch. The overlapping-range pattern is a fixed signature, not traffic that merely looks legitimate, so a tuned rule can block it before it reaches the server.
  • The response category is the finding. How your server answers a single crafted request tells you whether you are patched, whether something upstream is rejecting it, or whether you are exposed.

This is one post in a series covering each of the ten simulation types Obsidio runs, one per attack. They fail in genuinely different places, which is the reason a test programme needs coverage across the categories rather than volume in one of them. For how they fit together and how to structure a first run, start with our guide on how to test your DDoS protection.

The ten simulation types

One post each, grouped the way the platform groups them.

Application-layer floods

Slow attacks

Connection exhaustion

Protocol-specific and scripted

What an Apache Killer attack actually does

The HTTP Range header exists for a good reason. It lets a client ask for part of a file rather than the whole thing, which is how a paused download resumes and how a video player fetches only the segment it is about to play. A well-formed request says Range: bytes=0-1023 and gets back the first kilobyte, and the specification even lets a client ask for several ranges at once.

Apache Killer abuses that last part. It sends a request whose Range header lists many overlapping byte ranges of the same file, something like bytes=0-1,5-1,5-2,5-3, and so on. A vulnerable server takes the list literally and allocates a separate buffer for every range in it. Because the ranges overlap and repeat, a tiny file gets materialised in memory many times over. The request costs the attacker almost nothing to send; the reply costs the server a multiple of the file size in heap and resident memory to assemble.

That is why the attack behaves so differently from a flood. It does not lean on bandwidth or request rate. It leans on memory, so a handful of these requests in parallel can drive an unpatched httpd process into exhaustion while the traffic graph barely moves.

The plain-language version: imagine ordering a single page from a librarian, but asking for it sliced into fifty mostly-overlapping pieces. The librarian photocopies the page fifty times to assemble your answer. Do that a few times at once and the librarian runs out of paper, even though you only ever asked about one page.

Which of your controls should have caught this

It is worth walking the whole chain a request passes through, because the answer here is unusual for this series. Three groups matter: what sits in front, what absorbs whatever gets through, and whether anything tells you it happened.

Zone 1

Should any of these have stopped it?

  • DDoS protection and scrubbing. Waits for a traffic spike. This attack does not produce one, so there is nothing for it to trigger on.
  • Firewall and WAF. The exception in the series, and worth saying plainly. The overlapping-range pattern is a known signature, not traffic that only looks legitimate, so a tuned rule genuinely can match it and block the request. That works only if the rule is present and current, and many deployments carry none.
  • Rate limiting. Counts requests. This sends far too few to cross a threshold, because the amplification is inside each request, not in their number.
  • Bot detection and challenges. It is a plain GET with no page load and no session to profile, so there is nothing to challenge.
  • CDN or fronting cache. A CDN that normalises or coalesces ranges shields the origin. One that forwards the Range header untouched does not. Worth confirming which yours does.

Zone 2

What takes the hit?

  • Load balancer or reverse proxy. Absorbs the attack if it coalesces or rejects egregious range sets before forwarding. Worth confirming yours does rather than passing the header through.
  • Connection layer. Not the pressure point. The attack reuses a few connections and concentrates the load on memory, not sockets.
  • Web server. Where it bites, and only on a vulnerable Apache build. Resident memory climbs with every overlapping-range request until the process cannot allocate more.
  • Application and database. Never reached. The body is assembled in the server’s byte-range handling before any application logic runs.
  • Auto-scaling. Keys on request rate or CPU, neither of which spikes. Memory climbs quietly on one host, so a rate-based policy never scales.

Zone 3

Would you find out?

  • Dashboards. Requests per second look normal, even low. The strain is in memory, which is not where most traffic dashboards point.
  • A check from outside your network. The single most useful signal here. The response to one crafted request tells you plainly whether you are patched.
  • Logging and your SIEM. These requests complete, so unlike a slow attack they do leave access-log entries. But nothing flags an odd Range header unless someone wrote a rule for it.
  • Alerting. Nothing crosses a request-rate or bandwidth threshold.
  • On-call. If the process runs out of memory, host-level monitoring may page someone for a crash or restart, even though nothing recognised the attack behind it.

Purple marks what only a test on your own infrastructure can settle. Everything else follows from how the attack works, not from how well your team configured things.

The picture here is less bleak than for most attacks in the series, and that is the honest point: a patched server and a tuned edge rule really can shut this down. The risk is not that the attack is unstoppable, but that you assume you are patched everywhere and have never proved it.

The one request that tells you whether you are patched

Apache Killer has an unusually clean diagnostic property. You do not need to overwhelm anything to learn where you stand. Send the crafted request and read the reply, because the response category maps directly to your state.

A patched server refuses to play along. Faced with a set of overlapping ranges that would cost more than the file is worth, it ignores them and returns the complete file with a normal 200 response, or it rejects the request outright. An unpatched server does the dangerous thing: it returns a multipart range response with one part per requested range, which is the full amplification in action. A rejection by an upstream proxy or hardened stack, refusing the oversized header before it reaches the origin, is a third and equally informative outcome. Each is a different, readable answer to the same question.

In the Obsidio simulation this is driven by two parameters. rangeCount is the amplification knob: it sets how many overlapping byte-range entries each request carries, and a vulnerable server allocates one response copy per entry. Its default is a deliberately mild 10, enough to demonstrate the effect without straining anything. Raise it in steps rather than jumping to the maximum, and watch which response category comes back at each one. A count in the hundreds stresses an unpatched server hard; a very large count may simply be refused by a modern stack, which is itself a useful signal. The second parameter, parallelRequestsPerWorker, defaults to 20 and sets how many run at once, multiplying the memory copies in flight without changing the per-request amplification.

One detail matters for reading results: the Range header is computed from rangeCount and forced onto every request. You cannot override it, because it is the attack. Anything in your own headers sits alongside it.

How to defend against Apache Killer

Defence starts with the version number and works outward from there. Each layer is verifiable, which is the useful part.

  • Patch level, first and always. The fix for CVE-2011-3192 shipped in Apache HTTP Server 2.2.20 on 30 August 2011. Its changelog entry is exact: the server now handles byte-range requests using less memory, and “if the sum of all ranges in a request is larger than the original file, ignore the ranges and send the complete file.” A follow-up in 2.2.21 corrected a regression the first fix introduced. Any current Apache release is well past all of this, so the work is confirming that every server actually is current, appliances and vendor-shipped instances included.
  • Range-handling limits. Modern Apache exposes three directives that cap abusive range sets directly. MaxRanges limits the number of ranges before the server returns the complete resource instead, defaulting to 200. MaxRangeOverlaps caps overlapping ranges and MaxRangeReversals caps out-of-order reversals, both defaulting to 20. All three arrived in the 2.3.15 development line and are present in current stable builds. When a request exceeds a limit, the server sends the whole file rather than honouring the ranges, which removes the amplification.
  • A tuned WAF rule. Because the overlapping-range pattern is a fixed signature, a rule that recognises an abusive Range header can block the request before it reaches the origin. This is what makes Apache Killer the honest exception in this series. Worth having as a second line even on patched servers, but only as good as its currency.
  • Coalescing at the proxy or CDN. The HTTP specification itself says a server may ignore, coalesce, or reject range requests asking for more than two overlapping ranges or many small ranges out of order, because those signal a broken client or a deliberate denial-of-service attempt. A proxy or CDN that does this on your behalf shields the origin, provided the origin cannot be reached directly.

Each of these is a setting or a version string somewhere, which means each can be stale, missing on one host, or overridden by a change nobody re-checked.

What you can check yourself, and what it will get wrong

Apache Killer is the one attack in this series where a self-check is genuinely worth a lot. Two checks you can run today:

Read the version and the config. Confirm the Apache build on each host and check whether the range-handling directives are set. This tells you the setting exists and the version is current on the box you looked at.

Send one request to staging and read the reply, with change-management sign-off on infrastructure you own. The diagnostic lives in the response itself rather than in whether the server fell over, so you learn the true state of that one endpoint immediately.

The trap is not that the self-check misleads you about the endpoint you tested. It is what a single source cannot see. One request from one machine tells you nothing about the endpoints you did not think to test, and it is the forgotten ones, the legacy appliance and the unrebuilt vendor box, that carry the risk. Nor does it tell you whether anyone would notice memory climbing during a sustained run. A single request answers the version question. It does not answer the coverage question or the detection question, and those are the ones a real programme has to close.

How Obsidio tests it

Obsidio runs Apache Killer as a controlled, authorized simulation against infrastructure you own. Domain ownership is verified by a DNS TXT record before any traffic flows. Runs ramp up gradually, starting from the mild default range count and raising it in steps, and any run can be aborted live. You choose the range count and concurrency, then watch how each endpoint answers as the pressure rises. Because load comes from 100,000+ globally distributed real devices rather than a handful of datacenter instances, your estate is probed the way a real attacker would, not from a single predictable source your filters would trivially catch.

The thing to watch is the response category, not the request-rate graph, which stays low even while the attack is working. What matters is the mix of replies: a clean complete-file response or a rejection means that endpoint is holding, and a multipart range response means it is amplifying and exposed. Watching that mix shift as the range count climbs is the whole point of the run.

There is an honest split in what a test can measure. Obsidio measures the response category and edge behaviour from outside, because those are visible from the client side of the connection. Whether resident memory actually climbed on the host, whether your SIEM recorded the burst of range requests, and whether anyone was paged when a process restarted are answers that live only on your own consoles. Have someone watching them during the window, so the internal and external pictures line up into one finding.

Strength is proven, not promised. Apache Killer does not test your bandwidth. It tests whether the version you believe you are running is the version answering the request.

Where this fits in a testing programme

Apache Killer sits in the application-layer group alongside HTTP Flood, GoldenEye and Browser Flood, but it is the odd one of the four. The floods win on volume and hit request-processing capacity. Apache Killer wins on a specific implementation flaw and hits memory with almost no volume at all. A programme that only runs floods measures how much traffic your stack can take, but never asks the version-and-coverage question this attack answers, so that whole class of exposure goes unmeasured.

For regulated institutions, the test also has to leave a record. Obsidio produces cryptographically attested, tamper-evident reports mapped to FINMA, DORA and NIS2, generated inside Trusted Execution Environments, so the result of a run is an artifact you can file rather than a screenshot you have to vouch for. For an attack whose entire finding is which of your servers answered which way, a verifiable record of exactly that is worth having.

To scope an authorized Apache Killer simulation against your own infrastructure, see the Obsidio platform or get in touch with the team. Independent, neutral, verifiable: resilience you can prove.

← Back to Blog