Using CSRF on Anonymous Forms
This article will focus on linking CSRF vulnerabilities with phishing attacks to extend the lifetime of your captured credentials. Cross Site Request Forgery (CSRF) vulnerabilities on anonymous forms are often ignored or overlooked, but when combined with a credential-harvesting phishing campaign it extends the life of your captured credentials. When CSRF on anonymous login forms is used with a phishing campaign you can collect credentials and also serve your target the actual application behind the vulnerable login form. The user never realizes they submitted credentials to a phishing site, they don’t report it to their security team, and they don’t change their credentials.
Anecdotal evidence suggests this is very effective; I’ve used this on several assessments and the harvested credentials stayed valid for over a week without the user ever realizing they were phished.
The attack looks like this:
- Identify a form vulnerable to CSRF that accepts credentials, such as a VPN or webmail login form.
- Clone the vulnerable page and edit the form action to submit credentials to your infrastructure.
- Convince target user to enter credentials.
- Credentials are submitted to your infrastructure and also forwarded to the legitimate, vulnerable, page.
- Target user is served the legitimate application or web page that sits behind the login form.
Setting up an attack using King Phisher
Note: I use King Phisher for my phishing campaigns, it’s maintained by RSM and we’ve created templates to make this attack quicker to execute. The steps below will focus on executing this attack with King Phisher, it’s possible to pull off with the web server of your choice but you’ll have to do a lot of these steps manually.
Find a vulnerable form
We need to identify a form that’s vulnerable to CSRF that looks like it provides access to something tempting. You can accomplish this by examining a sample request using an intercepting proxy, examining the site’s source and cookies for an anti-CSRF token, or by simply trying to make a forged cross-site request and seeing if it works.
I’ve set up a vulnerable demo page as an example, the World Wide Cat Portal located at https://csrf.thor-vath.com/

Clone the vulnerable form
I’m going to use KingPhisher to clone the page.
Start by going to Tools, then Clone Web Page.
Enter the URL of the vulnerable form into the Target URL field, and click Clone.
The site is clone and saved in the path indicated by the Directory field.
Move these files into the web root of your phishing page so we can serve them to our targets.
Edit the cloned index.http
We need to make some modifications to index.html to ensure that the credentials are properly recorded and forwarded. Depending on the complexity of the site you’re cloning you may also need to make additional edits for the site to render properly on your web server, but that is outside the scope of this blog.
The lines in blue are the names of the POST parameters used by the form, this form uses “catname” and “catpass”. In order for King Phisher to record the credentials they need to be named “username” and “password” respectively.
The line in red will be our redirect page records the parameters entered by our phished targets and will also generate our forged cross-site request to the legitimate login page. Let’s edit this value to “auth.html”, we’ll be using a King Phisher HTML template file to accomplish these operations.
<head> <title>World Wide Cat Portal</title> <script src="/kp.js" type="text/javascript"></script> </head> <body> <h2>World Wide Cat Portal</h2> <form action='auth.php' method='post'> <div class='imgcontainer'> <img src='images/fancycat.jpg' alt='Avatar' class='avatar'> </div> <div class='container'> <label><b>Username</b></label> <input type='text' placeholder='Enter username' name='catname' required> <label><b>Password</b></label> <input type='password' placeholder='Enter password' name='catpass' required> <button type='submit'>Login</button> </div> </form> </body>
After editing our cloned index.html it should look like this:
<head> <title>World Wide Cat Portal</title> <script src="/kp.js" type="text/javascript"></script> </head> <body> <h2>World Wide Cat Portal</h2> <form action='auth.html' method='post'> <div class='imgcontainer'> <img src='images/fancycat.jpg' alt='Avatar' class='avatar'> </div> <div class='container'> <label><b>Username</b></label> <input type='text' placeholder='Enter username' name='usernmae' required> <label><b>Password</b></label> <input type='password' placeholder='Enter password' name='password' required> <button type='submit'>Login</button> </div> </form> </body>
Setup the redirect and CSRF generating page
Next we need to setup the page which will accept the credentials and perform the CSRF attack. To speed this up we’ve made a pair of templates to accomplish these tasks. By default the pages redirect to a target URL and display a spinning wheel while the redirect occurs. The user sees this image breifly, based on their connection and the responsiveness of the webserver. The template can be manipulated through Jinja variables to enable the CSRF behavior.
The templates can be found on the King Phisher github repository, here.
There are two templates, a light and a dark. The only difference is the color of the background and the color of the spinning wheel image.
Let’s clone the light template and save it in our webroot. We’ll name it auth.html.
Below are the variables from the template that control the behavior of the redirect page. The text in red will need to be changed for our attack to work.
{# CSRF #} {% set csrf = false %} {% set target_url = 'https://github.com/securestate/king-phisher' %} {# MODIFYING CSRF PARAMETERS Example: If the vulnerable site uses 'login_name' instead of 'username', the do extension would look like: 'login_name': request.parameters['username'] #} {% do request.parameters.update({ 'username': request.parameters['username'], 'password': request.parameters['password'] }) %}
- Change the value of csrf to true
- This changes the template’s behavior to send the username and password parameters to target_url instead of simple redirecting there.
- Change the value of target_url to ‘https://csrf.thor-vath.com/auth.php’
- This is the target of your redirect, or CSRF attack if you set the previous variable to true.
- Change the highlighted value of username to catname
- This copy’s the value of the username parameter into the catname parameter. In order for King Phisher to record the credentials entered into our cloned “index.html” landing page we changed the name of the parameter to username, but the actual application we are sending a CSRF attack to expects a parameter called catname. So we have to make sure the parameter has the correct name or the phished user won’t be logged into their application.
- Change the highlighted value of password to catpass
- Here we’re changing the password parameter name to catpass for the same reason we changed the username.
After making those changes, you the template should look like this:
{# CSRF #} {% set csrf = false %} {% set target_url = 'https://github.com/securestate/king-phisher' %} {# MODIFYING CSRF PARAMETERS Example: If the vulnerable site uses 'login_name' instead of 'username', the do extension would look like: 'login_name': request.parameters['username'] #} {% do request.parameters.update({ 'username': request.parameters['username'], 'password': request.parameters['password'] }) %}
There are also variables to control the display of the template. The parts highlighted in blue are optional changes you can make to edit the display variables. With these changes, redirect/CSRF page will be titled “Authenticating”, and the user will be presented with a small spinning image indicating that the page is hard at work. Nothing to worry about…
{# DISPLAY #} {% set title = 'Authenticating' %} {% set display_message = false %} {% set display_image = true %} {% set image_height = '200px' %} {% set image_width = '200px' %}
Example Attack
This gif shows an example of what your victim might see, from the time they get the phishing email, to the time they log into the application. At the bottom is Credentials tab from KingPhisher that you’d see if you were the attacker.
They target visited a cloned site that looked like the one they were expecting, entered their valid credentials, and were logged in. Now we have their valid credentials and can login to the application, and since the user experienced a familiar workflow they are less likely to report it.
If you’d like to test this process feel free to test against https://csrf.thor-vath.com. I can save you some time by telling you there’s no database behind the form, and no hidden credentials. The only creds that will work are UN:”fancy_cat” and PW:”I am a fancy cat.”, and there’s no reflected user input, just a simple static page behind the form.
Remediation
Educating users to identify phishing techniques will work to remediate the root of the attack. Without a successful phishing attack, the anonymous CSRF becomes irrelevant. However, eliminating the CSRF vulnerability can aid those poor users who fall for the phish. Remediating the anonymous CSRF follows the same process as authenticated CSRF; through the use of an anti-CSRF token. I typically see applications implementing a hidden form field that contains the value of a randomly generated anti-CSRF token, but there are other methods which are recorded on the CSRF topic of OWASP’s wiki.
Originally authored by Travis H.