CRLF injection is not restricted to HTTP/2 headers only. Any place where you send a \r\n that potentially ends up in the HTTP/1.1 request could potentially achieve the same results.
We will use the H2.CL vulnerability to force other users to like our post.
Duplicate the request and send in a single connection:
Success
THM{not_secret_anymore}
Bypassing Frontend Restrictions
Info
There’s a fundamental difference on how GET and POST requests are treated by a proxy. If a proxy implements caching, a GET request may be served from the proxy’s cache, so nothing will be forwarded to the backend server and the attack may fail. A POST request, on the other hand, is normally not served from cache, so it is guaranteed that it will be forwarded to the backend.
Header value:
Send twice:
Success
THM{staff_only}
Web Cache Poisoning
Header value:
Receive cookie:
Success
THM{nom_nom_cookies}
h2c
Two ways to negotiate HTTP/2:
h2: Protocol used when running HTTP/2 over a TLS-encrypted channel. It relies on the Application Layer Protocol Negotiation (ALPN) mechanism of TLS to offer HTTP/2.
h2c: HTTP/2 over cleartext channels. This would be used when encryption is not available. Since ALPN is a feature of TLS, you can’t use it in cleartext channels. In this case, the client sends an initial HTTP/1.1 request with a couple of added headers to request an upgrade to HTTP/2. If the server acknowledges the additional headers, the connection is upgraded to HTTP/2.
When an HTTP/1.1 connection upgrade is attempted via some reverse proxies, they will directly forward the upgrade headers to the backend server instead of handling it themselves.
Since connections in HTTP/2 are persistent by default, we should be able to send other HTTP/2 requests, which will now go directly to the backend server through the HTTP/2 tunnel. This technique is known as h2c smuggling.
Some proxies are aware of h2c and could try to handle the connection upgrade themselves. When facing an h2c-aware proxy, there’s still a chance to get h2c smuggling to work under a specific scenario. If the frontend proxy supports HTTP/1.1 over TLS, we can try performing the h2c upgrade over the TLS channel. This is an unusual request, since h2c is defined to work under cleartext channels only. The proxy may just forward the upgrade headers instead of handling the upgrade directly.
Note
Note that h2c smuggling only allows for request tunnelling. Poisoning other users’ connections won’t be possible.
Where /private is the private endpoint that we need to access by bypassing the proxy.
Output:
Success
THM{walls_are_a_suggestion}
WebSockets
To smuggle requests through a vulnerable proxy, we can create a malformed request such that the proxy thinks a WebSocket upgrade is performed, but the backend server doesn’t really upgrade the connection. This will force the proxy into establishing a tunnel between client and server that will go unchecked since it assumes it is now a WebSocket connection, but the backend will still expect HTTP traffic.
One way to force this is to send an upgrade request with an invalid Sec-Websocket-Version header.
Some proxies may assume that the upgrade is always completed, regardless of the server response.
Note
It is important to note that this technique won’t allow us to poison other users’ backend connections. We will be limited to tunnelling requests through the proxy only, so we can bypass any restrictions imposed by the frontend proxy by using this trick.
Lab 1: Proxy Does Not Check Back-end Server Responses
Lab 1: Varnish proxy.
Request to /flag:
Request to /404:
As we can see, the Varnish proxy server rejects requests sent to /flag endpoint.
Request to /socket
With invalid WebSocket version:
Attack request:
Remember to turn of Update Content-Length feature of Burp Suite.
Success
THM{bf208caddc31c6bb52621fdc2b3a73e5}
Note that some proxies will not even require the existence of a WebSocket endpoint for this technique to work. All we need is to fool the proxy into believing we are establishing a connection to a WebSocket, even if this isn’t true.
Lab 2: Proxy Do Check Back-end Server Responses
Using the attack request of the previous lab:
Response:
Since Nginx is checking the response code of the upgrade, it can determine that no valid WebSocket connection was established; therefore, it won’t allow us to smuggle the /flag request.
We need to somehow force the backend web server to reply to our upgrade request with a fake 101 Switching Protocols response without actually upgrading the connection in the backend.
If our target app has some vulnerability that allows us to proxy requests back to a server we control as attackers, we might be able to inject the 101 Switching Protocols response to an arbitrary request.
There is a request used for checking connection to a specified URL:
Point server param to our controlled listening netcat server on 10.13.57.143:5555:
The attack request:
Response:
Success
THM{a87d4e5b777c010ed3266e59fb42ccac}
Browser Desync
Identify with this script:
Confirmed after sending two requests:
The request used for storing gadget:
Payload for url param:
<script>alert(1)</script>
It will be rendered on /securecontact page like this:
However, when access /vulnerablecontact, the payload is rendered correctly:
We will change payload into a form that can send requests to smuggle request:
Where 10.13.57.143:1337 is our controlled server used for serving the malicous payload:
URL encode the above form and place it in the url param. The form will be rendered correctly on /vulnerablecontact page.
The cookie will be sent to port 8080 so we need to listen on this port:
After a while, the server and the listener receive requests: