Varol Cagdas Tok

Personal notes and articles.

Low-and-Slow Attacks

Most denial of service defenses are calibrated to high-volume traffic. Rate limiting triggers at high request rates. Anomaly detection looks for statistical deviations from traffic baselines. DDoS scrubbing infrastructure is designed to absorb or discard large traffic volumes. These defenses share a common assumption: attacks are distinguishable from legitimate traffic by their volume.

Low-and-slow attacks are designed specifically to violate this assumption. They achieve state exhaustion without generating traffic volumes that would trigger volume-based detection. An attack in this category may arrive at rates indistinguishable from normal user traffic, yet consume server resources that eventually prevent legitimate requests from being served. The distinguishing characteristic is not the traffic volume but the resource holding pattern: connections that stay open much longer than legitimate connections, resources held without productive progress, or state accumulated gradually over extended periods.


Slowloris in Operational Detail

The mechanism of Slowloris was described earlier in the application-layer post, but its operational characteristics warrant more detailed examination.

Slowloris was first demonstrated publicly by Robert Hansen (RSnake) in 2009, though the concept of partial HTTP header attacks was understood earlier in the security research community. The core exploit targets the connection handling behavior of threaded HTTP servers.

Apache HTTP Server in its prefork and worker MPMs assigns a thread or process to each active connection. This model is simple and performs well for connections that complete quickly. Under Slowloris, each connection completes slowly, never, in the attacker's design. The thread is occupied indefinitely, or until the server's header timeout expires.

The default header timeout in Apache (configured via RequestReadTimeout in mod_reqtimeout) was historically absent or very long. A stock Apache installation with no explicit timeout configuration would hold connections waiting for headers for the server's global Timeout value, often 300 seconds. With 256 worker threads (a common default configuration for modest-hardware servers), the attacker needs to maintain 256 slow connections. Each connection requires sending a partial header byte approximately every 200 seconds, a rate of less than 2 bytes per second per connection.

The total traffic generated by a saturating Slowloris attack on a 256-thread Apache server is approximately 512 bytes per second, less than a single small JPEG image per second. No volume-based detection system would identify this as anomalous.

Server Architecture Dependency

The impact of Slowloris depends critically on the server's concurrency model:

Thread-per-connection (Apache prefork/worker MPM): fully vulnerable. Each slow connection consumes a thread. The thread count is bounded. The attack achieves denial with connections equal to the thread limit.

Event-driven (nginx, Apache event MPM, Node.js, Tornado): resistant but not immune. These servers use non-blocking I/O and a small number of threads managing many connections via event loops. A connection waiting for headers consumes a file descriptor but not a thread. The file descriptor limit (typically configurable up to hundreds of thousands on Linux via ulimit -n) is much higher than typical thread pool sizes. The attacker needs correspondingly many connections to fill the fd table.

nginx enforces header timeouts through the client_header_timeout directive (default: 60 seconds). A connection that does not send complete headers within 60 seconds is closed, limiting the accumulation of partial-header connections. With a 60-second timeout and a maximum fd limit of, say, 65535, the attacker must be able to open and maintain connections faster than the server times them out.

Load balancer interposition: load balancers that buffer HTTP requests before forwarding them to backends effectively absorb Slowloris attacks against the backends. The load balancer handles the slow connection; the backend receives only complete, forwarded requests. HAProxy and similar L7 load balancers with appropriate timeout configuration handle this correctly.

Connection Hold Time and Detection

A key diagnostic characteristic of Slowloris traffic is the connection hold time distribution. Legitimate HTTP connections complete quickly, a typical page load involves connections that transmit headers in milliseconds and complete in under a second for fast connections. A Slowloris connection may hold for hundreds of seconds.

Traffic analysis that tracks connection duration distribution can identify the anomalous long-tail characteristic of Slowloris traffic. However, this requires access to connection-level logs, which are not always available at the point where mitigation would be applied. Network flow telemetry (NetFlow, IPFIX) typically aggregates at flow level and may not capture per-connection duration accurately for short-lived connections.


R.U.D.Y. and Body Submission Attacks

R.U.D.Y. (R-U-Dead-Yet) exploits a different phase of the HTTP exchange than Slowloris. Where Slowloris occupies connections during header receipt, R.U.D.Y. occupies connections during request body transmission.

The attack sends a valid, complete HTTP POST request header, including a Content-Length declaring a large body (say, 1 MB). The body is then transmitted one byte every 90 seconds. The server must receive the full declared body before it can dispatch the request for processing. The connection remains open during body receipt; the handler context (or the thread, in threaded servers) is occupied.

From the server's perspective, this is a slow client, not a malicious one. Slow clients exist legitimately, mobile users on degraded connections, users behind throttled networks. The server cannot distinguish slow legitimate clients from R.U.D.Y. connections without additional context.

The defense is server-side body receive timeout: if the client is not transmitting body data at a minimum rate after some initial threshold, close the connection. nginx's client_body_timeout directive (default: 60 seconds) specifies the maximum time between successive body data transmissions. The 60-second default means a R.U.D.Y. connection that sends one byte every 90 seconds will be timed out.


Sockstress

Sockstress, discovered and documented by Jack C. Louis and Robert E. Lee at Outpost24 in 2008, is a TCP-level low-rate attack that exploits the window size negotiation mechanism of TCP flow control.

The TCP receive window, advertised by the receiver in ACK packets, tells the sender how many bytes can be in flight before acknowledgment. A receiver advertising a window of 0 tells the sender to stop transmitting. The sender must then send periodic window probe packets (per RFC 793), waiting for the receiver to re-open the window. The connection remains established, using kernel memory for the socket state, while no data is transmitted.

Sockstress establishes a TCP connection, completes the three-way handshake (so it is not a SYN flood, it requires actual connectivity), and then advertises a receive window of 0 or near-zero. The server's TCP stack halts data transmission and enters a window probe retry loop. The server allocates kernel socket buffers and timer structures for the connection indefinitely.

The resource being exhausted is kernel memory for socket state and timer processing. Each zero-window connection consumes kernel resources for as long as the attacker maintains the connection. Unlike Slowloris, which targets application-layer resources (thread pool, fd table), Sockstress targets kernel resources, making it effective against any service that uses TCP, regardless of application architecture.

The traffic signature is distinctive: connections that complete the handshake, send zero data, and advertise zero or minimal window sizes. TCP window probing intervals are standardized (exponential backoff per RFC 793), so the probe traffic from the server to the attacker has a predictable timing signature.

Mitigations include:

Sockstress did not receive the same public exposure as Slowloris, and operational deployments of it as a DDoS tool are less documented. This may be because the attack complexity, requiring a completed TCP connection and active maintenance of zero-window state, is higher than Slowloris, and the kernel-level defenses have improved.


HTTPS Renegotiation Exhaustion

TLS renegotiation, the process by which either party in a TLS session can request renegotiation of the session parameters, was designed to allow refreshing cryptographic material or adding client certificate authentication mid-session. Each renegotiation triggers a new TLS handshake within the existing session, requiring asymmetric cryptographic computation.

An attacker who repeatedly triggers renegotiation exhausts server CPU at the asymmetric operation rate, which is limited to hundreds or low thousands of operations per second on typical hardware. A single connection performing continuous renegotiation at the maximum possible rate consumes a significant fraction of the server's TLS processing capacity.

This vulnerability was known and exploited before the TLS 1.3 specification eliminated the renegotiation capability. TLS 1.3 does not support renegotiation; post-handshake authentication is handled through a separate, more controlled mechanism. For servers still supporting TLS 1.2 connections, disabling renegotiation (available through configuration options in OpenSSL and most TLS library implementations) addresses this specific vector.


Slow DNS Queries

DNS resolvers maintain query state for outstanding recursive queries. A recursive resolver that receives a query begins the recursive resolution process and holds state for that query until resolution completes or a timeout expires. An attacker who issues queries that require extended recursive resolution, queries for domains with long CNAME chains, queries for domains whose authoritative servers are slow to respond, or queries that trigger DNSSEC validation chains, can accumulate outstanding query state on a resolver.

The resource being exhausted is the resolver's pending query table and the associated processing state. The attack traffic rate can be low because each outstanding query persists for the full duration of the resolution attempt (up to the configured resolution timeout).

This attack is most effective against resolvers that serve limited populations (corporate resolvers, ISP resolvers with smaller infrastructure) rather than public resolvers (Google's 8.8.8.8, Cloudflare's 1.1.1.1) which have substantial capacity.


The General Principle: Holding Resources Without Productive Progress

The server cannot know that a connection is never going to complete, it can only observe that it has not completed within some time window. The window must be large enough to accommodate legitimate slow clients; making it too small creates false positives. Making it too large creates vulnerability.

The calibration of timeouts is therefore a direct attack surface parameter. Defenders who set tight timeouts reduce the effectiveness of low-and-slow attacks but risk disconnecting slow legitimate clients. The appropriate timeout value depends on the application: a real-time API with a known client population has different timeout needs than a public web server serving heterogeneous global users.

Behavioral analysis that distinguishes slow-but-progressing connections from not-progressing connections can improve on pure timeout-based detection. A connection that sends headers continuously but slowly is different from a connection that sends exactly one header line every 45 seconds. The former may be a legitimately slow client; the latter is more characteristic of a Slowloris pattern. Application-layer detection that tracks progress rates, rather than only presence or absence of activity, enables more precise classification.


Low-and-Slow in Distributed Form

The attacks described above are largely effective from a single source or a small number of sources, which makes source-based mitigation viable. A single-source Slowloris attack can be blocked by per-IP connection limits.

Distributing these attacks across many source IPs changes the mitigation calculus. A Slowloris attack from 10,000 source IPs, each maintaining a few connections, exhausts the same server connection pool while preventing per-IP rate limiting from identifying any individual source as anomalous.

Distributed low-and-slow attacks combine the evasion properties of low-volume traffic (no volumetric detection) with the distribution properties of botnets (no per-source detection). They are among the harder attack types to mitigate without application-layer behavioral analysis, because the only distinguishing characteristic is the behavioral pattern, connections that never complete.

The appropriate mitigation is challenge-response: require potential clients to demonstrate browser-like behavior before being allowed to accumulate connection state. A JavaScript challenge that a real browser executes but a simple connection-holding tool cannot is effective. The cost is added latency for legitimate users and exclusion of API clients or non-browser user agents, both of which may be unacceptable depending on the application.