Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
Weblogic-CVE-2020-2551-To-Internet — CVE-2020-2551 POC для использования в Интернете | Kitploit
Инструменты/GitHubGitHub/dido1960/weblogic-cve-2020-2551-to-internet
Анализ уязвимостейЭксплуатацияЭксплуатация веб-приложенийТестирование на ПроникновениеОбучение и ОбразованиеРазработка Полезной Нагрузки
GitHubdido1960/weblogic-cve-2020-2551-to-internet

Weblogic-CVE-2020-2551-To-Internet

CVE-2020-2551 POC для использования в Интернете

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться
Репозиторий
2276 лет назадПроверено Kitploit

Weblogic-CVE-2020-2551-To-Internet

POC CVE-2020-2551 для использования в Интернете

  • Тестовый POC (можно использовать для внешнего тестирования)

    python CVE-2020-2551.py [HOST] [IP]

  • Попытка изменить codebase для удалённой загрузки классов (провал)

    python CVE-2020-TEST.py [HOST] [IP]

Кратко об уязвимости WebLogic CVE-2020-2551 и создании POC для внешней сети

(Впервые опубликовано на Anquanke, ссылка на оригинал)

0x00 Основные понятия

Для изучения этой уязвимости требуются некоторые предварительные знания, например CORBA и RMI.

Кратко опишу:

CORBA — это технический стандарт, разработанный OMG, для распределённых приложений; в нём используется IDL для обеспечения кросс-языковой поддержки, а взаимодействие между клиентом и сервером осуществляется по протоколу IIOP.

RMI — это другая технология распределённых приложений; в Java её можно упростить с помощью JNDI. Клиент и сервер общаются по протоколу JRMP, однако в WebLogic RMI использует протокол T3, о котором ранее уже было немало уязвимостей.

RMI-IIOP объединяет преимущества RMI и CORBA, позволяя развёртывать RMI-приложения через протокол IIOP.

В официальной документации также упоминается:

Серверные объекты RMI могут использовать протокол IIOP и взаимодействовать с CORBA-клиентскими объектами, написанными на любом языке.

0x01 RMI-IIOP

Пока оставим WebLogic в стороне и сосредоточимся на том, как написать пример RMI-IIOP.

Код клиента можно посмотреть в тестовом проекте из статьи Заметки о RMI, JNDI, LDAP, JRMP, JMX, JMS в Java (часть 1). Можно самостоятельно скомпилировать HelloClient и HelloServer, либо использовать уже скомпилированные версии из тестового проекта.

Запустите сервер имён в командной строке (входит в состав Java):

root@kitploit:~
start orbd -ORBInitialPort 1050

Запустите серверный HelloServer из командной строки и настройте удалённую отладку. О том, как настроить удалённую отладку в IDEA, можно посмотреть в методе, описанном в начале этой статьи.

root@kitploit:~
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 HelloServer

Конечно, можно не использовать удалённую отладку, а просто запустить и посмотреть результат:

root@kitploit:~
java HelloServer

Запустите клиент в командной строке:

root@kitploit:~
Java HelloClient 

В этот момент появится калькулятор; при успешной удалённой отладке можно увидеть следующий стек вызовов:

Команды выполняются в EvilMessage.readObejct():

Кстати, статьи по установке и отладке WebLogic.

Что насчёт RMI-IIOP в WebLogic? В статье О RMI-IIOP в Java упоминается эксплуатация RMI-IIOP в WebLogic; на её основе я провёл некоторые исследования. Using WebLogic’s RMI over IIOP описывает несколько способов использования WebLogic в качестве клиента RMI-IIOP, включая:

  1. Автономный RMI-клиент (с использованием JNDI, без каких-либо компонентов WebLogic)
  2. WebLogic-клиент
  3. J2EE-клиенты
  4. Клиенты CORBA/IDL

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

Ранее при изучении T3-десериализации в WebLogic я разворачивал приложение Helloserver, у которого был доступный метод sayhello(). Я попробовал использовать оба JNDI_FACTORY и через второй JNDI_FACTORY успешно вызвал метод sayHello().

Тогда я немного изменил POC для протокола T3 в WebLogic — фактически просто заменил RMI на IIOP — и обнаружил, что цепочка эксплуатации jtaTransactionManager успешно сработала и отправила jrmp-запрос локальному jrmplisten.

Посмотрим на трафик: при вызове метода remove() отправляется запрос remove__java_lang_Object, в трафике есть вредоносные данные, но магического заголовка aced не найдено.

Предполагаю, что на сервере данные сначала проходят специальный разбор, а затем десериализуются. Если взглянуть на стек вызовов, видно, что вторая половина цепочки выполнения очень похожа на цепочку из ранее рассмотренного нативного RMI-IIOP: в том случае запуск происходил из CDRInputStream.read_value(), а здесь — из IIOPInputStream.read_value() в WebLogic (эта точка read_value также упоминалась в докладе 2019 года).

Здесь запрос сначала обрабатывается в clusterableServerRef.invoke(), который в зависимости от типа invoker вызывает this.invoker.invoke(). В данном случае вызывается Mejb_dj5nps_HomeImpl_WLSkel.invoke(), и поскольку операция — "remove", выполняется ветвь case 6, где вызывается IIOPInputStream.readObject(); в методе read_value() разбираются данные IIOPInputStream и запускается десериализация. Это и есть POC с использованием метода remove().

0x02 CVE-2020-2551

В [статье Lucifaer](https://lucifaer.com/2020/02/25/WebLogic WLS核心组件RCE分析(CVE-2020-2551)/?from=timeline&isappinstalled=0#2-2-Weblogic解析流程) упоминается использование метода bind() — это также основной способ эксплуатации в интернете. Проследим стек вызовов.

Как и раньше, запрос сначала обрабатывается в clusterableServerRef.invoke(), который в зависимости от типа invoker вызывает this.invoker.invoke(); в данном случае вызывается CobraServerRef.invoke(), а затем в _NamingContextAnyImplBase._invoke(), поскольку va1 равно "bind_any", выполняется ветвь case 0, где вызывается IIOPInputStream.read_any(); далее снова вызывается IIOPInputStream.read_value(), что запускает десериализацию. Ранее я говорил, что в трафике не видно магического заголовка aced — это потому, что в IIOPInputStream есть собственный способ разбора. Hex-value форма IIOPInputStream выглядит следующим образом и содержит имя класса и информацию о полях:

В итоге вызывается метод readObejct() вредоносного класса.

Посмотрел на патч и обнаружил, что он находится в том же месте, что и патч для эксплуатации T3-десериализации в 2015 году.

В тестах из анализа уязвимости WebLogic CVE-2020-2551 видно, что позиция фильтрации классов для CVE-2020-2551 также находится в классе weblogic.iiop.Utils.

Однако при локальном тестировании WebLogic 10.3.6 с установленным патчем 2015 года функция isBlacklisted() не сработала (хотя в MsgAbbrevInputStream и InboundMsgAbbrev есть вызовы isBlacklisted() для проверки чёрного списка... странно).

Патч для CVE-2020-2551 добавляет метод verifyclassermitted() для фильтрации в weblogic.iiop.Utils.LoadClass().

Чёрный список отфильтровывает вредоносные классы, включая родительский класс JtaTransactionManager — com.bea.core.repackaged.springframework.transaction.support.AbstractPlatformTransactionManager. Этот класс входит в состав WebLogic и очень опасен. При просмотре патча у меня возникла мысль: поскольку проверка в строке 606 выполняется после LoadClass(), то если при загрузке className произойдёт загрузка класса и выполнение вредоносного статического блока, разве это не позволит обойти защиту? Об этом поговорим позже.

0x03 Имитация протокола IIOP для создания POC

POC, написанный на Java, имеет сетевые проблемы: работает только против локального сервиса WebLogic, но не работает против docker-контейнера или машины во внешней сети. Статьи с анализом этой проблемы:

Пошаговое руководство по решению сетевых проблем POC для WebLogic CVE-2020-2551

Обсуждение WebLogic-CVE-2020-2551

Далее займёмся отладкой POC. Можно опираться на предыдущий вариант с remove или на версию от Y4er. В двух упомянутых выше статьях предлагаются два способа решения:

  • Изменить weblogic.jar и пересобрать его
  • Имитировать протокол IIOP

Я попробовал оба варианта. После пересборки WebLogic возникает ошибка java.lang.NoSuchMethodError:weblogic.security.subject.SubjectManager.installCESubjectManager, но решения я так и не нашёл.

Поэтому я решил имитировать протокол IIOP. Сначала поставил точку останова в POC для отладки.

Обнаружил, что при вызове new InitialContext(env) в EndPointImpl.sendReceive() отправляются и принимаются два пакета.

LocateReply содержит информацию IOR. Здесь нужно понимать, что такое IOR. Его роль — предоставлять host и port, необходимые для IIOP-взаимодействия между RMI-IIOP клиентом и серверным объектом. Кроме того, Object_key в красной рамке используется для различения разных объектов на сервере.

При имитации протокола IIOP ключевое внимание нужно уделить Object_key; host и ip на самом деле не влияют. Когда я начинал тестирование, просто повторно воспроизводил все пакеты; при отправке resolve_any возвращался location forward.

В официальной документации GIOP говорится, что location forward означает, что Object_key меняется: при разных запросах возвращаемый Object_key может быть разным (Object_key здесь — это key address в пакете данных). Как уже упоминалось, этот Object_key при использовании протокола IIOP служит для определения того, с каким объектом ведётся связь, и его значение нужно динамически получать из LocateReply.

В итоге я решил имитировать не метод remove(), а IIOP-запрос, отправляемый методом bind(), поскольку таких запросов меньше. Посмотрим на пакет данных при локальной успешной эксплуатации.

Отправляем LocateRequest, получаем data и через регулярное выражение извлекаем key address из LocateReply.

Вручную задаю адрес вредоносного jrmp-сервера (rmi://...) и отправляю пакеты bind_any с интервалом в 1 секунду. Поскольку цепочка эксплуатации здесь отправляет jrmp-запрос не через DGCClient, на неё не влияет JEP290, и её можно эксплуатировать через jrmplisten.

POC успешно протестирован в среде docker. Можно использовать vulhub с окружением SSRF, указав IP хост-машины; docker успешно получает jrmp-запрос от хост-машины. Код выложен на Github.

0x04 Проверка гипотезы

Ранее упоминалась идея использования codebase для загрузки удалённого кода в обход детектирования. Тем, кто изучал JNDI-атаки, должно быть известно, что codebase можно использовать для указания местоположения удалённых классов. Если codebase контролируем и программа разрешает удалённую загрузку классов, то можно загрузить удалённый вредоносный класс и выполнить вредоносный код в статическом блоке.

Из чтения кода видно, что второй параметр weblogic.iiop.Utils.lodaClass() — это codebase; этот параметр считывается в IIOPInputStream.read_value(), это параметр var8. На строке 1659 вызывается readIndirectingRepositoryId(var8), который в итоге вызывает weblogic.iiop.Utils.lodaClass(). Чтобы выполнились строки 1644 и 1659, необходимо (va4r & 1)=1 и (va4 & 6)=2, поэтому значение var4 должно быть равно 3.

Стек вызовов от readIndirectingRepositoryId до getClassFromId, в конце которого выполняется loadclass() на строке 304.

Посмотрим на пакет bind_any: он состоит из GIOP Header и GIOP Request. GIOP Request также включает key address (совпадает с LocateReply), ServiceContextList и stub_data. Значение var4 — это \x7f\xff\xff\x02 из stub_data, поэтому (va4r & 1)=0, (va4 & 6)=2, и строка 1644, задающая codebase, не выполняется.

Мы модифицируем первый выделенный блок \x7f\xff\xff\x02 на \x00\x00\x00\x03, а во втором блоке добавляем длину и значение codebase. Конкретный код находится на Github. Можно заметить, что там выполняется ещё и операция выравнивания — это подводный камень. Дело в том, что перед чтением последующей информации о классе проверяется, является ли позиция следующего байта кратной 4; если нет, часть байтов пропускается. Например, если позиция следующего байта равна 1, будут пропущены 3 байта, и чтение начнётся с байта на позиции 4. Позиция здесь отсчитывается относительно всего пакета bind_any; если позиция не кратна 4, выполняется дополнение нулями.

Есть ещё одна проблема. Посмотрим на предыдущий стек вызовов от readIndirectingRepositoryId до getClassFromId: между ними находится функция findClassInfo(). Если какой-то класс уже был загружен, информация об ID класса сохраняется, и при вызове findClassInfo() сразу возвращается информация о классе, без входа в weblogic.iiop.Utils.getClassFromID().

Поэтому при тестировании каждый раз приходится менять имя класса.

Как бы то ни было, в итоге удалось успешно имитировать протокол IIOP, изменить значение codebase и выполнить функцию weblogic.iiop.Utils.getClassFromId().

К сожалению, при получении RMIURLClassFinder возвращается NULL, а функция RMIEnvironment.getEnvironment().isNetworkClassLoadingEnabled() возвращает false.

Причина в том, что параметр _NetworkClassLoadingEnable в ServerMBeanImpl имеет значение False.

Хотел посмотреть, в каком конфигурационном файле WebLogic задаётся этот параметр, но так и не нашёл...

Заключение

На самом деле в процессе изучения этой уязвимости я понял, что требуется много предварительных знаний, таких как Java-десериализация, RMI, JNDI и тому подобное. Для изучения можно обратиться к этому тематическому разделу статей. Хотя в итоге эксплуатация с изменением codebase провалилась, я всё равно вынес много полезного.

Скачать инструмент