Internal - TryHackMe Writeup
The link for this lab is located here: https://tryhackme.com/room/internal
You have been assigned to a client that wants a penetration test conducted on an environment due to be released to production in three weeks. This room contains web hacking, privilege escalation, manual enumeration and more.
Full Walkthrough
The first step is to run a simple Nmap port scan with the following parameters:
-Pn to disable pinging (in case of a Windows machine)
-p- for all ports
10.10.19.57 (target IP)
-oN initscan (outputs to a normal Nmap format)
A quick side note: my command line may look slightly different. As is the case with the following nmap command where “nmap” is replaced with “cmap” – this is simply an alias I created that uses grc (generic colourizer) to add some colour to commands. The full command for “cmap” would simply be “grc nmap” – simple right?
The basic scan reveals 2 ports open – SSH and HTTP. This gives us an indication that the machine is likely running a website of some sort we can visit. Whilst we visit the website, we can run another Nmap command that gathers more information about these specific ports with the following syntax:
-T4 for the speed
-A to perform service detection, OS detection and run some scripts
-p22,80 to specify ports
This reveals some more information such as OpenSSH 7.6p1 is running for the SSH service. Additionally, we can determine the OS is highly likely to be Linux (maybe some variant of Ubuntu due to the SSH information). Finally, we see that Apache httpd 2.4.29 is running with what seems to be the default page
Navigating to the website does indeed reveal a default Apache 2 web page.
This likely tells us that there is not really anything running on it – at least on the default page. A good methodology to get into immediately is to try and find any hidden subdirectories or possibly even a different subdomain (although that is not needed here).
For me, I use a tool called Feroxbuster to search for any hidden directories but feel free to use any directory busting tool. The command takes the following arguments:
--url http://10.10.19.57 specifies the website and directory to start searching from
-w /usr/share/wordlists/dirb/common.txt specifies the wordlist
-d 1 tells the tool to only go 1 link deep (e.g. should only have 1 directory after the home page)
After a very short while, the tool comes back with some results:
What immediately jumps out is the WordPress directory – if you’ve been around cyber security for a bit, you’ll know WordPress has a semi-bad reputation for being insecure with certain themes and plugins. Navigating to /wordpress reveals a badly-formatted page:
Sometimes, websites will do this and the way to fix it is to add an entry in /etc/hosts for a domain name. In my example, I mapped the IP address to the domain of “internal.thm”.
After a quick reload, we get a nice looking WordPress site:
It’s interesting to note here that in the blog posts, you can see who the post was created by – in this case, a user “admin” created the first post. This could potentially be a future username for the website or even a possible SSH username.
Talking about potential usernames, scrolling down the page reveals some extra clickable links, including one titled “Log In”.
Clicking into this link reveals the standard WordPress login panel. How about trying that “admin” username or blog writer we found earlier with a random password?
The credentials don’t work. However, this reveals an interesting detail – look at the error message. The error message reveals that the “admin” user is a valid account as it tells as that the password is incorrect and NOT the username.
If the username was invalid, it might display a message saying “the username is incorrect” as an example. So, now we know for sure that “admin” is a valid username and it seems like a default username. What if the password is also lazily created with something like “password”?
However, before bruteforcing, we can do some more enumeration and I’ll show you a couple of cool tricks you can use. First, if we dive into the source code of the page and search for the string “ver”, it can actually possibly reveal the version of WordPress being used – in this case, it is possibly using version 5.4.2 (take it with a grain of salt).
Another manual enumeration trick that can be used is finding possible authors that post on the site. To do this, we can type “?author=1” after the URL and increment the number up or down to find possible authors.
In this case, only one author appears, but it confirms that there is an author called admin.
Another thing we can do is run a tool called WPScan as this site is running WordPress. This tool essentially scans the website for potential problems with the WordPress installation including outdate themes, plugins, possible usernames, etc..
To run it, we simply provide it with the “—url http://internal.thm/blog” parameter along with “-e” to enumerate everything
After a short while, some results come back. I won’t cover everything but some of the interesting information that came back was the WordPress version, which if you remember from earlier in the source code could have been 5.4.2, it turns out it was correct. Additionally, the WordPress theme in use is “twentyseventeen” and it is running an out-of-date version.
Finally, it performed some username enumeration and found the “admin” username we have already found.
Now that we’ve gathered some more information and have performed some manual and automated enumeration, we can try to bruteforce the login page we found earlier with the admin username and a wordlist.
To do this, there are a variety of tools available, but ultimately the easiest for WordPress is using WPScan itself by providing the following parameters:
--url http://internal.thm/blog/wp-login.php specifies the login page
--paswords /usr/share/wordlists/rockyou.txt is the wordlist
--usernames admin specifies the username
--max-threads 100 makes it go faster
After a short while, a valid combination is found and we get the password for the admin account.
Using these found credentials, we can login to the WordPress site and should be met with a similar looking dashboard:
I’ll let you perform some manual enumeration yourselves – have a look around at the plugins, themes, posts, settings and see what you can gather. Looking through the posts section, we see the post that was already on the website, but there is a second post that is Private – hmm….
Opening up this page and taking a look at its content, it seems like an easy win as it provides a username and password combination for a user called Will.
First, I tried to use these credentials via SSH but no luck unfortunately:
However, if you paid close attention to the directory busting results we did earlier, there was another interesting page – phpmyadmin – which takes us to another login portal. Unfortunately, neither credentials found so far works on that page either but always worth a try.
Now, researching a bit about how to exploit WordPress, I found this site and saw we could get a reverse shell by posting some PHP code into a certain page.
Going into Appearance -> Editor and looking down the right side, we see some PHP files. A good one to modify is the 404.php but feel free to use any.
The PHP code that I will be using is the famous PentestMonkey PHP Reverse Shell with a modified IP and port number.
After modifying it, I simply copy and pasted it into the 404.php file:
Then, we can save it and navigate to this page to activate the PHP code. But where is this page located? Typically, in a WordPress site, the /wp-content folder will contain the /themes folder. Thanks to WPScan, we know the theme running is twentyseventeen and we want the 404.php page – in full, the URL looks like:
However, before executing, make sure that a netcat listener or something else is ready to catch the reverse shell on the same port. For me, the port is 443. After navigating to the 404.php page, we get a reverse shell back:
A good idea is to try and stabilize the shell before moving forwards. There are plenty of ways of doing this, but my preferred method if Python is installed is to first spawn a BASH shell using python, then exporting the TERM, background the shell using CTRL+Z and then typing in “stty raw -echo; fg” which provides us more functionality in the shell such as tab autocompletion, the ability to clear, etc…
The first place to look on a system for me is the /home directory which can have some sensitive files. In this scenario, there was a directory for a user called “aubreanna” but the permissions do not allow the www-data to look inside.
Another directory I like to look in is /etc which typically contains configuration files (e.g. possible credentials). Looking around, I found a wordpress directory. Upon looking inside, I found a PHP file which contained some possible credentials:
Before trying to use these, I looked around some more and found another interesting directory – phpmyadmin. Inside, I found multiple interesting files.
Just as a gut instinct, some of these files can be quite large so for the purpose of simplicity in case my shell crashed, I decided to download these files to my local machine. To do this, I started up a python HTTP server on the target machine running on a port that did not require sudo privileges – in this example port 8888:
Then, I navigated to the IP on port 8888 in my browser and proceeded to download every file that was present.
One file that immediately stood out to me was “htpasswd.setup” but unfortunately the file was empty.
Next, I looked at the config-db.php file and found some more potential credential for the phpMyAdmin login page.
After finding these and the previous possible credentials, I navigated back to the /phpmyadmin directory and tried first logging in with the “phpmyadmin” user which proved successful:
This provides some useful information like the server type, server version, PHP version and more. However, looking through the whole phpmyadmin database, I found nothing interesting or that was not found before – seemed to be a dead end.
After this, I tried to use the “wordpress” username credentials and it also logged in successfully with a different database this time:
Once again, looking through the whole database, I found either no useful information or information previously found such as users:
Another dead-end. Instead of continuing in the /etc directory, I decided to move to the /opt directory which contains software and add-on packages which could reveal a vulnerable version of something. To my surprise, listing the contents I found a TXT file called “wp-save.txt”.
Opening this file revealed even more credentials – this time for the user aubreanna which we know exists on this target machine.
Knowing the credentials for this user, we can try and SSH in:
And it works! We now have user access to the machine via SSH. From this, we can navigate to the aubreanna home directory found earlier and grab the user.txt flag sitting in there
By listing the contents of the home directory, there is another interesting file – jenkins.txt. Reading this file tells us an interesting message that an Internal Jenkins service is running on 172.17.0.2:8000.
However, this IP address is not on the same network we attacked this machine on. Checking the network information via “ifconfig” reveals that there is an interface called “docker0” which does have that 172.17.0.0/16 network.
We need to pivot somehow. In this case, I will be using the technique of SSH Tunneling. There are two ways to create a forward SSH tunnel – port forwarding and creating a proxy.
Port forwarding is accomplished with the “-L” switch which creates a link to a LOCAL port. For example, we have access to 10.10.19.57 and there is a server running on 172.17.0.2, we can use the following command to create a link to the server on 172.17.0.2:
ssh -L 8080:172.17.0.2:8080 aubreanna@10.10.19.57
This then allows us to access the website on 172.17.0.2 (through 10.10.19.57) by navigating to port 8080 on our localhost by entering “localhost:8080” or whatever port you chose – it does not have to be the same port running on the remote server/host:
After doing this and navigating to localhost:8080, we get a Jenkins login page – the pivoting worked!
As we did with WordPress, we can try some random credentials – they don’t work. Now you attempt to bruteforce both the username and password, but remember the famous phrase – work smarter, not harder.
Before hammering the login, we can maybe find some default credentials first. Doing a quick Google search reveals that the default username for Jenkins is admin and the password is random – we now have a possible valid username.
For bruteforcing this page, I like to use Hydra. In order for Hydra to work, we first need to intercept a login request via Burp Suite. Doing this, we can see the parameters that are posted to the login page and the URL as well:
Once the information is gathered from the interception, we can run hydra with the following options:
-l admin is the username
-P /usr/share/wordlists/rockyou.txt is the wordlist
127.0.0.1 -s 8080 specifies the IP address and the port
http-post-form indicates this is a HTTP POST request
“/j_acegi_security_check is the URL to send the login to (found in Burp Suite)
j_username=^USER^&j_password=^PASS^….. specifies the username and password request and the parameters to substitute (^USER^ & ^PASS^)
Invalid username or password indicates the message for a failed login, if not present it means valid credentials have been entered.
After a short while, a username and password are returned to us:
Using this information, we can login to the Jenkins console:
Doing some research on Jenkins exploitation, I found the following article that tells us we can execute a Groovy script.
Looking at this, we then navigate down to the Tools and Actions section and find the “Script Console”:
Researching Groovy Script, it seems like it is implemented in Java meaning a Java reverse shell should work (in theory!):
Using the Java reverse shell found here, I pasted in and changed the IP address to my IP and the port to 5678:
Before executing, a netcat listener was started on the same port to catch the connection:
Once the listener is ready, I executed the script and received a reverse shell back:
Running the “whoami” and “id” commands, it seems like we are the jenkins user.
As before, I did some manual enumeration by looking through various directories (/home, /etc, /opt). In the opt directory, I found another text file containing root credentials addressed to Aubreanna which means the credentials are likely for the main machine we exploited before.
Using the newly found root credentials, we can SSH into the machine and get root access:
From there, all that is left to do is navigate to /root and grab the root.txt flag: