В этом рай­тапе я покажу, как иссле­довать API сай­та на пред­мет потен­циаль­ных лазе­ек, затем мы напишем собс­твен­ный прок­си‑сер­вер на Python, а потом при­меним XSS для эксфиль­тра­ции дан­ных и про­экс­плу­ати­руем слож­ную уяз­вимость чте­ния про­изволь­ных фай­лов.

Уп­ражнять­ся мы будем на вир­туаль­ной машине Response с пло­щад­ки Hack The Box. Ее уро­вень слож­ности — Insane, и на сегод­няшний день это самая слож­ная машина на HTB и пер­вая в моей серии рай­тапов, которую мне не уда­лось прой­ти до кон­ца. Одна­ко даже получе­ние двух поль­зователь­ских уче­ток ока­залось зах­ватыва­ющим.

warning

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

 

Разведка

 

Сканирование портов

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

10.10.11.163 response.htb

И запус­каем ска­ниро­вание пор­тов.

Справка: сканирование портов

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

На­ибо­лее извес­тный инс­тру­мент для ска­ниро­вания — это Nmap. Улуч­шить резуль­таты его работы ты можешь при помощи сле­дующе­го скрип­та:

#!/bin/bash
ports=$(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 8.2p1 и 80 — веб‑сер­вер Nginx 1.21.6. С SSH ничего не сде­лать, поэто­му сра­зу перехо­дим к вебу.

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

На сай­те находим упо­мина­ние домена www.response.htb, поэто­му обновля­ем запись в фай­ле /etc/hosts:

10.10.11.163 response.htb www.response.htb

Что­бы рас­ширить область тес­тирова­ния, сос­тавим кар­ту сай­та с помощью Burp Discovery. Для это­го в Burp History выбира­ем целевой адрес и в кон­текс­тном меню Engagement tools → Discover content.

Карта сайта
Кар­та сай­та

Так находим нес­тандар­тный файл /status/main.js.php.

 

Точка входа

Ко­пиру­ем содер­жимое фай­ла /status/main.js.php на локаль­ную машину и изу­чаем. Этот файл содер­жит дан­ные для обра­щения к домену api.response.htb через сайт на домене proxy.response.htb.

Содержимое файла main.js.php
Со­дер­жимое фай­ла main.js.php

Так как обра­щение про­исхо­дит к под­домену proxy, добав­ляем в /etc/hosts толь­ко его.

10.10.11.163 response.htb www.response.htb proxy.response.htb

За­тем копиру­ем дан­ные для обра­щения и пов­торя­ем зап­рос.

POST /fetch HTTP/1.1
Host: proxy.response.htb
Content-Type: application/json
Content-Length: 262
{"url":"http://api.response.htb/","url_digest":"cab532f75001ed2cc94ada92183d2160319a328e67001a9215956a5dbf10c545","method":"GET","session":"6c2a752c873e8c03fc927a81647402d0","session_digest":"6ce5cbd27651561e9005287bc5d8cf3201aa6c4fe885057ae80b40af0b8951bd"}
Запрос и ответ сервера
Зап­рос и ответ сер­вера

От­вет от сер­вера закоди­рован в Base64, декоди­ровать мож­но пря­мо в Burp Inspector.

Burp Inspector
Burp Inspector

Так как даль­ше дан­ные пред­став­лены в фор­мате JSON, мож­но кра­сиво отоб­разить их при помощи ути­литы jq.

Полученные с сервера данные
По­лучен­ные с сер­вера дан­ные

Прос­мотрим так­же стра­ницы /get_chat_status и /get_servers.

Обращение к странице /get_chat_status
Об­ращение к стра­нице /get_chat_status
Ответ сервера
От­вет сер­вера
Обращение к странице /get_servers
Об­ращение к стра­нице /get_servers
Ответ сервера
От­вет сер­вера

Рас­кры­ваем еще один сер­вис — chat.response.htb. Добав­ляем его в файл /etc/hosts и прос­матри­ваем ответ сер­вера.

10.10.11.163 response.htb www.response.htb proxy.response.htb chat.response.htb
Ответ сервера
От­вет сер­вера

Сайт ока­зал­ся недос­тупен. Но мож­но обра­тить­ся к нему через сайт proxy. Прав­да, для это­го нам нуж­но под­твер­дить параметр url под­писью в парамет­ре url_digest, который сами вычис­лить мы не можем. Но параметр session, где переда­ется иден­тифика­тор веб‑сес­сии, тоже под­твержда­ется под­писью session_digest.

Запрос /status/main.js.php
Зап­рос /status/main.js.php

Тог­да про­буем вмес­то иден­тифика­тора сес­сии отпра­вить ссыл­ку, что­бы получить под­пись для нее.

Получение подписи URL
По­луче­ние под­писи URL

Как видишь, мы узна­ем дей­стви­тель­ную под­пись URL, отправ­ленно­го вмес­то иден­тифика­тора сес­сии.

 

Точка опоры

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

Получение значения url_digest
По­луче­ние зна­чения url_digest

С под­писью мож­но выпол­нить зап­рос к прок­си‑сай­ту.

Получение содержимого страницы chat.response.htb
По­луче­ние содер­жимого стра­ницы chat.response.htb

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

  1. Че­рез свой бра­узер обра­щаем­ся к внут­ренне­му сай­ту, ука­зывая IP-адрес написан­ного нами веб‑сер­вера.
  2. Наш сер­вер будет кодиро­вать при­нятый зап­рос и отправ­лять на прок­си‑сайт.
  3. Пос­ле получе­ния отве­та от прок­си‑сай­та наш самопис­ный сер­вер будет декоди­ровать при­нятые дан­ные и отправ­лять в качес­тве отве­та бра­узе­ру.

Так как работать будем с сай­том http://chat.response.htb, сде­лаем запись в файл /etc/hosts:

127.0.0.1 chat.response.htb

Сна­чала напишем оснас­тку веб‑сер­вера без вся­ких фун­кций. В клас­се сер­вера ProxyServer реали­зуем обра­бот­чики do_GET и do_POST, которые будут вызывать еди­ный метод do_Multi. Спер­ва прос­то будем выводить URL, к которо­му обра­тит­ся бра­узер.

from http.server import BaseHTTPRequestHandler, HTTPServer
from socketserver import ThreadingMixIn
class ProxyServer(BaseHTTPRequestHandler):
def do_GET(self):
self.do_Multi('GET')
def do_POST(self):
self.do_Multi('POST')
def do_Multi(self, method):
uri = self.path
target_url = 'http://chat.response.htb' + uri
print(method + " " + target_url)
class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
pass
ws = ThreadedHTTPServer(("0.0.0.0", 80), ProxyServer)
print("Server started...")
try:
ws.serve_forever()
except KeyboardInterrupt:
pass
ws.server_close()
print("Server stopped.")

За­пус­каем сер­вер и обра­щаем­ся к http://chat.response.htb/.

Логи сервера
Ло­ги сер­вера

Продолжение доступно только участникам

Вариант 1. Присоединись к сообществу «Xakep.ru», чтобы читать все материалы на сайте

Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее

Вариант 2. Открой один материал

Заинтересовала статья, но нет возможности стать членом клуба «Xakep.ru»? Тогда этот вариант для тебя! Обрати внимание: этот способ подходит только для статей, опубликованных более двух месяцев назад.


  • Подпишись на наc в Telegram!

    Только важные новости и лучшие статьи

    Подписаться

  • Подписаться
    Уведомить о
    2 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии