Initial recon
sudo nmap -T4 -oA fullNmap -A --version-all -Pn -p- 10.10.10.246
So we have 2 SSH ports, which is interesting and a single page on port 8080
- additionally we can see right now interesting paths from robots.txt
file. Getting into it.
On the main page we don’t see any content - in path /.ftp_uploads/
there seem to be some database file and text file with warning Binary files are being corrupted during transfer!!! Check if are recoverable.
. We could assume that this database file was uploaded without binary mode on FTP and thus it was corrupted. Need to get deeper into how exactly this mode break binary files and if it is reversible.
Directory listing on path /.ftp_uploads/
VPN login doesn’t seem like anything interesting would be there at the first sight, so I guess retrieving the database data is our priority.
Exploiting Webapp
Retrieving SQL data
File db.sql.gz
is legit gzipped file which contains database schema , it looks like it creates some user from what we can read as a plaintext.
Having in mind the warning text, gzip was probably broken when using FTP to transfer files and no binary mode was set. In that case, files that are transferred are broken - but how exactly?
It turns out ftp transfer without the binary mode performs one simple operation which ends up breaking most binary files. It replaces every newline character (Line feed [LF]
- hex byte 0x0A
) with “Windows style” newline (so called Carriage return Line feed [CRLF]
- hex bytes 0x0D0A
). So essentially every byte 0x0A
is replaced by two bytes 0x0D
and 0x0A
. It is easy enough to replace this operation on any file and get original content back. In this case it could even be done manually with hex editor. I was too lazy so used the script i found here
You can see below differences in hexdump of both files (which we downloaded and fixed version) - it only differs in places where there is byte 0x0A
. Notice in the original version it always follows byte 0x0D
which we remove when fixing it.
Hex dump of broken gz file
Hex dump of fixed gz file
With that operation we have legitimate database schema with credentials.
VPN login - generating TOTP
Password looks like a hash - checking it in public databases of cracked hashes like hashes.com we find that admin password is… admin.
Doesn’t look too inspiring - but after logging in it asks for totp code so at least we could not guess that one blindly.
However - here it is not that simple that we can just enter totp value and it works. The reason is that TOTP
stands for Time-Based One Time password
which is password changing over time. However its value is calculated from the base secret which we have stored in the database. So we simply need to read up how the token is generated for any given instance of time and create it ourselves.
Based on wikipedia - standard algorithm for TOTP
is pretty simple. It is function of secret key and counter, which is calculated by taking the current linux timestamp divided by time window used. Function is one of standard hash methods like SHA1
by default. There are parameters that are flexible - time window interval when token is valid, Unix time start and length of the token. We can start with default ones and work our way further if needed.
Wikipedia explanation of TOTP generation
As I am lazy person, I used first totp online generaton I found which has dynamic parameters so let’s test various combinations here. Unfortunately default parameters or some minor modification did not seem to work, so it’s time to code!
Wrote a quick script which uses python library to generate TOTP
where attempted to find legitimate parameters. Tried to differ all sane parameters that generation of TOTP
could rely on - thee include interval
, number of digits in code and different digests used. Sending it over and over to the server and hoping something will work.
Script i baked up - checking valid code by checking content length is LAME but fastest way it should almost always work. I’ll be damned if this trips me up, one can hope.
After running it for a while it seems obvious to not find proper values, so my next guess was that syncrhonization is probably off. With the information we have - it is kinda hard to get what amount of time we could be off. Protocol which would enable us to check that is NTP Network Time Protocol
which is used for synchronizing time between computers. Let’s run UDP scan on that port then!
I also run nmap scripts in the same time which get the time amount with sudo nmap -p123 -sU 10.10.10.246 --script=clock-skew,ntp-info
It seems we are off about 13 minutes from the time on the host. It would make sens our TOTP tokens would not work!
Let’s try the default parameters again but with the skew we observed, if this does not work we can get back to our brute-force.
Assuming skew of 13 minutes flat as reading from NTP can be normally off few seconds each way, nothing is perfect.
Our modified code - left comments to just check it modify it on-the fly and left parts if we needed to brute-force again.
My first try - and it works! It’s a nice feeling that just a thought about how a challenge should work perfectly matches the reality.
Succesful try!
Panel after logging in
Pivoting further
After entering anything into Common Name
we receive OpenVPN config to download, which is generated using PHP as we see some error messages there. After deleting the errors and adding vpn.static.htb to hosts
file pointing to address 10.10.10.246
it succesfully connects. Value which we enter as Common Name
is just inserted as certificate Common Name
. Will get to it later on if needed, but let’s recon the network here using addresses in the VPN panel to see what interesting is there.
While that is going on I noticed that whenever i insert space into the parameter we see interesting prompt error batch mode: /usr/bin/ersatool create|print|revoke CN
. It looks like number of arguments does not match and PHP is executing shell script with our parameter CN. Normal injections using &&
and ;
do not work. It seems to ignore all characters besides alphanumerics and spaces.
Meanwhile top1000 port scan across the VPN network finished and nothing interesting is there so very doubt there would be something when scanning across all ports. However, after that I inspected the routes that are created when using VPN. It turns out, there is a route to the networks 172.30.0.0/16
and 172.17.0.0/24
. After manually adding routes for the rest of the addresses with sudo ip route add 172.20.0.0/24 via 172.30.0.1 dev tun9
and sudo ip route add 192.168.254.0/24 via 172.30.0.1 dev tun9
on the site we can find some services there after all!
Taking into consideration all services I scanned by doing quick top1000 scan - we have:
There does not seem to be any default password used on MySQL like root/root and it requires password for root user, so let’s look at the web service.
The next web
On service http://172.20.0.10
we have again a plain directory listing.
Directory listing
VPN directory leads to exactly same panel as on the main host - there does not exist any difference on the first sight. However info.php
file is interesting - but in my case had serious trouble getting it. No idea if this is some problem with multiple VPNs through OpenVPN or something other than that, but the file info.php
was taking forever to load and never loaded.
The solution in my case was launching main HTB VPN through Windows and getting second VPN on my WSL-powered Linux then it worked without a problem. I could do it only because of my setup - but maybe on standard linux it would work out of the box? Anyway if anyone is struggling this is the solution for me.
When I could finally load the info.php
file - it is kinda what we expect, so phpinfo()
command executed.
Going through the environment variables and other interesting things in phpinfo()
output there is nothing that pops out right away. However as it should have some purpose, I noticed an interesting module called xdebug
. It helps with debugging PHP application. As this is the first time I encountered that one, quick google search tells us that if settings xdebug.remote_enable
and xdebug.remote_connect_back
are set to true - we can get it to connect to us and give us reverse shell! Getting through the options these seem to be enabled here, so off to the hacking.
Xdebug module
I used PoC on github since we need to communicate using the debugging protocol to execute commands.
Getting reverse shell as www-data
Escalate to user
As a limited shell we can execute commands that read some data from the host, but cannot execute any command that does not return information. Maybe it could be improved by modifying the PoC, but we can notice the SSH key in /home/www-data/.ssh/id_rsa
. Also a nice gift in the /home/
directory as there is user.txt
flag waiting for us.
There is just a small inconvenience - it seems we are only able to read just a bit over 10 lines once at a time, so we cannot simply cat
the private key. I used the simple way of splitting the data by using combination of head
and tail
commands. Reading data with sequentially:
We can get parts of the key and glue it as we notice overriding parts.
SSH private key (truncated)
Using this key we can log in onto our host - but only on SSH on port 2222 on IP 10.10.10.246
To the root
First thing we can get from the sources on the host are database credentials. We already know that database is hosted on 172.20.0.11:3306
so we can check what is there.
Creds are root:2108@C00l
and dbname is static
.
Going through the databases - there are only credentials for the users that we already know and nothing more.
Running linpeas.sh script also did not return anything meaningful aside from the information we are inside a docker. Then I moved my attention to the script that was used to generate VPN config as we had inklings there could be some sort of command injection there.
Interesting snippet from /var/www/html/vpn/panel.php
is
It seems that our input is cleaned from non-alphanumeric characters in that step. So maybe, we are able to send some malicious input directly to the host and exploit this issue?
Fast testing shows that input is also validated on the target though, something worth a notice. Attempts on spawning staging meterpreter interestingly fail, seems like something is blocking it?
For further testing - I forwarded local port 80 to point to the 80 port on server PKI with ssh command sudo ssh www-data@10.10.10.246 -p 2222 -i id_rsa -L 127.0.0.1:80:192.168.254.3:80
.
Going forward, I did basic port recon with python script to scan hosts inside the network if we see some extra ports, but none were found. The only avenue of the attack still seems to be the PKI
host at IP 192.168.254.3
. After confirming I cannot exploit the cn
parameter I noticed the suspicious version of the PHP in the header - X-Powered-By: PHP-FPM/7.1
. Digging a bit, there is a exploit on that version and even a metasploit module for that one. Check seems promising, so let’s go to the exploitation.
Metasploit module seemed to perform some actions but did not really work in my case. Instead I downloaded an original exploit from here. After running it with phuip-fpizdam http://127.0.0.1/index.php
we can simply send requests with parameter a
and it should execute our code!.
I doesn’t work every time but should after few retries. The vulnerability is fascinating in itself, recommend reading in detail about it.
Working exploit with command execution
Here it would be nice to get a shell, looking briefly with the command through the system - it seems that is it just another docker instance with nothing interesting there besides the ersatool
binary. We can confirm that the cn
parameter was again sanitized on the server when looking at index.php
content:
Now I’m pretty sure this is the path to the root. Instead of getting a shell (which is slightly problematic as target cannot reach us directly), I just downloaded the ersatool using base64
linux command on the binary and decoding it locally. If this will be a miss, we can get into getting direct shell to the target to perform more reconnaisance.
Getting to the reversing then!
Reversing ersatool
Well - lost all the notes from the reversing of this one. However it was a fun ride with relatively simple format string exploit and enjoyed it a lot. One of the not-so-many binary exploitation at this time at HTB.
For now that will be all - but for special requests I could whip something up from IDA files and doing it anew. If you would like to see me write about it, ping me on twitter. Right now have no extra motivation for writing it.