CSRF is a type of vulnerability where a request (POST) originates from a different domain (ORIGIN) than the target. If a vulnerable site allows another domain to send a request, it will be processed. The request would be crafted to make a change to a user account, and the trick is to get a user to pass their authentication along with the request. It may seem doubtful that this could actually happen – but it is a valid and common attack vector. A client could get tricked to land on a realistic site to the one they are attempting to access. Only the attack site will prompt for a login, which is captured and sent to the real site, along with the fake request.
For example, if the target is vulnerablesite.io and the attacker’s site is evilattacker.com, then the attacker would entice a user of vulernablesite.io to click a page hosted on their site (evilattacker.com). The attack page that loads will attempt a request that submits to the vulnerable site.
The request will be crafted to do one action, but that action will likely be significant. It could be a POST request to change ownership of an account, create a user on an account, change the email address or login of the account, or reset the password. The victim likely will not be aware of the attack while it happens. For the victim they would click to the fake site, be redirected to the real site and all seems well and good. Unknown to the victim, a request was made to modify their account in some way.
What makes a CSRF attack work is a lack of an ORIGIN policy. Technologies like CORS and CSRF-Tokens try to resolve the issue by enforcing the same domain as the origin of all change requests. If a request is originating from a different domain, it will be dropped, ignored or error out.
Checking for CSRF Vulnerability
Almost any scanner (OWASP ZAP, etc.) will detect a lacking CORS or CSRF token, which in itself is not necessarily an indicator of vulnerability, but it does indicate further testing is required. Outside of an automated scanner, one can use the Burp Suite proxy.
Launch Burp Suite and click Proxy.
On the proxy screen, click the button to launch the Browser. This will spawn a Burp Suite Browser, which acts as a proxy and sends all requests back to Burp Suite for analysis.
Once the Burp browser is open, navigate to the target/test domain and then in Burp Suite click “Intercept” to turn it on.
Once Intercept is on, go to the test (target) domain and perform an action like logging in. With intercept on, we are stepping through each step of the requests, pausing after each one. Clicking “Forward” in Burp Suite moves the break point one more step. This allows us to see (and change) the request headers along the way.
During the handshake of a POST (such as performing a login requiest), note the headers and see if there is an “Origin: [target domain]” listed. If not, then there is likely a CSRF vulnerability that can be tested.
CSRF Exploit
Pre-Requisites:
- Target domain that is vulnerable to a CSRF attack
- Your own domain that can host HTML
Research
Scope the target/test domain out. Using a legit account, go through the account and look at all the actions you can do to your own account. Can you add users to it? Can you change ownership of it? Can you change the email address? Can you do a reset password without a email confirmation flow?
Your attack is like firing a single torpedo. Having only one shot, you want it to be effective at disabling the target.
Crafting the Exploit
Once you have discovered a single action/POST/DELETE, etc. to use on the test target domain, use Burp Suite to capture the request itself.
What is needed:
- The URL the request is POSTed to
- The variables and values of the request
The above data is necessary to craft the attack. Opening an editor of choice, create a new HTML file on your domain (attacker domain). The HTML will have a hidden form, that posts to the POST URL of the target, and hidden fields for all the variables and values being sent.
<form action="https://test.vulnerablesite.io/myaccount/useradmin/adduser" method="POST">
<input type="hidden" name="fname" value="Naughty" />
<input type="hidden" name="lname" value="User" />
<input type="hidden" name="username" value="naughtyuser" />
<input type="hidden" name="pass" value="passwwwword" />
<input type="hidden" name="newuser_email" value="naughtyuser@evilattacker.com" />
</form>
<script>
history.pushState('', '', '/');
document.forms[0].submit();
</script>
The above demo/example would add a new user on an account of a web application hosted at the fake domain: test.vulnerablesite.io. The action is the fully qualified path to the function adduser, which was captured using Burp Suite.
Each of the fields in the example above would have been captured in Burp Suite during the research phase. These are the fields required for the POST. In this fictitious example, we’re sending fname, lname, username, pass, and newuser_email. We’ll pretend for discussion that these fields and values are required to generate a new user on the account.
The script below the form is to ensure that the submit action occurs without user input. Just landing on the page triggers it.
Getting the Victim to Issue Our POST
We need the victim to trigger the HTML. When the victim clicks our HTML, the request will be sent to test.vulnerable.io and will likely get a Login page on the target domain. If the victim has a logged in session, they will bypass the login page and run the code immediately (creating our user on their account). Once they login, the request in the form above will execute, AS THE VICTIM. It is as though some victim account is issuing the POST above.
For a proof of concept, this should be enough for the team to verify the problem. This would show that any attack request (POST, DELETE, etc.) can be executed via a customer/client/victim using the CSRF vulnerable web app.
Delivery in the Real World
In a test application, a proof of concept doesn’t require the full flow of how to trick a user.
In real world scenarios, a list of customer account contact information might be leaked. Knowing all the email addresses of current customers, is one way to deliver this attack. An email could be crafted that appears to be an official email of the site, but is an attacker email with a link to their attack script.
Another idea would be a waterhole attack variation, where the attacker guesses a site that customers may also click on. This could be a site that is being shared via social media, “Are you a customer of [vulnerable website]? If so, they may have been overcharging you. Click HERE to know more…” Through some trickery a customer of the vulnerable site, might engage the fake site to click on the page that asks them to login to their account. Simply clicking that link will execute the request.
CSRF Mitigation
There are several mitigation methods. Many modern web app development frameworks now come with mitigations backed in. Spring Boot, for example, has a baked in method of setting up a CSRF token validation. Python’s Django web framework uses an special package to mitigate CSRF: django.middleware.csrf.CsrfViewMiddleware. Rails has a method of creating and using CSRF tokens as well: https://guides.rubyonrails.org/security.html By default these counter measures are not enabled. This is where the problem. If a development team is small, or in a hurry, the counter measures can be ignored and that leads to an origin vulnerability.