# Hack The Box - Unattended

## Quick Summary

Hey guys today Unattended retired and here’s my write-up about it. Personally I think this box should have been rated as hard not medium, it really had a lot of stuff that were hard to find and exploit. There was an interesting SQL injection vulnerability that could be escalated to local file inclusion then to remote code execution and that’s my favorite part about this box. It’s a Linux box and its ip is 10.10.10.126, I added it to /etc/hosts as unattended.htb. Let’s jump right in !

## Nmap

As always we will start with nmap to scan for open ports and services :
nmap -sV -sT -sC unattended.htb

Only http and https, and surprisingly no ssh. Also the ssl certificate from the https port tells us that the common name is www.nestedflanders.htb so I added that to my hosts file :

## Web Enumeration

Checking unattended.htb on both 80 and 443 gives us a blank page :

http://www.nestedflanders.htb responds with a redirection to https://www.nestedflanders.htb which has the default Apache page :

I used wfuzz to enumerate sub directories and it was weird to see both index.php and index.html with different content :

Also there was a sub directory called /dev.
/dev :

/index.html :

/index.php

## Nginx off-by-slash

When I checked wappalyzer results I saw that it identified the web server as nginx and that was weird because we saw Apache’s default page. Also when I went to https://www.nestedflanders.htb/dev I got a redirection to https://www.nestedflanders.htb/dev/ (It added a slash /).

As demonstrated in this document there can be a vulnerability because of this. I gave it a try by adding .. after dev:

We got 403 maybe because we are out of html directory, I added /html/index.php and I successfully got the source of the index page :

## SQLI

By looking at the php code we can see database credentials :

We can also see this :

It defines an array called valid_ids, then it checks the GET parameter id, if it exists and it’s in the valid_ids array, it will append it to this SQL query : SELECT name FROM idname where id = [ID HERE].
To understand what’s happening in a better way let’s check the website again.

There are 3 pages, main, about and contact. By visiting them we notice that the id parameter is added and each page has one of the ids we saw in the php code : 25 (main), 465 (about) and 587 (contact).

I tried adding a single quote to https://www.nestedflanders.htb/index.php?id=465 and I got the main page instead of the about page because the query failed :

When I fixed the query it worked :

I started sqlmap to automate it and dump the database :

There are 2 databases, information_schema and neddy :

We don’t need information_schema in anything and also dumping neddy with that kind of injection would take a lot of time, let’s take a look at the tables.

I only dumped filepath and idname because these are the ones I saw in the source of index.php.

## SQLI to LFI

Now we have the actual file names, about for example (/47c1ba4f7b1edf28ea0e2bb250717093.php) :

It’s just the text and nothing else. We can also verify that there is nothing hidden by checking the php source of the three pages :

First guess will be that the page name gets queried from the database table idname then the path (or the actual php file name) gets queried from the database table filepath then it includes that page to the index page. And that’s true but since we have the source of index.php let’s also look at it.
By looking at the dumped tables and the source of index.php again we can understand the following :
The SQL injectable query we just exploited is part of the function getTplFromID which returns the page name after querying it from the table idname based on our given id number :
Function getTplFromID() :

Table idname :

There is another function called getPathFromTpl which takes the returned page name and queries the actual path from the table filepath then returns it :
Function getPathFromTpl() :

Table filepath :

The first function gets called and its return value gets saved in the variable tpl : $tpl = getTplFromID($conn);
Then the second function gets called with the variable tpl and its return value gets saved in the variable inc
And finally it includes that page include("$inc"); We have a SQL injection vulnerability which we can use to control what’s being included, in other words we have a local file inclusion vulnerability. After some attempts to read /etc/passwd this payload worked : ' UNION SELECT "main' UNION SELECT '/etc/passwd';-- ";-- ## LFI to RCE We need to get RCE from this LFI. If I could include my session file (/var/lib/php/session/sess_[SESSION COOKIE]) then I could put php code in a cookie and include it. My session cookie was c5vmccsqkle2rdionj28kit221. Request : Response : It worked, I created a cookie and called it RCE, any php code I put there will be included and executed so we can get RCE by system() or passthru(), let’s try whoami : Request : Response : I spent a lot of time trying to get a reverse shell and I couldn’t, so I checked iptables rules : Request : Response : We can only get a reverse shell on ports 443 and 80. My problem was trying to get a connection on port 1337. nc wasn’t on the box so I used php to get a reverse shell. shell.sh : I started a python server on port 80 then I downloaded the shell file on the box and executed it : And we get a shell as www-data : But I didn’t like 2 things about this shell. First thing, it wasn’t a tty shell. Second thing, with only 2 ports available It was annoying because I usually need more shells. So I created a php meterpreter payload because with meterpreter I can spawn as many shells as I want and they can be tty shells. Note : I stopped the python server before starting the listener because both of them use port 80. ## Shell as guly, User Flag There is only one user on the box : guly, and we can’t access the home directory : Earlier we got the database credentials from index.php and we couldn’t dump the whole database because of the slow process, let’s check the database : config looks interesting, let’s check it : The row with id 86 looks interesting. It has a value of some perl scripts : Apparently these scripts get executed from time to time, we can’t read these scripts or replace them, but we can change the value of that configuration from the database and put a reverse shell command. There’s no nc so I used socat : We owned user. ## initrd, Root Flag After getting a shell as guly I terminated my meterpreter session as www-data and got a new one as guly : I noticed that guly was in the local group grub, I searched for files that are owned by this group : I could only access /boot/initrd.img-4.9.0-8-amd64, so I created a directory in /tmp and copied it there. initrd is the abbreviation for initial ramdisk. Using file on it says that it’s a gzip archive : I renamed it to initrd.img-4.9.0-8-amd64.gz then I used gzip to extract it : The new file is a cpio archive : To extract it : After extracting it we get a lot of files : Searching for guly in these files reveals this interesting comment in a script called cryptroot : I checked that part of the script : This line /sbin/uinitrd c0m3s3f0ss34nt4n1 |$cryptopen generates root password and pipes it to \$cryptopen. We don’t have permission to execute uinitrd :

But in the extracted files we have the same binary and we can execute it :

And we owned root !
That’s it , Feedback is appreciated !