TryHackMe: Blog (Writeup)

TryHackMe: Blog (Writeup)

Billy Joel made a Wordpress blog!

·

12 min read

Blog is a rated as a medium difficulty, CTF-Style machine on TryHackMe created by Nameless0ne. This machine took me down a few rabbit holes and because of that fact, this writeup is slightly longer than normal. My intention behind this is to provide a more complete picture of my attack methodology. Even if some paths don't lead to anything fruitful, it still follows proper enumeration practices and provides us with a more complete picture of the puzzle we're trying to solve.

Challenge link here:: tryhackme.com/room/blog

Enumeration

Our initial nmap scan shows us three accessible services; SSH on 22, Apache on 80, and Samba on 139/445. I always do a full (TCP) port scan as well, but the full scan only came back with the same four ports.
We also notice that nmap pulled the robots.txt file from the webserver and identified a path to /wp-admin/ which gives the impression that this might be a wordpress site.

001.png

The first thing I'm going to look at before even visiting the website is those SMB shares. I prefer to use smbmap for an initial enumeration because it'll return the access rights as well as the listing of shares.

002.png

When we do a similar lookup with smbclient it'll list the shares for us but it's anyone's guess what we can actually Read or Write to...

003.png

Anyhow, now that we know we have Read/Write access to BillySMB as a guest lets try connecting there and poking around for some threads to pull on. (This is where smbclient shines as a handy SMB shell) We were able to access it before by using guest access, so all we need is the following (watch your backslash count):
smbclient \\\\10.10.101.104\\BillySMB

From here we can grab a couple of interesting files with the command
get <filename>

004.png Once the files are transferred to our local we take a quick look with eog <filename> The check-this.png file ends up being a QR-code. We can upload this file to a service such as zxing.org/w/decode.jspx for decoding and it returns a URL to a youtube video..
(This was not quite what I was expecting, but also completely what I was expecting. Haha.)

005.png

Moving on.. I run eog on Alice-White-Rabbit.jpg but it just looks like an image from the 1950s Alice in Wonderland cartoon movie. (On an aside in the context of CTFs, anytime I come across anything having to do with rabbits, or Alice(s) I always wonder if I'm starting to go down a rabbit hole specifically created to distract or frustrate us.) Beware.
I try some initial probing with exifprobe, exiftool, and exif but without finding anything interesting. I also run strings against the file because you never know what data might have been hidden in plain sight. Eventually I try using steghide with the info command and we find a non-password protected file embedded in the image.
steghide info Alice-White-Rabbit.jpg

006.png

We extract the embedded file with
steghide extract -sf Alice-White-Rabbit.jpg
We cat the file but take a guess where we've found ourselves..

007.png

Lastly there's that tswift.mp4 file. I tried running exiftool, strings, and binwalk on the file but it seems to just be a parody video file. Good for an entertaining watch but doesn't seem to have anything else significant

Initial Compromise

On to the webserver! When I first visit the site it looks pretty crummy and perhaps even broken.

008.png

I take a look at the page source (CTRL+U on Firefox) and see what may be the issue.

009.png

Ahhh easy mistake! Since I jumped on the SMB shares right out of the gate I completely forgot to add the IP address and Domain Name to my /etc/hosts file.

010.png

After updating the local /etc/hosts file, we can reload the page and see it in all it's glory. There's not a lot on the blog itself. Two different posts; one by Karen Wheeler(Mom) and one by Billy Joel. There's a couple comments on Karen's post but nothing significant for us.

011.png

Just to keep something going in the background I start up a wpscan with the following command: wpscan -e --url 10.10.101.104 where -e will run a number of different enumeration checks

012.png

Looks like an old version of Wordpress from December of 2018.

013.png

Additionally the wpscan confirms our users and even provides us with the specific syntax used for usernames on the site (First initial/Last name).

014.png

We make our way over to the login page at blog.thm/wp-login.php to start testing our usernames. I feel confident we have some valid usernames but first lets test the form's functionality by inputting complete garbage before passing anything potentially valid.

For my first login attempt I try admin:password (if this does work the target has other problems..) but after rejecting the login it returns one of my favorite error messages in the Wordpress world. Error: Invalid username I love when websites specify exactly which part of your user input it didn't like.

015.png

I'm feeling confident that bjoel might be admin of the site so lets see if we can get access as them. This time I try logging in as bjoel:password and when it returns the next error message it specifies: ‘The password you entered for the username bjoel is incorrect’ So this time it accepted our username but still errored out on the password, this is definitely progress.

016.png

NOTE: We can confirm kwheel is another valid username but bjoel definitely seems like the more interesting of the two accounts at the moment so that's where we'll proceed. Always good to enumerate additional usernames though.

017.png

I haven't seen any protection against excessive requests (mainly because I haven't made any excessive requests yet..) but lets try a hydra attack to get us through the login form!

When initially using hydra for this authentication attack i had some trouble getting it started. My normal hydra command would return every password attempted as correct. After checking out the Storage tab from the browser's developer tools I realized I was missing a cookie. You can add on a cookie value to hydra by appending :H=Cookie: <Key>:<Value> where the :H= will set values into the request header.

018.png

Although this seemed terribly slow. It was only getting through 10-15 requests per minute! Something wasn't right with this.. So I took out the cookie but now I was back to hydra seeing every request as a success.

Eventually I realized what I was doing wrong and it had nothing to do with cookies. I had included the username as part of the Response's error/failure message! I've had better results with Hydra when specifying a failure message that is simple yet unique to the page.

In this case I was including a string(username) that is likely being dynamically generated and then inserted based on the request instead of being a static element of the requested page.

So I alter my hydra command to the following and its off to the races! The first update tells me it's made 360 requests in the first minute so I feel like I may have finally found the right syntax for this request.

019.png

Except now it's been running for a while. After waiting five minutes...going to make coffee, coming back and still nothing after a couple thousand passwords I began to wonder if this was even working..again!

So I do a quick google search for brute forcing wordpress and quickly realize that you can use wpscan for bruteforcing the XML-RPC API if it's active (didn't know this before; usually just relied on Hydra). Since XML-RPC is enabled on this wordpress server this seems like an attack that may be more closely crafted to our target service.

020.png

At this point I had the wpscan password attack running and I decided to take my dog for a quick bathroom break and grab something to snack on from the fridge. But after about thirty minutes and sixteen-thousand passwords later..I figured this wasn't it either. 021.png

At this point I was really at a loss. Typically for these types of learning CTFs a few minutes bruteforcing through rockyou is usually enough to get the lesson across. Since there wasn't much on the site anyway I did a quick crawl through it with cewl to assemble a more crafted password list but that was quickly exhausted without results either.

I was thinking about what else I had seen and what else I hadn't tried yet. Then I remembered I had another username I hadn't tried anything other than verifying yet. I do the same wpscan but this time with Karen's username and what do you know.

Password found in a little under three and a half minutes.
wpscan -U kwheel_file -P /usr/share/wordlists/rockyou.txt --url 10.10.101.104

022.png

Just for a sanity check I try the Hydra attack again but this time with ‘kwheel’ as the username. This time it returns the password in just about two minutes thanks to it's parallel connection threads.

023.png

024.png

So now we're logged in as Karen on the wordpress site. Normally if I'm able to get on the admin side of a wordpress site I'll look for a template to overwrite with a reverse shell. However Karen doesn't have the necessary permissions to edit templates, only to make posts.

025.png

However once on the inside we're reminded that this is Wordpress 5.0 released in December of 2018. If there are any RCE exploits from 12/2018 onward we might be able to do something with this.

The first google search for wordpress 5.0 exploit refers us to the following: WordPress 5.0.0 - Image Remote Code Execution exploit-db.com/exploits/49512

I tried to get this exploit working for a while. Did plenty of side reading to understand what was happening behind the script and eventually I came to the realization that the exif metadata we're using as a placeholder for our malicious injection is being stripped away once it's edited. In order for the metadata to be maintained after making the edits necessary for file traversal to work, the ImageMagick library would need to be installed on the target machine but after visiting the uploaded file we see that it's been edited by the GD image library which strips away our injection(See image below). Additional Sources::
blog.sonarsource.com/wordpress-image-remote..
pentest-tools.com/blog/wordpress-remote-cod..

026.png

So eventually I give in against my better judgement and turn to metasploit for an initial foothold. Nothing against Metasploit, by the way. It's an awesome framework and I know there's plenty of folks who use it on the daily. I just enjoy manual exploitation a bit more since you have to work harder for it but you (usually) gain a better understanding of what's actually happening. At this point in my journey I'm still trying to prioritize gaining a better understanding of concepts over simply rooting boxes and collecting flags FTW.

Anyhow in msfconsole we just load the applicable module, set the rhost/lhost, provide user/pass and then type 'run.' I'll allow you to figure out which module is applicable to this particular pentest but otherwise it's pretty straightforward.

Privilege Escalation

Now that we're in as www-data we can start looking around the box itself. I also use python to spawn a better pseudo-TTY shell with the following::
python -c 'import pty;pty.spawn("/bin/bash")'

027.png

We can access bjoel's home directory and we find a user.txt file but it's another false positive.

028.png

At this point I uploaded linpeas to run in the background while doing some quick enumeration checks.

We find a password in the wordpress wp-config.php file that may be usable for bjoel, but no luck there when trying to switch user with su.

029.png 030.png

However since we've got a new thread to pull on here lets see if there's anything interesting in the wordpress database. We log in to the database with the following command:
mysql -uwordpressuser -p'LittleYellowLamp90!@' -hlocalhost

031.png

Next we show databases;
Then show tables;
Remember to mind the semi-colon at the end.

032.png

Lastly we dump the users table with select * from wp_users
The fact that none of these hashes are obfuscated in this writeup is a hint that this will also not be our path to bjoel or root. We already have Karen's password and when I crack that hash using john we see it confirmed in fairly short order. However before cracking Karen's hash, bjoel's hash ran through the entirety of rockyou sooo this might be another deadend...(It is)

033.png

To be perfectly honest I got pretty stuck at this point. Nothing was really standing out to me as a path to either bjoel or root. I started going through old notes and writeups of my own trying to find something that might be applicable here but nothing was really connecting.

After taking a break, walking the doge, coming back and still not making any progress I really caved this time and went to look at someone else's writeup..

Giving credit where credit is due; go check out this awesome hacker who also has a nifty room on THM for Linux Function Hooking... whokilleddb.medium.com/tryhackme-blog-9fe23..

Anyway, their writeup introduces me to a new tool called SUID3NUM which you can find here: github.com/Anon-Exploiter/SUID3NUM
Not only does this script check for binaries with the SUID bit set, it also sorts them depending on whether they're default binaries, custom binaries, or GTFO binaries. In our case it points out a custom SUID binary i later realized was in the linpeas output but I had completely overlooked.

Key takeaway from this lesson for me is to not depend on a single tool or if possible, not depend on tools at all.

Even without SUID3NUM I could have taken the list of SUID binaries returned from the manual check: find / -type f -perm -04000 -ls 2>/dev/null and cross-checked them against the GTFOBins site myself.

#DoTheDueDiligence

However even with that said, this is a pretty nifty script so many thanks to the author ‘Anon-Exploiter’

034.png

Now that we have a custom binary owned by root but executable by anyone lets see if we can't do something with it.

035.png Great. Not a whole lot to go on there. Taking a little deeper look at the file shows us that's its just a little over 8KBs. Shouldn't be anything too crazy in there right?

036.png We know from previous experience that ltrace can be used to trace the library calls made during a program's execution.
man7.org/linux/man-pages/man1/ltrace.1.html
We also know that getenv() takes an environmental variable key as an argument and returns the value
man7.org/linux/man-pages/man3/getenv.3.html
So it looks like this program is trying to pull an environmental variable named ‘admin’ but doesn't find it so it prints/puts the ‘Not an Admin’ message to the screen.

037.png

So lets set an environmental variable named admin and try again! This time when it runs getenv("admin") it returns the value admin value we exported. It calls setuid(0) which should make us root Then it makes a call to the system() library to start “/bin/bash” With that we just need to run the program by itself and we have root!

038.png

Conclusion

This machine had plenty of rabbit holes to dig around in but when it came down to it, the initial compromise that got us a shell and eventually root was due to an out-of-date wordpress site. According to this article from TechJury Wordpress sites accounts for 39.5% of the entire clear web and 62% of all CMS-based websites, meaning there's a good percentage of live servers that may still be vulnerable to attack due to outdated CMS software.