Что за ерунда JNDI, которая часто попадает в беду?

Java Архитектура Безопасность

Оригинал: Miss Sister Taste (идентификатор публичной учетной записи WeChat: xjjdog), добро пожаловать, пожалуйста, сохраните источник для перепечатки.

Каждый раз, когда возникает относительно крупномасштабная уязвимость, JNDI, кажется, не отсутствует. С ним также связана недавно известная уязвимость Log4j2, которая заставляет задуматься, не является ли это бэкдором, открытым автором.

Поскольку JNDI — это вещь, не говоря уже об использовании, многие люди даже не слышали о ней. Такая непопулярная вещь, какой смысл помещать ее в фреймворк логирования? Боюсь, это может понять только автор.

управляемый базой данных

Многие люди вступают в контакт с JNDI, начиная с драйвера базы данных. Конечно, с ростом популярности режима единого выпуска SpringBoot все меньше и меньше антикварных компаний используют этот метод для получения конфигурации базы данных.

Например, в файле server.xml tomcat мы можем настроить файл с именем

<Resource name="jdbc/xjjdogDB" auth="Container" type="javax.sql.DataSource"
maxTotal="100" maxIdle="30" maxWaitMillis="10000"
username="xjjdog" password="123456" driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/xjjdog_db"/>

Затем нам нужно только настроить имя JNDI в SpringBoot, и он сможет загрузить правильную конфигурацию. Предпосылка заключается в том, что нам нужно упаковать службу SpringBoot как пакет WAR и опубликовать ее. Такое программное обеспечение, как JBoss, претендующее на роль корпоративного сервера, любит это делать.

spring:
  datasource:
	jndi-name: jdbc/xjjdogDB

Отсюда мы можем это увидеть. JNDI, в конце концов, волшебная вещь? Вы можете думать об этом как о центре конфигурации, или вы можете думать об этом как о службе именования. Его основная функция — позволить вам получить ряд сложных конфигураций и инициализированных функций с помощью короткой строки.

Таким образом, мы можем избежать написания этих конфигураций непосредственно в проекте. То, что загружается при запуске программы, зависит от конфигурации рабочей среды.

Если это специально реализовано, разве это не HashMap, который может получить значение по ключу.

Опасность исходит от этого

Ключ - это значение, это не строка, это объект. Чтобы перейти от строки к обычному классу и быть универсальным, вы должны полагаться на отражение.

jndiarch.gif

Это изображение является официальным введением Oracle в JNDI. Ничто из вышеперечисленного не является ключевым.Ключевым моментом является то, что JNDI может взаимодействовать с различными технологиями, такими как LDAP и RMI, через механизм SPI.

Любой удобный канал, который не соответствует норме удобства, создаст проблемы. SPI — одна из немногих технологий, нарушающих механизм загрузки классов Java, и, как и классы Unsafe, она мощная, но не рекомендуется.

image-20211213152723788.png

Как показано выше, этоNamingManagerметоды в классеgetObjectFactoryFromReference. Когда он загружает соответствующий класс локально, если он не может его загрузить, он делает то, что не должен делать, но должен делать, то есть конструирует соответствующий объект из кода в сети!

image-20211213161601961.png

На этот раз, демонстрируя свои мускулы, его можно прикончить. Как показано выше, нам нужно запустить nginx только на порту 8000. Или запустите крошечный веб-сервер напрямую, используя python.

python -m http.server 8000

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

Также очень легко создавать эти наступательные полезные нагрузки, и есть такие инструменты, как marshalsec, которые можно легко сгенерировать.

В соответствии с механизмом загрузки классов в java в блоке статического кода вы можете выполнить некоторую фактическую логику выполнения кода. Нам просто нужно поместить скомпилированный класс a.class туда, где он должен быть, и JNDI сможет его загрузить.

public class a {
    static {
        try {
            String[] cmd = {"calc.exe"};
   java.lang.Runtime.getRuntime().exec(cmd).waitFor();
        } catch ( Exception e ) {
            e.printStackTrace();
        }
    }
}

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

END

Как видно из вышеизложенного, отражение в Java очень мощное, но и очень опасное. Функция SPI унаследовала эту особенность и смело обнажила свою слабость. Я думаю, что функция очень хорошая, но почему она существует во фреймворке логирования?

Может из-за объема. В конце концов, журнальный фреймворк тоже мечтает о метавселенной!

Об авторе: Miss Sister Taste (xjjdog), общедоступный аккаунт, который не позволяет программистам идти в обход. Сосредоточьтесь на инфраструктуре и Linux. Десять лет архитектуры, десятки миллиардов ежедневного трафика, обсуждение с вами мира высокой параллелизма, дающие вам другой вкус. Мой личный WeChat xjjdog0, добро пожаловать в друзья для дальнейшего общения.