Всем привет, меня зовут Ваагн Варданян (тут нет опечатки, как многие думают :) ), работаю я в DSec исследователем безопасности SAP-систем, и в этой небольшой статье расскажу о связке уязвимостей в SAP, использование которых может привести к компрометации системы и как результат – доступу к критичной бизнес информации.
С каждой новой версией SAP NW, приложения становятся все более защищёнными, и уязвимости не дают скомпрометировать систему полностью. Но бывают ситуации, когда несколько проблем безопасности, используемых вместе, все же позволяют атакующим добиться своих целей. Сегодня мы расскажем о том, как скомпрометировать SAP NW с помощью связки уязвимостей.
В статье сначала мы поговорим о возможности получения информации из системы, об эксплуатации уязвимости, основанной на утечке информации, далее — об эскалации привилегий. Все уязвимости были найдены в последних (на момент исследования) версиях SAP (SAP NW AS JAVA 7.4). Ну что ж, понеслось.
![](https://habrastorage.org/files/17c/5a2/a60/17c5a2a601e64fe7abbd3e4c5c6df218.jpeg)
Введение
На сервере SAP AS JAVA есть множество стандартных приложений, которые хранятся в папке C:\usr\sap\%SID%\J00\j2ee\cluster\apps\sap.com, где %SID% — это SID SAP-системы. Так, наша тестовая система имеет SID DM0.
Из приведенного ниже скриншота можно понять, что в стандартной сборке SAP NW присутствует более 1400 компонентов (если установить полную сборку, то выйдет и более 2000), которые могут быть вызваны пользователями SAP'a с различными правами.
![](https://habrastorage.org/files/272/9fc/9ec/2729fc9ec6554f008bc1b97cb864d2fd.png)
Каждый компонент, который можно вызвать, имеет некий уровень доступа, описанный в файлах web.xml, portalapp.xml. Всего существует 4 вида прав доступа к компонентам:
![](https://habrastorage.org/files/fe6/4dc/f45/fe64dcf454864ab6bc479c619e6fbb19.png)
Естественно, нас будут интересовать сервлеты, приложения и компоненты, которые имеют права no_safety, либо такие, у которых права вообще не предопределены, поскольку они доступны извне, и любой неавторизованный пользователь может получить к ним доступ.
Перейдем к первой уязвимости.
Уязвимость разглашения информации
После поиска файлов конфигураций файл дескрипторов, в которых есть описание прав доступа
<property name="SafetyLevel" value="no_safety"/>
или оно полностью отсутствует. Был найден webdynpro компонент tc~rtc~coll.appl.rtc~wd_chat. Вот его конфигурационный файл:
![](https://habrastorage.org/files/f6a/42a/825/f6a42a8254134b4bafc0f60548c09f0f.png)
К данному сервису можно обратится по следующему адресу:
http:/SAP_IP:SAP_PORT/webdynpro/resources/sap.com/tc~rtc~coll.appl.rtc~wd_chat/Chat#
Oткрываем страницу и видим некоторый функционал по отправке сообщений. Среди прочего, в нем есть возможность добавления адресатов (пользователей):
![](https://habrastorage.org/files/db5/c40/bd2/db5c40bd2fd44896ab40030c7d4885bb.png)
Нажав на запись add participant, можем увидеть окно, которое предлагает поискать пользователя без авторизации.
![](https://habrastorage.org/files/525/a80/9d6/525a809d615d4bdc8ed98aad51a8fdf7.png)
Очень интересно, что в списке был найден пользователь с именем Jon Snow и логином J.Snow.
Гмм… Похоже, используя данную уязвимость, можно получить список логинов пользователей SAP. Однако, этого недостаточно для компрометации системы, поскольку после того, как 3 – 5 раз будет введет неправильный пароль, учетная запись будет блокирована. Так что давайте поищем другие уязвимости.
SQL injection
Следующий анонимный сервис, в котором была найдена уязвимость – UDDISecurityService.
На сервере SAP данный сервис находится по адресу: C:\usr\sap\DM0\J00\j2ee\cluster\apps\sap.com\tc~uddi\servlet_jsp\UDDISecurityService\
Как видно из конфигурационного файла, сервис также доступен анонимно:
![](https://habrastorage.org/files/dcd/b04/bf3/dcdb04bf37704638832ce541641e5781.png)
Тег servlet-class показывает, что доступ к данному сервлету можно получить с помощью SOAP-запросов. Теперь перед нами стоит задача найти структуру SOAP-запроса. Известно, что структуру запросов можно узнать, найдя wsdl-файл, в котором описан данный сервис. Получается, что нам надо найти wsdl файл, содержащий запись UDDISecurityImplBean. Используя total commander, запустим поиск.
![](https://habrastorage.org/files/f96/867/e23/f96867e233874949aab3b5a74b1728cb.png)
На сервере нашелся файл, содержащий нужную нам информацию. Поскольку он имеет wsdl-структуру, преобразовать его в SOAP-запрос можно, используя специальную утилиту. Мы выяснили, что в данном файле описано 2 метода: applyPermission и deletePermissionById.
![](https://habrastorage.org/files/b60/e5b/715/b60e5b715cdc49609cf6d031c6f2e80f.png)
Выберем второй метод (deletePermissionById), сгенерируем SOAP-запрос и отправим его на сервер SAP.
![](https://habrastorage.org/files/aad/a39/bfb/aada39bfb24945b8bf014241aa79df87.png)
В ответе получим:
![](https://habrastorage.org/files/5a0/81b/ae4/5a081bae4bd949e3b5cb0c796510f951.png)
Ответ вернул 200-ый код, но логика обработки отправленных данных непонятна. Чтобы «познакомиться» с полным функционалом данной программы, надо найти на сервере JAVA-код, обрабатывающий SAOP-запрос. И мы обнаруживаем jar-файл, в котором есть описание обработки данного запроса, и расположенный на сервере по адресу:
C:\usr\sap\%SID%\J00\j2ee\cluster\apps\sap.com\tc~uddi\EJBContainer\applicationjars\tc~esi~uddi~server~ejb~ejbm.jar
После декомпиляции файла можем увидеть следующие классы:
![](https://habrastorage.org/files/601/91a/095/60191a095fb2408d9110e6abe1b41a66.png)
Сама обработка запроса происходит в классе UDDISecurityBean.
![](https://habrastorage.org/files/04b/8d8/03f/04b8d803f0eb4628aa119d1c916c1516.png)
Когда мы отправляем запрос deletePermissionById, видно, как появляется конструктор PermissionsDao(), который вызывает функцию deletePermision. Переходим в класс PermissionsDao.
![](https://habrastorage.org/files/c4d/783/919/c4d78391971a45f89c338fe8d85b2f4e.png)
Данные, передаваемые через SOAP-запрос, используются для обращения к базе данных сервера SAP без фильтрации. Можно предположить, что тут есть SQL injection. Чтобы наверняка убедиться в этом, необходимо отправить специальный запрос для SQL injection и посмотреть логи базы данных сервера SAP. Файлы логов базы данных находятся по умолчанию в папке C:\usr\sap\%SID%\J00\j2ee\cluster\server0\log\system\ и называются по умолчанию database_NN.N.log, где N – число от 0 до 9 включительно.
Отправим следующий запрос:
![](https://habrastorage.org/files/1a6/698/b68/1a6698b6876d42efb6b7fad2af04366f.png)
В ответе также получим 200-ый код:
![](https://habrastorage.org/files/09f/8d2/6f3/09f8d26f362e45c3ad7ace47aef89171.png)
Но в логах базы данных можно заметить следующее:
![](https://habrastorage.org/files/cdd/6e7/0dc/cdd6e70dcd37442f8ddf49e57230049d.png)
Теперь точно можно говорить о том, что у нас есть анонимная SQL-инъекция в базу данных SAP. Удалим логи с сервера и отправим следующий запрос. Если на сервере в логах не возникнут ошибки, то структура SQL-запроса правильная.
![](https://habrastorage.org/files/282/652/2ca/2826522ca7274d2cb8c15d93e16cd343.png)
Ошибок нет.
![](https://habrastorage.org/files/bb7/a74/568/bb7a74568f05426aa0126d9cee29f89c.png)
Теперь новая задача — найти запрос, который поможет получить критичные данные из базы данных SAP, например, хеш пароля Jon Snow. Из документации SAP NW AS JAVA известно, что данные о пользователях (логин, именa, хеши пароля) хранятся в таблице UME_STRINGS.
Запрос для получения всех данных из UME_STRINGS имеет следующий вид:
![](https://habrastorage.org/files/56e/eea/802/56eeea8021c14dfc96ca8165f7e01d23.png)
![](https://habrastorage.org/files/373/c5c/0d6/373c5c0d6e1648d088deb32a3f62daba.png)
Как видно, данная SQL injection vulnerability не error based, а адаптер, который используется в этом сервлете и не поддерживает sleep() функцию. Будем использовать метод умножения таблиц для увеличения времени обработки запроса и превратим данную уязвимость в time-based SQL injection. Для этого надо найти таблицу, в которой всегда во всех SAP-серверах будут содержаться данные. Такая таблица — J2EE_CONFIG, в которой хранится информация о конфигурации компонентов.
Oправим следующий запрос:
![](https://habrastorage.org/files/0e4/499/7da/0e44997da2bc4de596c14f3262a08ea9.png)
Сервер, получая запрос, пробует извлечь данные из БД, предварительно умножив 2 таблицы — UME_STRINGS и J2EE_CONFIG. Поскольку в таблицах хранятся данные большого объёма, произойдет временная нагрузка на сервер.
![](https://habrastorage.org/files/690/fd3/e89/690fd3e89969429894e1dfaa3fc102b5.png)
А ответ мы получаем спустя 32 секунды. И – готово: time-based SQL injection.
![](https://habrastorage.org/files/321/510/a9f/321510a9f49e445d8740045bcb1e2b4d.png)
Получение хеша администратора
Как уже говорилось выше, захешированные пароли хранятся в таблице UME_STRINGS, которая имеет следующую структуру:
![](https://habrastorage.org/files/7d3/e61/953/7d3e6195380c4b8e87e3616c9b3e6a55.png)
В таблице UME_STRINGS.PID хранятся имена пользователей.
UME_STRINGS.ATTR = 'j_password' показывает, что пользователь создан и присутствует в SAP AS JAVA стеке.
UME_STRINGS.VAL хранит хеши паролей от пользователей, логины которых записаны в UME_STRINGS.PID.
Выходит, что надо подобрать данные, содержащиеся в поле UME_STRINGS.VAL. Базовый SQL-запрос для injection выглядит так:
SELECT COUNT(*) FROM J2EE_CONFIG, UME_STRINGS WHERE UME_STRINGS.ATTR='j_password' AND UME_STRINGS.PID LIKE '%J.Snow%' AND UME_STRINGS.VAL LIKE '%'
Известно, что пароль хранится в базе данных SAP в захешированном виде, алгоритм хеширования может быть следующим:
SAPSHA
SSHA
SHA
SHA-512
Т.е. в хеше паролей могут быть такие символы:
1234567890QWERTYUIOPASDFGHJKLZXCVBNM*.,{}#+:-=qwertyuiopasdfghjklzxcvbnm/{SPACE}
Будем перебирать их, и, если символ, который мы выбрали, совпадает с символом хеша из пароля, у нас будет задержка запроса.
![](https://habrastorage.org/files/702/677/c50/702677c5091146408e502dedbe95069a.png)
Ответ будет задержан на 1 секунду.
![](https://habrastorage.org/files/eec/05a/549/eec05a549c394875badcde743fd74b43.png)
Автоматизируя этот процесс, получим хеш от пользователя Jon Snow.
{SHA-512, 10000, 24}YXNkUVdFMTIzzbAIcuqnw5RzpmdgZ38PWjhBeaGzHkV6XINN7ZDqxqgr0nYxfCaE5ncdK7kzzkzryJAn42qv9YlY034Llr4b8Rv1534chnIf1i8jZE6ylzTV5XuzvUlaXQ==
![](https://habrastorage.org/files/846/2e5/a5a/8462e5a5a51d470ba1d307225ef3efa2.png)
Как видно, пароль захеширован алгоритмом SHA-512. На этом исследование бы закончилось, если бы не третья уязвимость.
Криптографическая ошибка, эскалации привилегий
Эта уязвимость была найдена случайно :-)
С помощью SQL injection получили хеш пароля пользователя Jon Snow:
{SHA-512, 10000, 24}YXNkUVdFMTIzzbAIcuqnw5RzpmdgZ38PWjhBeaGzHkV6XINN7ZDqxqgr0nYxfCaE5ncdK7kzzkzryJAn42qv9YlY034Llr4b8Rv1534chnIf1i8jZE6ylzTV5XuzvUlaXQ==
Хммм. Как видно, в конце хеша есть символы ==. А что будет, если мы сделаем base64decode?
![](https://habrastorage.org/files/8fa/4c0/127/8fa4c012747749e6bba2cab6a5be6b45.png)
![](https://habrastorage.org/files/3d3/7cf/d62/3d37cfd6290b4495b499f7920f26957e.jpg)
Что? Как? Пароль? Есть единственный способ проверить, действительно ли это пароль от Jon'a — зайти на портал, используя логин J.Snow и пароль asdQWE123.
![](https://habrastorage.org/files/8b8/597/d42/8b8597d421874165968cbb0ed8ea080b.png)
Ура! Я администратор! Но как? Надо разобраться, с чем связан тот факт, что пароль находится в формате base64 в БД.
В результате поиска, мы нашли файл sap.com~tc~sec~ume~core~impl.jar, который находится в папке: C:\usr\sap\DM0\J00\j2ee\cluster\bin\ext\com.sap.security.core.sda\lib\private. Он содержит функции, которые отвечают за хеширование пароля пользователей, проверку их валидности, блокировку пользователей и т.д. Один из основных классов — PasswordHash. Рассмотрим этот класс подробнее.
![](https://habrastorage.org/files/068/133/b9c/068133b9cea846c1990025fffc488912.png)
Он имеет 2 конструктора, один из которых
public PasswordHash(String user, String password)
{
this._user = user;
this._password = password;
this._extra = null;
}
Как мы видим, он инициализирует внутренние переменные user и password.
Чтобы из пароля получить хеш, используется другая функция getHash класса PasswordHash.
![](https://habrastorage.org/files/3d5/cc8/08d/3d5cc808deb546f880cb12b36ec0cb81.png)
Как видно из строки 114, эта функция вызывает createHashWithIterations функцию, которая принимает случайное значение на вход в качестве соли для генерации хеша. Перейдем в функцию createHashWithIterations(salt)
![](https://habrastorage.org/files/3bc/876/078/3bc87607881442b3b7c25fb797a31525.png)
На строке 184 инициализируется переменная output, хранящая байты введенного пароля пользователя.
В строке 185 создается новая переменная pass_n_salt, состоящая из байтов пароля и случайной соли, сгенерированной в строке 112.
Далее в строке 191 вызывается функция hashWithIterations, принимающая на вход 2 параметра — output и pass_n_salt. Заметим, что в output хранится пароль asdQWE123 в байтах.
![](https://habrastorage.org/files/e6f/f3b/72e/e6ff3b72e1c6443abe568ea516492f30.png)
Так, интересно. Рассмотрим каждую строку по отдельности:
Строка 238 инициализирует переменную output, в которой записываются данные из переменной data (первые байты переменной data – пароль asdQWE123).
Строка 241 инициализируется переменная md класса MessageDigest, которая будет отвечать за хеширование данных.
Строка 243 начинает цикл для хеширования, _iterations = 10000.
Строки 244-245 хешируют данные по алгоритму SHA-512 и записываются в переменную data.
Строка 246, переменная output обнуляется.
Строка 247, в переменную output записываются данные из переменной pass (asdQWE123).
Строка 248, в конец переменной output записываются данные из data.
Получатся, что переменная output будет иметь следующую структуру:
![](https://habrastorage.org/files/553/0c7/804/5530c7804bfe4b869daa3305ea5576ff.png)
Вся эта логика будет исполнена 10?000 раз, и в последнем шаге цикла в начало переменной output будет добавлен пароль, после пароля – захешированные данные. Тем самым, первые байты переменной output будут состоять из незахешированого пароля.
Блок-схема уязвимого участка кода:
pass = plain_pass
output = [plain_pass]+[random_byte]
i=0
data = sha_512(output)
output = [NULL]
output = [plain_pass]+[data]
for(i)i = i + 1
if i==10000
exit_from_loop
output == «asdQWE123blablabla»
Ошибка программистов состояла в том, что они не хешируют данные в последнем шаге цикла for. Данная уязвимость уже закрыта, и исправление выглядит вот так:
pass = plain_pass
output = [plain_pass]+[random_byte]
i=0
output = [plain_pass]+[data]
data = sha_512(output)
for(i)i = i + 1
if i==10000
exit_from_loop
![](https://habrastorage.org/files/2a9/584/cd6/2a9584cd6ab94250ace474fc878540bc.png)
Как мы видим, SAP поменял порядок шагов, теперь сначала происходит инициализация переменной оutput, а затем хеширование данных переменной.
Заключение
Итак, давайте посмотрим, какие ноты безопасности выпустил SAP для исправления данных уязвимостей.
Разглашение пользователей, логинов – SAP nota 2255990, уязвимость была исправлена 8-ого мая 2016-ого года. Имеет уже CVE-шку CVE-2016-3973 (CVSS v3 7.5).
Список уязвимых версий SAP:
![](https://habrastorage.org/files/eb0/f8b/012/eb0f8b012eeb4ed8b712aa9f626c630a.png)
Для исправления SQL injection была выпущена SAP security note 2101079, была исправлена 9-ого февраля 2016-ого года, CVE-2016-2386 (CVSS v3 9.1).
Список уязвимых версий SAP:
![](https://habrastorage.org/files/617/7c9/277/6177c9277aab49afa5ed637e5fa08b78.png)
Уязвимость с неправильной реализацией хеширования паролей лечится нотой 2191290. Нота выпущена 12 января 2016-ого, CVE-2016-1910 (CVSS v3 5.3).
Список уязвимых версий SAP:
![](https://habrastorage.org/files/d78/242/04f/d7824204fec04737b84f8f1ee0f92ab5.png)
Конечно, кто-то из вас может сказать, мол, установили какой-то «кривой сервер» и нашли баги, но и для этого есть статистика только по разглашению списка пользователей SAP-a. Сканирование проводилось по 7348 SAP-серверам, которые доступны через Интернет.
![](https://habrastorage.org/files/5bc/df4/3bd/5bcdf43bd7d44d639de349548d35a6cf.png)
Статистика по каждому порту
![](https://habrastorage.org/files/685/9ab/7bf/6859ab7bf42f492e83b5bb9566371774.png)
В сумме выходит, что, к уязвимости разглашения информации подвержены около 1013 серверов (~14%)
![](https://habrastorage.org/files/0f8/e6c/bc6/0f8e6cbc62274a40a078ea6878ee57b4.png)
Ну и еще одна табличка по статистике ДОСТУПНОСТИ сервлета в котором может быть уязвимость SQL injection (если еще не установлен патч)
![](https://habrastorage.org/files/fb2/b78/236/fb2b782366894110853d988018abd41f.png)
Суммарно – 2174 серверов, что составляет ~30%
Выходит, что нужно делать?
Нужно патчиться, товарищи администраторы.
Да, и напоследок: хочешь у нас работать и находить еще более крутые баги – присылай свое резюме сюда
Noyer
Очень интересно и необычно! Думаю коммьюнити поддержит, если я попрошу чаще публиковать подобные статьи!