CRLF Powered Desyncs

This blogpost is really important to us, it is the culmination of over a year of research carried out by Tobia Righi and PortSwigger researcher Thomas Stacey. rember to mention black hat and defcon

In this blogpost we will show how HTTP Header Injection can be turned into really powerful desync attacks, allowing you to take over victim accounts without user interaction, cause mass-PII leaks, access internal sensitive data, gain XSS out of thin air and a lot more. All the attacks showcased in this blogpost are from real world applications running bug bounty or vulnerability disclosure programs.

The origin story

Around 1 year ago, we came across this post on Bluesky which mentioned an attack technique we’d heard of, but never come across in the wild. This post bothered us, as it claimed the attack was “not that uncommon” in spite of our failure to ever find it. On top of this, we knew of at least two other research papers on the same topic (both of which were in their respective year’s Top 10 Web Hacking Techniques).

The first, Making HTTP header injection critical via response queue poisoning by James Kettle explains how you can achieve HTTP request smuggling using request splitting, citing a single case study as evidence. The second, HTTP Request Splitting Vulnerabilities Exploitation by Sergey Bobrov explores how common request splitting actually is, due to a common Nginx misconfiguration, but only briefly mentions the potential for desyncs.

This got us thinking. What would happen if we took James’ desync techniques, and applied them to everything that seemed vulnerable to HTTP header injection. After our first encounter, we quickly realized the technique’s potential and started to spot gaps in its current understanding.

Nginx’s fatal flaw

Sergey’s research showed us that when the $uri variable is included in a proxy_pass directive nginx will normalize the request path before it is used. This includes CRLF sequences %0d%0a, allowing us to inject new lines into the request forwarded by nginx allowing us to for example inject arbitrary headers which will get processed by the application upstream of nginx.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# nginx.conf
http {
    upstream backend {
        server backend.internal.com:8000;
    }
    server {
        location / {
            proxy_pass http://backend$uri;
        }
    }
}

The above is an example of a vulnerable configuration. If you’re a developer and you recognize this from your own app you may go and patch before finishing this post, but promise to come back :).

GET /%20HTTP/1.1%0d%0aContent-Length:%20-1%0d%0aX:%20x HTTP/1.1                       GET / HTTP/1.1
Host: example.com                                                   --[normalize]-->  Content-Length: -1
                                                                                      X: x HTTP/1.1
                                                                                      Host: example.com
                                                                                      

In the example above, we inject an invalid Content-Length header resulting in the application returning a 400 Bad Request response, telling us that our injected header was in fact processed.

For the rest of this post we will be using Hackvertor notation to represent our payloads as it is clearer and easier on the eyes:

GET /<@urlencode_all> HTTP/1.1
Content-Length: -1
X: x</@urlencode_all> HTTP/1.1
Host: example.com

Detection

All detection tech

Request splitting

Theory

Response Queue Poisoning

  • Theory
  • Why we can do it with our CRLF injection

RQP inside a CDN

Case

RQP in a major telecom provider

Case

CRLF-Powered CL.TE Desync Attacks

Ok lots of confusing words:

  • Explain CL.TE
  • Explain it in context of CRLF

The CL.TE desync disaster

  • Clothing store
  • Shopping cart crazyness
  • ATO

Pwning phones across the world

  • Intro
  • Blind xss
  • ATO via qr code

Browser-Powered CRLF Desync Attacks

  • Browser spec
  • Browser powered desync worm

Request Tunneling

  • Explaination
  • Bypasses with Expect header

Exploiting desyncs in the browser

  • Connection locked and ip locked is why we need the browser

Browser-Powered 0.CL in a streaming service

Case XSS OUT OF THIN AIR

Browser-Powered Desync using iframes

Case

Bypassing HttpOnly with Browser-Powered desync

Case

Response header injection

  • Next logical steps
  • Nginx configuration
  • Location problems

Case

XSS on a Redirect Response

  • Hunting for origin to edge headers
    • Other impacts that can be achieved
  • Case -> mention johan

Reverse desyncs

Theory

Defence

Tooling

Further research