On this page
URL-Based Access Control Can Be Circumvented
Lab
URL-based access control can be circumvented · Apprentice
Solution
Given
This website has an unauthenticated admin panel at /admin, but a front-end system has been configured to block external access to that path. However, the back-end application is built on a framework that supports the X-Original-URL header.
To solve the lab, access the admin panel and delete the user carlos.
Analyzing the task
A site with an admin panel at /admin, access to which is restricted. However, we know the framework supports the X-Original-URL header. We need to get into the admin panel and delete the user.
Theory
Let's recall what X-Original-URL is used for.
It's a non-standard HTTP header. What for? It lets the backend see the original URL before proxy (nginx, Apache) processing. Some frameworks trust this header, which lets us bypass restrictions on closed URLs.
We send a request to a publicly accessible page, but with X-Original-URL we change the URL to, for example, /admin.
Recon
Open the site — right away we see the «Admin panel» link. Click it — «Access denied».
OK, then we throw a GET / request into Repeater and append X-Original-URL: /admin. The admin HTML comes back. Inside, we find the delete-user link:
<a href="/admin/delete?username=carlos">
We try:
X-Original-Url: /admin/delete?username=carlos
But the server complains «Missing parameter 'username'». Maybe the query string is being stripped?
What if we pass the query string in the main request:
GET /?username=carlos
X-Original-Url: /admin/delete
Worked! Lab solved.
More in this category
Arbitrary Object Injection in PHP (PortSwigger Lab)
Recovering leaked source code and injecting a serialized CustomTemplate object whose __destruct deletes an arbitrary file.
Using Application Functionality to Exploit Insecure Deserialization (PortSwigger Lab)
Tampering with the `avatar_link` field in the session object to delete an arbitrary file via the account-delete feature.
Modifying Serialized Data Types (PortSwigger Lab)
Abusing PHP loose comparison by changing the `access_token` type to integer `0` to bypass authentication.