05.09.2004

»спользование Libwhisker

 ак замечено в статье ѕроверка надежности Web-приложений использование веб приложений дл€ ведени€ бизнеса возрастает. „асто компании имею сайты, созданные внутренними разработчиками, и найти все у€звимости сайта, использу€ автоматизированные утилиты, практически невозможно. ѕростой поиск различного ѕќ с установками по умолчанию может ничего не дать, но этот созданный на заказ сайт все же может быть у€звимым ко многим различным ошибкам программировани€. ѕроведение тестировани€ сайта может быть наиболее важным этапом создани€ сайта, и намного более сложным, чем тестирование с использованием соответствующих утилит. –учна€ проверка сайта необходима почти всегда, но когда специфическа€ у€звимость обнаружена, очень удобно иметь набор утилит дл€ автоматизации дальнейших действий.

Ќейл ƒесэй, перевод ¬ладимир  уксенок

 ак замечено в статье ѕроверка надежности Web-приложений использование веб приложений дл€ ведени€ бизнеса возрастает. „асто компании имею сайты, созданные внутренними разработчиками, и найти все у€звимости сайта, использу€ автоматизированные утилиты, практически невозможно. ѕростой поиск различного ѕќ с установками по умолчанию может ничего не дать, но этот созданный на заказ сайт все же может быть у€звимым ко многим различным ошибкам программировани€. ѕроведение тестировани€ сайта может быть наиболее важным этапом создани€ сайта, и намного более сложным, чем тестирование с использованием соответствующих утилит. –учна€ проверка сайта необходима почти всегда, но когда специфическа€ у€звимость обнаружена, очень удобно иметь набор утилит дл€ автоматизации дальнейших действий.

ѕочему Libwhisker?

— того момента, когда мы начинаем иметь дело с заказными приложени€ми, нам нужен набор специализированных утилит. ≈сть много различных утилит, дл€ которых можно создавать скрипты, но мы сосредоточимс€ на Libwhisker. Libwhisker это не утилита или приложение, это Perl библиотека, котора€ позвол€ет создавать HTTP пакеты.

— этого момента предполагаетс€, что читатель имеет представление о протоколе HTTP и знаком с написанием Perl скриптов, использующих внешние модули.

ƒл€ начала давайте ответим на вопрос: «ачем нам нужно использовать другой Perl модуль, дл€ того чтобы сделать то, что может быть реализовано с помощью существующих Perl модулей (т.е. LWP, HTTP, URI)? Libwhisker дает нам много преимуществ по сравнению с другими модул€ми:
  1. Ёто 100% Perl код. Ёто означает, что он будет работать на любой системе, где установлен Perl.
  2. ќн сочетает в себе функциональные возможности многих различных Perl модулей, обычно используемых дл€ взаимодействи€ с веб приложени€ми.
  3. Ќе требует инсталл€ции. Ќужно всего лишь иметь копию LW2.pm в каталоге со скриптом, использующем этот модуль.
  4. ќн был создан по методу отсутстви€ правил. Ёто означает, что он позвол€ет пользователю создавать запросы, не соответствующие стандартам. ƒругие Perl модули могут провер€ть и измен€ть наши запросы дл€ соответстви€ стандартам.

»спользование Libwhisker

√лавна€ структура данных в Libwhisker это хэш-массив 'whisker'. ’эш-массив это структура данных в Perl, похожа€ на ассоциативные массивы в других скриптовых €зыках и €зыках программировани€.

’эш-массив 'whisker' может устанавливать различные параметры HTTP запроса и читать различные части HTTP ответа. ќднако доступ к этой информации может вызвать затруднени€.

ѕрежде чем использовать какие-либо функции Libwhisker, нужно определить два хэш-массива, один дл€ HTTP запроса, другой дл€ HTTP ответа. Ќекоторые элементы будут определены в хэш-массиве 'whisker', а некоторые непосредственно в хэш-массиве запроса, или будут читатьс€ непосредственно из хэш-массива ответа. „тобы определить какие части HTTP запроса/ответа €вл€ютс€ частью хэш-массива 'whisker', а какие частю хэш-массивов запроса/ответа, давайте посмотрим на возможные элементы хэш-массива 'whisker', имеющие отношение к HTTP пакету.

ќбратите внимание, что два элемента хэш-массива 'whisker', 'hin' и 'hout' непосредственно указывают на хэш-массивы запроса и ответа соответственно. ¬ этой статье мы будем использовать хэш-массивы Perl %request, %response и %jar дл€ обращени€ к хэш-массиву HTTP запроса, хэш-массиву HTTP ответа и хэш-массиву HTTP cookies соответственно.

  1. {'whisker'}->{'host'} = ”даленный хост, к которому мы хотим подключитьс€. Ёто значение будет также находитс€ в поле 'Host' HTTP заголовка. Ёто может быть IP адрес, DNS или NetBIOS им€. ≈сли вы хотите установить другое значение в поле 'Host' HTTP заголовка, вы должны будете сделать это вручную до вызова функции 'LW2::http_do_request'. Ёто поле должно быть во всех HTTP 1.1 пакетах, чтобы соответствовать RFC. ѕо умолчание его значение - 'localhost'.
  2. {'whisker'}->{'port'} = ”даленный порт, с которым мы хотим соединитьс€. ƒопустимые значени€ это числа между 1 и 65535. «начение по умолчанию - 80.
  3. {'whisker'}->{'proxy_host'} = ’ост прокси, который мы хотим использовать. ѕо умолчанию не установлен.
  4. {'whisker'}->{'proxy_port'} = ѕорт прокси, который мы хотим использовать. ƒолжно быть установлено, если установлена переменна€ 'proxy_host'.
  5. {'whisker'}->{'method'} = HTTP метод, который мы хотим использовать. ѕо умолчанию это GET.
  6. {'whisker'}->{'uri'} = URI, который мы хотим использовать. ѕо умолчанию это '/'.
  7. {'whisker'}->{'version'} = ¬ерси€ протокола HTTP, которую мы хотим использовать. ћы можем указать 0.9, 1.0 или 1.1 . ≈сли установлено 0.9, Libwhisker, по умолчанию, будет использовать только те возможности, которые поддерживаютс€ версией 0.9. ѕо умолчанию установлено значение 1.1.
  8. {'whisker'}->{'error'} = »спользуетс€ только если определен хэш-массив 'hout'. Ќе имеет отношени€ к HTTP коду, возвращенному сервером, но реагирует на ошибки, возникающие при получении данных от сервера. ѕо умолчанию пусто.
  9. {'whisker'}->{'data'} = ≈сли используетс€ в хэш-массиве запроса, в эту переменную помещаютс€ любые POST или PUT данные. ≈сли после определени€ {'whisker'}->{'data'}, происходит вызов функции 'http_fixup_request', будет установлено поле 'Content-Length' HTTP заголовка. ≈сли эта переменна€ используетс€ в хэш-массиве ответа, она указывает на HTML данные, полученные от сервера.
  10. {'whisker'}->{'code'} = ƒоступно только в хэш-массиве ответа. Ёто должен быть числовой HTTP код, возвращенный удаленным сервером.
  11. {'whisker'}->{'message'} = “екстовое сообщение, ассоциированное с {'whisker'}->{'code'}.
  12. {'whisker'}->{'header_order'} = Ёто хэш-массив, содержащий все HTTP заголовки, полученные от сервера, в пор€дке, в котором они были получены.
  13. {'whisker'}->{'http_space1'} = Ёто значение, которое отдел€ет HTTP метод от URI. ѕо умолчание это '' (один пробел).
  14. {"whisker'}->{'uri_prefix'} = «начение, наход€щеес€ перед URI. ѕо умолчанию пусто.
  15. {'whisker'}->{'uri_postfix'} = «начение, наход€щеес€ после URI. ѕо умолчанию пусто.
  16. {'whisker'}->{'uri_param_sep'} = —имвол, отдел€ющий параметры. ѕо умолчанию это '?'.
  17. {'whisker'}->{'http_space2'} = «начение, отдел€ющее URI и версию HTTP. ѕо умолчанию - пробел.
  18. {'whisker'}->{'http_eol'} = «начение, определ€ющее конец заголовка.
  19. {'whisker'}->{'cookies'} = ƒоступно только в хэш-массиве ответа. ќбычно не используетс€, так как есть функции дл€ чтени€ и записи cookies. ≈сли дл€ cookies определен хэш-массив, они могут быть сохранены в нем.
Ќиже показана схема пакета HTTP запроса, на которой показаны пол€, имеющие отношение к элементам хэш-массивов 'whisker' и запроса.

–исунок 1: HTTP запрос и хэш-массив 'whisker'

ƒалее идет схема пакета HTTP ответа, на которой показано, как обратитьс€ к хэш-массиву 'whisker'.


–исунок 2: HTTP ответ и хэш-массив 'whisker'

Ќачнем

ƒл€ ознакомлени€ с Libwhisker напишем консольную утилиту, осуществл€ющую первые п€ть шагов, описанных в статье "Penetration Testing of Web Applications". Ёто будет хороший пример, на котором могут основыватьс€ ваши скрипты. ќбобщим, что должен делать скрипт:

  1. јнализировать ответы на запросы HEAD и OPTIONS
  2. јнализировать формат и структуру 404 и других страниц об ошибках
  3. ѕроверка на известные типы файлов/расширени€/каталоги
  4. јнализ исходников доступных страниц
  5. ћанипулирование вводом дл€ вы€влени€ ошибок в скриптах
≈сть несколько разных способов инициализации хэш-массивов запроса и ответа. ќдин из них заключаетс€ в инициализации вручную [см. I], другой в использовании функций 'LW2::http_new_request' и 'LW2::http_new_response' [см. II].

I.

use LW2;

%request = ();
%response = ();
LW2::http_init_request(\%request);
$request{'whisker'}->{'host'} = "www.victim.com";

II.

use LW2;

$request = LW2::http_new_request(host=>'www.victim.com', uri =>'/');
$response = LW2::http_new_response();
ƒл€ осуществлени€ первого из наших п€ти шагов нам нужно послать на сервер запрос HEAD или OPTION и посмотреть, что нам будет отправлено в ответ. Ёто означает, что нам нужно измен€ть значение переменной {'whisker'}->{'method'} и печатать все заголовки, возвращенные сервером. ћетод можно будет указать, использу€ опцию '-m' командной строки. ћожно будет выбрать метод GET, HEAD или OPTIONS.
#ћодули, которые мы будем использовать.
use strict;
use LW2;
use Getopt::Std;

#’эш-массивы дл€ опций командной строки, запросов и ответов
my (%opts, %request, %response, $headers_array, $header);

getopts('h:m:', \%opts);

#»нициализаци€ всех переменных запроса. Ќекоторые из них будут перезаписаны.
LW2::http_init_request(\%request);

if (!(defined($opts{h}))) {

    die "You must specify a host to scan.\n";

}

if (defined($opts{m})) {

    if ($opts{m} =~ /OPTIONS|HEAD|GET/) {

        $request{'whisker'}->{'method'} = $opts{m};
    } else {

        die "You can only use OPTIONS, HEAD or GET for the method.\n";

    }
}

##начинаем создание запросов

#”становка хоста, который мы хотим сканировать
$request{'whisker'}->{'host'} = $opts{h};

#ќбеспечиваем совместимость с RFC
LW2::http_fixup_request(\%request);

#ѕроизводим сканирование
if(LW2::http_do_request(\%request,\%response)){

##обработка ошибок
    print 'ERROR: ', $response{'whisker'}->{'error'}, "\n";
    print $response{'whisker'}->{'data'}, "\n";

} else {

##выводим результаты

    #ѕолучаем информацию из хэш-массива 
	#'$headers_array' это ссылка
    $headers_array = $response{'whisker'}->{'header_order'};
    print "HTTP " ,$response{'whisker'}->{'version'}, "\t";
    print $response{'whisker'}->{'code'} , "\n";

    foreach $header (@$headers_array) {

        print "$header";
        print "\t$response{$header}\n";

    }
}

¬торой, третий, четвертый и п€тый шаг в нашем примере могут быть объединены, так как они все состо€т в изменении URI и анализе HTML данных, возвращенных сервером. „тобы помен€ть URI, нам нужно изменить значение переменной {'whisker'}->{'URI'}. Ќам также нужно добавить опцию дл€ вывода HTML данных. “ак мы сможем увидеть, есть ли что-нибудь интересное в возвращенных данных, например ошибка 404 (шаг 2), файлы и директории (шаг 3), исходный код (шаг 4) и ошибки, полученные манипул€цией URI в GET запросах (шаг 5). ƒл€ задание URI мы будем использовать опцию '-u', а дл€ вывода HTML кода опцию '-d'.

ƒавайте посмотрим на новый код, основанный на предыдущем:

#ћодули, которые мы будем использовать.
use strict;
use LW2;
use Getopt::Std;

#’эш-массивы дл€ опций командной строки, запросов и ответов
my (%opts, %request, %response, $headers_array, $header);

##обратите внимание на дополнение, опцию 'd' дл€ данных
##и 'u' дл€ URI
getopts('dh:m:u:', \%opts);

#»нициализаци€ всех переменных запроса. Ќекоторые из них будут перезаписаны.
LW2::http_init_request(\%request);

if (!(defined($opts{h}))) {

    die "You must specify a host to scan.\n";

}

if (defined($opts{m})) {

    if ($opts{m} =~ /OPTIONS|HEAD|GET/) {

        $request{'whisker'}->{'method'} = $opts{m};
    } else {

        die "You can only use OPTIONS, HEAD or GET for the method.\n";

    }
}

##установка URI, если он передан в командной строке
if (defined($opts{u})) {

    $request{'whisker'}->{'uri'} = $opts{u};

}

#”становка хоста, который мы хотим сканировать
$request{'whisker'}->{'host'} = $opts{h};

#ќбеспечиваем совместимость с RFC
LW2::http_fixup_request(\%request);

#ѕроизводим сканирование
if(LW2::http_do_request(\%request,\%response)){

    print 'ERROR: ', $response{'whisker'}->{'error'}, "\n";
    print $response{'whisker'}->{'data'}, "\n";

} else {

    #ѕолучаем информацию из хэш-массива 
	#'$headers_array' это ссылка
    $headers_array = $response{'whisker'}->{'header_order'};
    print "\n\n";
    print "HTTP " ,$response{'whisker'}->{'version'}, "\t";
    print $response{'whisker'}->{'code'} , "\n";

    foreach $header (@$headers_array) {

        print "$header";
        print "\t$response{$header}\n";

    }

##если использована опци€ 'd' выводим некоторую информацию
    if (defined($opts{d})) {

        print "\n\n-----------------------------
			-----------------------------\n\n";
        print $response{'whisker'}->{'data'} , "\n";

    }
}

“еперь добавим возможность изменени€ пол€ 'User-Agent' HTTP заголовка. –азработчики использует его, чтобы определитьс€ использует ли клиент поддерживаемый ими браузер. ѕо умолчанию 'User-Agent', используемый Libwhisker, установлен в 'Mozilla (libwhisker/2.0)'. ћы добавим поддержку трех различных браузеров, Netscape 7.1, Microsoft IE 6 и Mozilla Firefox 0.9.

„тобы подделать 'User-Agent' мы добавим опцию '-U', котора€ будет использоватьс€ в сочетании с N (Netscape), I (Internet Explorer) или F (Mozilla Firefox). ќднако подделать браузер гораздо сложнее, чем просто изменить поле 'User-Agent' HTTP заголовка. ¬ большинстве случаев наш способ сработает, но каждый браузер также имеет какие-то свои, специфичные пол€ заголовка. ≈сли вы хотите полностью подделать браузер, нужно сначала определить, какие специфичные пол€ заголовка он использует и какие значение в них передаютс€, а затем соответственно установить эти пол€ в вашем скрипте.

Ќам также нужно добавить поддержку метода POST. Ќекоторые приложени€ требуют, чтобы пользователь открыл сеанс перед отправкой данных методом POST, поэтому мы должны получить cookies из ответа сервера и установить их дл€ осуществлени€ POST запроса. ќдин минус этого состоит в том, что URI, который мы будем определ€ть, использу€ опцию '-u', должен использоватьс€ только в POST запросе. ¬начале скрипт сделает простой GET запрос и получить cookie, затем, перед вызовом 'LW2::http_do_request', установит cookie в POST запросе. Ќиже показан скрипт, позвол€ющий измен€ть поле 'User-Agent' HTTP заголовка, а также делать POST запросы. ќпци€ '-D' будет использоватьс€ дл€ определени€ данных, которые должны находитс€ в POST запросе.

Ќиже находитс€ заключительный вариант нашего скрипта, который теперь может выполнить все п€ть ранее поставленных задач.

#ћодули, которые мы будем использовать.
use strict;
use LW2;
use Getopt::Std;

#’эш-массивы дл€ опций командной строки, запросов, ответов и cookies
my (%opts, %request, %response, , %jar, $headers_array, $header);

##обратите внимание, добавлены опции 'U' и 'D'
getopts('dh:m:u:U:D:', \%opts);

#»нициализаци€ всех переменных запроса. Ќекоторые из них будут перезаписаны.
LW2::http_init_request(\%request);

if (!(defined($opts{h}))) {

    die "You must specify a host to scan.\n";

}

if (defined($opts{m})) {
##по умолчание GET, если €вно указано, то POST
    if ($opts{m} =~ /OPTIONS|HEAD|GET/) {

        $request{'whisker'}->{'method'} = $opts{m};
    }
}

if (defined($opts{u})) {
##не устанавливать URI, если используем метод POST
   $request{'whisker'}->{'uri'} = $opts{u} unless ($opts{m} eq "POST");

}

##установка 'User-Agent' по опции 'U'
##'F', 'I' или 'N' дл€ Firefox/IE/Netscape
##как и указано в тексте
if (defined($opts{U})) {

    if ($opts{U} eq "F") {

        $request{'User-Agent'} = 
		"Mozilla/5.0 (Windows; U; Windows NT 5.1; 
		en-US; rv:1.7) Gecko/20040614 Firefox/0.9";

    } elsif ($opts{U} eq "I") {

        $request{'User-Agent'} = 
		"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)";

    } elsif ($opts{U} eq "N") {

        $request{'User-Agent'} = 
		"Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.4) 
		Gecko/20030624 Netscape/7.1 (ax)";

    } else {

        die "You did not specify a supported \'User-Agent\'.\n";

    }
}

#”становка хоста, который мы хотим сканировать
$request{'whisker'}->{'host'} = $opts{h};

#ќбеспечиваем совместимость с RFC
LW2::http_fixup_request(\%request);

#ѕроизводим сканирование
H_REQUEST:
if(LW2::http_do_request(\%request,\%response)){

    print 'ERROR: ', $response{'whisker'}->{'error'}, "\n";
    print $response{'whisker'}->{'data'}, "\n";

} else {
##иначе сохраним cookie дл€ следующего запроса
    LW2::cookie_read(\%jar, \%response);
    #ѕолучаем информацию из хэш-массива 
	#'$headers_array' это ссылка
    $headers_array = $response{'whisker'}->{'header_order'};
    print "\n\n";
    print "HTTP " ,$response{'whisker'}->{'version'}, "\t";
    print $response{'whisker'}->{'code'} , "\n";

    foreach $header (@$headers_array) {

        print "$header";
        print "\t$response{$header}\n";

    }

    if (defined($opts{d})) {

        print "\n\n----------------------------------
				------------------------\n\n";
        print $response{'whisker'}->{'data'} , "\n";

    }

    if ($opts{m} eq "POST") {

        LW2::cookie_write(\%jar, \%request);
        $request{'whisker'}->{'method'} = "POST";
        $request{'whisker'}->{'uri'} = $opts{u};
        $request{'whisker'}->{'data'} = $opts{d  };
        LW2::http_fixup_request(\%request);
        $opts{d} = undef;
        $opts{m} = undef;
        goto H_REQUEST;

    }
}

«аключение

Ќаличие ваших собственных скриптов и утилит может быть очень удобно дл€ тестировани€ веб приложений. ќдин из плюсов этого - вы знаете, как эти утилиты работают, и можете добавить новые функциональные возможности, в соответствии с вашими потребност€ми. Ёто также помогает в понимании принципов работы приложени€.

ћногие утилиты, провед€ простое тестирование, могут сказать пользователю, что приложение у€звимо, но иногда требуетс€ большее. Libwhisker можно использовать дл€ автоматизации процесса сбора информации, как это было показано здесь. “ак же как и многие утилиты дл€ проверки защиты, использующие libnet и libpcap, дл€ создани€ и приема специфичных пакетов, Libwhisker предоставл€ет нам тот же уровень функциональных возможностей дл€ создани€ и анализа HTTP пакетов и может быть очень полезен испытателю на проникновение.

или введите им€

CAPTCHA