ЅЯР wrong эncяyptioи або як скомпрометувати всіх користувачів SAP JAVA

Всім привіт, мене звуть Ваагн Варданян (тут немає помилки, як багато хто думає :) ), працюю я в DSec дослідником безпеки SAP-систем, і в цій невеликій статті розповім про зв'язці вразливостей в SAP, використання яких може призвести до компрометації системи і як результат – доступу до критичної бізнес інформації.
З кожною новою версією SAP NW, додатки стають все більш захищеними, і уразливості не дають скомпрометувати систему повністю. Але бувають ситуації, коли кілька проблем безпеки, що використовуються разом, все ж дозволяють атакуючим домогтися своїх цілей. Сьогодні ми розповімо про те, як скомпрометувати SAP NW з допомогою зв'язки вразливостей.
У статті спочатку ми поговоримо про можливості отримання інформації з системи, про експлуатації уразливості, заснованої на витоку інформації, далі — про ескалації привілеїв. Всі уразливості знайдені в останніх (на момент дослідження) версіях SAP (SAP NW AS JAVA 7.4). Ну що ж, понеслося.


Введення
На сервері SAP AS JAVA є багато стандартних додатків, які зберігаються в папці C:\usr\sap\%SID%\J00\j2ee\cluster\apps\sap.com, де %SID% — це SID SAP-системи. Так, наша тестова система має SID DM0.
З наведеного нижче скріншота можна зрозуміти, що в стандартній збірці SAP NW присутні більше 1400 компонентів (якщо встановити повну збірку, то вийде понад 2000), які можуть бути викликані користувачами SAP'a з різними правами.

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

Звісно, нас будуть цікавити сервлети, програми та компоненти, які мають права no_safety, або такі, у яких права взагалі не визначені, оскільки вони доступні ззовні, і будь-неавторизований користувач може отримати до них доступ.
Перейдемо до першої уразливості.
Вразливість розголошення інформації
Після пошуку файлів конфігурацій файл дескрипторів, в яких є опис прав доступу
<property name="SafetyLevel" value="no_safety"/>

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

До даного сервісу можна звернутися за адресою:
http:/SAP_IP:SAP_PORT/webdynpro/resources/sap.com/tc~rtc~coll.appl.rtc~wd_chat/Chat#
Відкриваємо сторінку і бачимо деякий функціонал по відправці повідомлень. Серед іншого, в ньому є можливість додавання адресатів (користувачів):

Натиснувши на запис add participant, можемо побачити вікно, яке пропонує пошукати користувача без авторизації.

Дуже цікаво, що в списку був знайдений користувач з іменем 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\
Як видно з конфігураційного файлу, сервіс також доступний анонімно:

Тег servlet-class показує, що доступ до цього сервлету можна отримати з допомогою SOAP-запитів. Тепер перед нами стоїть завдання знайти структуру SOAP-запиту. Відомо, що структуру запитів можна дізнатися, знайшовши wsdl-файл, в якому описано даний сервіс. Виходить, що нам треба знайти wsdl-файл, що містить запис UDDISecurityImplBean. Використовуючи total commander, запустимо пошук.

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

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

У відповіді отримаємо:

Відповідь повернув 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
Після декомпіляції файлу можемо побачити наступні класи:

Сама обробка запиту відбувається в класі UDDISecurityBean.

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

Дані, що передаються через SOAP-запит, використовуються для звернення до сервера бази даних SAP без фільтрації. Можна припустити, що тут є SQL injection. Щоб напевно переконатися в цьому, необхідно відправити спеціальний запит SQL injection та подивитися логи бази даних сервера SAP. Лог-файли бази даних знаходяться за замовчуванням в папці C:\usr\sap\%SID%\J00\j2ee\cluster\server0\log\system\ і називаються за замовчуванням database_NN.N.log N, де N – число від 0 до 9 включно.
Відправимо наступний запит:

У відповіді також отримаємо 200-ий код:

Але в логах бази даних можна помітити наступне:

Тепер точно можна говорити про те, що у нас є анонімна SQL-ін'єкція в базу даних SAP. Видалимо логи сервера і відправимо наступний запит. Якщо на сервері в логах не виникнуть помилки, то структура SQL-запиту правильна.

Помилок немає.

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


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

Сервер, отримуючи запит, пробує витягнути дані з БД, попередньо помноживши 2 таблиці UME_STRINGS і J2EE_CONFIG. Оскільки в таблицях зберігаються дані великого обсягу, відбудеться тимчасова навантаження на сервер.

А відповідь ми отримуємо через 32 секунди. І – готово: time-based SQL injection.

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

У таблиці 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
США
SHA
SHA-512

тобто в хеше паролів можуть бути такі символи:
1234567890QWERTYUIOPASDFGHJKLZXCVBNM*.,{}#+:-=qwertyuiopasdfghjklzxcvbnm/{SPACE}

Будемо перебирати їх, і, якщо символ, який ми обрали, збігається з символом хеш з пароля, у нас буде затримка запиту.

Відповідь буде затриманий на 1 секунду.

Автоматизуючи цей процес, отримаємо хеш від користувача Jon Snow.
{SHA-512, 10000, 24}YXNkUVdFMTIzzbAIcuqnw5RzpmdgZ38Pwjhbeagzhkv6xinn7zdqxqgr0nyxfcae5ncdk7kzzkzryjan42qv9yly034llr4b8rv1534chnif1i8jze6ylztv5xuzvulaxq== 


Як видно, пароль захеширован алгоритмом SHA-512. На цьому дослідження б закінчилося, якби не третя вразливість.
Криптографічна помилка, ескалації привілеїв
Ця уразливість була знайдена випадково :-)
За допомогою SQL injection отримали хеш пароля користувача Jon Snow:
{SHA-512, 10000, 24}YXNkUVdFMTIzzbAIcuqnw5RzpmdgZ38Pwjhbeagzhkv6xinn7zdqxqgr0nyxfcae5ncdk7kzzkzryjan42qv9yly034llr4b8rv1534chnif1i8jze6ylztv5xuzvulaxq== 

Хммм. Як видно, в кінці хешу є символи ==. А що буде, якщо ми зробимо base64decode?


Що? Як? Пароль? Є єдиний спосіб перевірити, чи це дійсно пароль від Jon's a — зайти на портал, використовуючи логін J. Snow і пароль asdQWE123.

Ура! Я адміністратор! Але як? Треба розібратися, з чим пов'язаний той факт, що пароль знаходиться у форматі 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. Розглянемо цей клас докладніше.

Він має 2 конструктора, один з яких
public PasswordHash(String user, String password) 
{ 
this._user = user; 
this._password = password; 
this._extra = null; 
} 

Як ми бачимо, він ініціалізує внутрішні змінні user і password.
Щоб отримати хеш пароля, використовується інша функція getHash класу PasswordHash.

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

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

Так, цікаво. Розглянемо кожний рядок окремо:
Рядок 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 буде мати наступну структуру:

Вся ця логіка буде виконана 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

Як ми бачимо, SAP поміняв порядок кроків, тепер спочатку відбувається ініціалізація змінної оutput, а потім хешування даних змінної.
Висновок
Отже, давайте подивимося, які ноти безпеки випустив SAP для виправлення даних вразливостей.
Розголошення користувачів, логінов – SAP nota 2255990, уразливість була виправлена 8-ого травня 2016-го року. Має вже CVE-шку CVE-2016-3973 (CVSS v3 7.5).
Список версій SAP:

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

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

Звичайно, хтось із вас може сказати, мовляв, встановили якийсь «кривий сервер» і знайшли баги, але і для цього є статистика тільки за розголошення списку користувачів SAP-a. Сканування проводилося за 7348 SAP-серверів, які доступні через Інтернет.

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

У сумі виходить, що, до уразливості розголошення інформації схильні близько 1013 серверів (~14%)

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

Сумарно – 2174 серверів, що складає ~30%
Виходить, що потрібно робити?
Потрібно патчиться, товариші адміністратори.
Так, і наостанок: хочеш у нас працювати і знаходити ще більш круті баги – надсилай своє резюме сюди
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.