SЯP wrong эncяyptioи или как скомпрометировать всех пользователей в SAP JAVA

в 9:34, , рубрики: base64, encryption, sap, Блог компании «Digital Security», информационная безопасность

Всем привет, меня зовут Ваагн Варданян (тут нет опечатки, как многие думают :) ), работаю я в DSec исследователем безопасности SAP-систем, и в этой небольшой статье расскажу о связке уязвимостей в SAP, использование которых может привести к компрометации системы и как результат – доступу к критичной бизнес информации.

С каждой новой версией SAP NW, приложения становятся все более защищёнными, и уязвимости не дают скомпрометировать систему полностью. Но бывают ситуации, когда несколько проблем безопасности, используемых вместе, все же позволяют атакующим добиться своих целей. Сегодня мы расскажем о том, как скомпрометировать SAP NW с помощью связки уязвимостей.

В статье сначала мы поговорим о возможности получения информации из системы, об эксплуатации уязвимости, основанной на утечке информации, далее — об эскалации привилегий. Все уязвимости были найдены в последних (на момент исследования) версиях SAP (SAP NW AS JAVA 7.4). Ну что ж, понеслось.

SЯP wrong эncяyptioи или как скомпрометировать всех пользователей в SAP JAVA - 1

Введение
На сервере SAP AS JAVA есть множество стандартных приложений, которые хранятся в папке C:usrsap%SID%J00j2eeclusterappssap.com, где %SID% — это SID SAP-системы. Так, наша тестовая система имеет SID DM0.
Из приведенного ниже скриншота можно понять, что в стандартной сборке SAP NW присутствует более 1400 компонентов (если установить полную сборку, то выйдет и более 2000), которые могут быть вызваны пользователями SAP'a с различными правами.

SЯP wrong эncяyptioи или как скомпрометировать всех пользователей в SAP JAVA - 2

Каждый компонент, который можно вызвать, имеет некий уровень доступа, описанный в файлах web.xml, portalapp.xml. Всего существует 4 вида прав доступа к компонентам:

SЯP wrong эncяyptioи или как скомпрометировать всех пользователей в SAP JAVA - 3

Естественно, нас будут интересовать сервлеты, приложения и компоненты, которые имеют права no_safety, либо такие, у которых права вообще не предопределены, поскольку они доступны извне, и любой неавторизованный пользователь может получить к ним доступ.
Перейдем к первой уязвимости.

Уязвимость разглашения информации
После поиска файлов конфигураций файл дескрипторов, в которых есть описание прав доступа

<property name="SafetyLevel" value="no_safety"/>

или оно полностью отсутствует. Был найден webdynpro компонент tc~rtc~coll.appl.rtc~wd_chat. Вот его конфигурационный файл:

SЯP wrong эncяyptioи или как скомпрометировать всех пользователей в SAP JAVA - 4

К данному сервису можно обратится по следующему адресу:
http:/SAP_IP:SAP_PORT/webdynpro/resources/sap.com/tc~rtc~coll.appl.rtc~wd_chat/Chat#

Oткрываем страницу и видим некоторый функционал по отправке сообщений. Среди прочего, в нем есть возможность добавления адресатов (пользователей):

SЯP wrong эncяyptioи или как скомпрометировать всех пользователей в SAP JAVA - 5

Нажав на запись add participant, можем увидеть окно, которое предлагает поискать пользователя без авторизации.

SЯP wrong эncяyptioи или как скомпрометировать всех пользователей в SAP JAVA - 6

Очень интересно, что в списке был найден пользователь с именем Jon Snow и логином J.Snow.
Гмм… Похоже, используя данную уязвимость, можно получить список логинов пользователей SAP. Однако, этого недостаточно для компрометации системы, поскольку после того, как 3 – 5 раз будет введет неправильный пароль, учетная запись будет блокирована. Так что давайте поищем другие уязвимости.

SQL injection

Следующий анонимный сервис, в котором была найдена уязвимость – UDDISecurityService.
На сервере SAP данный сервис находится по адресу: C:usrsapDM0J00j2eeclusterappssap.comtc~uddiservlet_jspUDDISecurityService
Как видно из конфигурационного файла, сервис также доступен анонимно:

SЯP wrong эncяyptioи или как скомпрометировать всех пользователей в SAP JAVA - 7

Тег servlet-class показывает, что доступ к данному сервлету можно получить с помощью SOAP-запросов. Теперь перед нами стоит задача найти структуру SOAP-запроса. Известно, что структуру запросов можно узнать, найдя wsdl-файл, в котором описан данный сервис. Получается, что нам надо найти wsdl файл, содержащий запись UDDISecurityImplBean. Используя total commander, запустим поиск.

SЯP wrong эncяyptioи или как скомпрометировать всех пользователей в SAP JAVA - 8

На сервере нашелся файл, содержащий нужную нам информацию. Поскольку он имеет wsdl-структуру, преобразовать его в SOAP-запрос можно, используя специальную утилиту. Мы выяснили, что в данном файле описано 2 метода: applyPermission и deletePermissionById.

SЯP wrong эncяyptioи или как скомпрометировать всех пользователей в SAP JAVA - 9

Выберем второй метод (deletePermissionById), сгенерируем SOAP-запрос и отправим его на сервер SAP.

SЯP wrong эncяyptioи или как скомпрометировать всех пользователей в SAP JAVA - 10

В ответе получим:

SЯP wrong эncяyptioи или как скомпрометировать всех пользователей в SAP JAVA - 11

Ответ вернул 200-ый код, но логика обработки отправленных данных непонятна. Чтобы «познакомиться» с полным функционалом данной программы, надо найти на сервере JAVA-код, обрабатывающий SAOP-запрос. И мы обнаруживаем jar-файл, в котором есть описание обработки данного запроса, и расположенный на сервере по адресу:
C:usrsap%SID%J00j2eeclusterappssap.comtc~uddiEJBContainerapplicationjarstc~esi~uddi~server~ejb~ejbm.jar

После декомпиляции файла можем увидеть следующие классы:

SЯP wrong эncяyptioи или как скомпрометировать всех пользователей в SAP JAVA - 12

Сама обработка запроса происходит в классе UDDISecurityBean.

SЯP wrong эncяyptioи или как скомпрометировать всех пользователей в SAP JAVA - 13

Когда мы отправляем запрос deletePermissionById, видно, как появляется конструктор PermissionsDao(), который вызывает функцию deletePermision. Переходим в класс PermissionsDao.

SЯP wrong эncяyptioи или как скомпрометировать всех пользователей в SAP JAVA - 14

Данные, передаваемые через SOAP-запрос, используются для обращения к базе данных сервера SAP без фильтрации. Можно предположить, что тут есть SQL injection. Чтобы наверняка убедиться в этом, необходимо отправить специальный запрос для SQL injection и посмотреть логи базы данных сервера SAP. Файлы логов базы данных находятся по умолчанию в папке C:usrsap%SID%J00j2eeclusterserver0logsystem и называются по умолчанию database_NN.N.log, где N – число от 0 до 9 включительно.
Отправим следующий запрос:

SЯP wrong эncяyptioи или как скомпрометировать всех пользователей в SAP JAVA - 15

В ответе также получим 200-ый код:

SЯP wrong эncяyptioи или как скомпрометировать всех пользователей в SAP JAVA - 16

Но в логах базы данных можно заметить следующее:

SЯP wrong эncяyptioи или как скомпрометировать всех пользователей в SAP JAVA - 17

Теперь точно можно говорить о том, что у нас есть анонимная SQL-инъекция в базу данных SAP. Удалим логи с сервера и отправим следующий запрос. Если на сервере в логах не возникнут ошибки, то структура SQL-запроса правильная.

SЯP wrong эncяyptioи или как скомпрометировать всех пользователей в SAP JAVA - 18

Ошибок нет.

SЯP wrong эncяyptioи или как скомпрометировать всех пользователей в SAP JAVA - 19

Теперь новая задача — найти запрос, который поможет получить критичные данные из базы данных SAP, например, хеш пароля Jon Snow. Из документации SAP NW AS JAVA известно, что данные о пользователях (логин, именa, хеши пароля) хранятся в таблице UME_STRINGS.
Запрос для получения всех данных из UME_STRINGS имеет следующий вид:

SЯP wrong эncяyptioи или как скомпрометировать всех пользователей в SAP JAVA - 20
SЯP wrong эncяyptioи или как скомпрометировать всех пользователей в SAP JAVA - 21

Как видно, данная SQL injection vulnerability не error based, а адаптер, который используется в этом сервлете и не поддерживает sleep() функцию. Будем использовать метод умножения таблиц для увеличения времени обработки запроса и превратим данную уязвимость в time-based SQL injection. Для этого надо найти таблицу, в которой всегда во всех SAP-серверах будут содержаться данные. Такая таблица — J2EE_CONFIG, в которой хранится информация о конфигурации компонентов.

Oправим следующий запрос:

SЯP wrong эncяyptioи или как скомпрометировать всех пользователей в SAP JAVA - 22

Сервер, получая запрос, пробует извлечь данные из БД, предварительно умножив 2 таблицы — UME_STRINGS и J2EE_CONFIG. Поскольку в таблицах хранятся данные большого объёма, произойдет временная нагрузка на сервер.

SЯP wrong эncяyptioи или как скомпрометировать всех пользователей в SAP JAVA - 23

А ответ мы получаем спустя 32 секунды. И – готово: time-based SQL injection.

SЯP wrong эncяyptioи или как скомпрометировать всех пользователей в SAP JAVA - 24

Получение хеша администратора
Как уже говорилось выше, захешированные пароли хранятся в таблице UME_STRINGS, которая имеет следующую структуру:

SЯP wrong эncяyptioи или как скомпрометировать всех пользователей в SAP JAVA - 25

В таблице 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}

Будем перебирать их, и, если символ, который мы выбрали, совпадает с символом хеша из пароля, у нас будет задержка запроса.

SЯP wrong эncяyptioи или как скомпрометировать всех пользователей в SAP JAVA - 26

Ответ будет задержан на 1 секунду.

SЯP wrong эncяyptioи или как скомпрометировать всех пользователей в SAP JAVA - 27

Автоматизируя этот процесс, получим хеш от пользователя Jon Snow.

{SHA-512, 10000, 24}YXNkUVdFMTIzzbAIcuqnw5RzpmdgZ38PWjhBeaGzHkV6XINN7ZDqxqgr0nYxfCaE5ncdK7kzzkzryJAn42qv9YlY034Llr4b8Rv1534chnIf1i8jZE6ylzTV5XuzvUlaXQ== 

SЯP wrong эncяyptioи или как скомпрометировать всех пользователей в SAP JAVA - 28

Как видно, пароль захеширован алгоритмом SHA-512. На этом исследование бы закончилось, если бы не третья уязвимость.

Криптографическая ошибка, эскалации привилегий
Эта уязвимость была найдена случайно :-)
С помощью SQL injection получили хеш пароля пользователя Jon Snow:

{SHA-512, 10000, 24}YXNkUVdFMTIzzbAIcuqnw5RzpmdgZ38PWjhBeaGzHkV6XINN7ZDqxqgr0nYxfCaE5ncdK7kzzkzryJAn42qv9YlY034Llr4b8Rv1534chnIf1i8jZE6ylzTV5XuzvUlaXQ== 

Хммм. Как видно, в конце хеша есть символы ==. А что будет, если мы сделаем base64decode?

SЯP wrong эncяyptioи или как скомпрометировать всех пользователей в SAP JAVA - 29
SЯP wrong эncяyptioи или как скомпрометировать всех пользователей в SAP JAVA - 30

Что? Как? Пароль? Есть единственный способ проверить, действительно ли это пароль от Jon'a — зайти на портал, используя логин J.Snow и пароль asdQWE123.

SЯP wrong эncяyptioи или как скомпрометировать всех пользователей в SAP JAVA - 31

Ура! Я администратор! Но как? Надо разобраться, с чем связан тот факт, что пароль находится в формате base64 в БД.

В результате поска, мы нашли файл sap.com~tc~sec~ume~core~impl.jar, который находится в папке: C:usrsapDM0J00j2eeclusterbinextcom.sap.security.core.sdalibprivate. Он содержит функции, которые отвечают за хеширование пароля пользователей, проверку их валидности, блокировку пользователей и т.д. Один из основных классов — PasswordHash. Рассмотрим этот класс подробнее.

SЯP wrong эncяyptioи или как скомпрометировать всех пользователей в SAP JAVA - 32

Он имеет 2 конструктора, один из которых

  public PasswordHash(String user, String password) 
  { 
    this._user = user; 
    this._password = password; 
    this._extra = null; 
  } 

Как мы видим, он инициализирует внутренние переменные user и password.
Чтобы из пароля получить хеш, используется другая функция getHash класса PasswordHash.

SЯP wrong эncяyptioи или как скомпрометировать всех пользователей в SAP JAVA - 33

Как видно из строки 114, эта функция вызывает createHashWithIterations функцию, которая принимает случайное значение на вход в качестве соли для генерации хеша. Перейдем в функцию createHashWithIterations(salt)

SЯP wrong эncяyptioи или как скомпрометировать всех пользователей в SAP JAVA - 34

На строке 184 инициализируется переменная output, хранящая байты введенного пароля пользователя.
В строке 185 создается новая переменная pass_n_salt, состоящая из байтов пароля и случайной соли, сгенерированной в строке 112.
Далее в строке 191 вызывается функция hashWithIterations, принимающая на вход 2 параметра — output и pass_n_salt. Заметим, что в output хранится пароль asdQWE123 в байтах.

SЯP wrong эncяyptioи или как скомпрометировать всех пользователей в SAP JAVA - 35

Так, интересно. Рассмотрим каждую строку по отдельности:
Строка 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 будет иметь следующую структуру:

SЯP wrong эncяyptioи или как скомпрометировать всех пользователей в SAP JAVA - 36

Вся эта логика будет исполнена 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

SЯP wrong эncяyptioи или как скомпрометировать всех пользователей в SAP JAVA - 37

Как мы видим, SAP поменял порядок шагов, теперь сначала происходит инициализация переменной оutput, а затем хеширование данных переменной.

Заключение

Итак, давайте посмотрим, какие ноты безопасности выпустил SAP для исправления данных уязвимостей.

Разглашение пользователей, логинов – SAP nota 2255990, уязвимость была исправлена 8-ого мая 2016-ого года. Имеет уже CVE-шку CVE-2016-3973 (CVSS v3 7.5).
Список уязвимых версий SAP:

SЯP wrong эncяyptioи или как скомпрометировать всех пользователей в SAP JAVA - 38

Для исправления SQL injection была выпущена SAP security note 2101079, была исправлена 9-ого февраля 2016-ого года, CVE-2016-2386 (CVSS v3 9.1).
Список уязвимых версий SAP:

SЯP wrong эncяyptioи или как скомпрометировать всех пользователей в SAP JAVA - 39

Уязвимость с неправильной реализацией хеширования паролей лечится нотой 2191290. Нота выпущена 12 января 2016-ого, CVE-2016-1910 (CVSS v3 5.3).
Список уязвимых версий SAP:

SЯP wrong эncяyptioи или как скомпрометировать всех пользователей в SAP JAVA - 40

Конечно, кто-то из вас может сказать, мол, установили какой-то «кривой сервер» и нашли баги, но и для этого есть статистика только по разглашению списка пользователей SAP-a. Сканирование проводилось по 7348 SAP-серверам, которые доступны через Интернет.

SЯP wrong эncяyptioи или как скомпрометировать всех пользователей в SAP JAVA - 41

Статистика по каждому порту

SЯP wrong эncяyptioи или как скомпрометировать всех пользователей в SAP JAVA - 42

В сумме выходит, что, к уязвимости разглашения информации подвержены около 1013 серверов (~14%)

SЯP wrong эncяyptioи или как скомпрометировать всех пользователей в SAP JAVA - 43

Ну и еще одна табличка по статистике ДОСТУПНОСТИ сервлета в котором может быть уязвимость SQL injection (если еще не установлен патч)

SЯP wrong эncяyptioи или как скомпрометировать всех пользователей в SAP JAVA - 44

Суммарно – 2174 серверов, что составляет ~30%

Выходит, что нужно делать?
Нужно патчиться, товарищи администраторы.
Да, и напоследок: хочешь у нас работать и находить еще более крутые баги – присылай свое резюме сюда

Автор: Digital Security

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js