Skip to content

Conversation

@msutovsky-r7
Copy link
Contributor

@msutovsky-r7 msutovsky-r7 commented Jan 5, 2026

This PR adds modules for multiple CVEs (CVE-2025-61675, CVE-2025-61678, CVE-2025-66039). This PR works as placeholder for now as modules are not finished, but contain the basic exploitation logic. All modules use authentication bypass (CVE-2025-66039). The CVE-2025-61675 describes multiple SQL injections, but the SQLi modules uses only one variant (one for user insertion, the other one for RCE).

WORK IN PROGRESS, TREAT AS SUCH

The CVE-2025-66039 represents an authentication bypass: when FreePBX uses Webserver Authorization Mode (an option the admin can enable), it allows an attacker to authenticate as any user.

The CVE-2025-61675 describes multiple SQL injections; the modules exploits the SQL injection in the custom extension component. The module chains these vulnerabilities into an unauthenticated SQL injection attack that creates a new fake user and effectively grants an attacker access to the administration.

The CVE-2025-61678 allows unrestricted file uploads via firmware upload, including path traversal. These vulnerabilities allow unauthenticated remote code execution by bypassing authentication and placing a webshell in the web server’s directory.

To setup the environment, perform minimal installation from here. Note that Authorization Type needs to be set to webserver:

  1. Login into FreePBX Administration
  2. Settings -> Advanced Settings
  3. Change Authorization Type to webserver
  • Split modules into separate PRs

@github-actions
Copy link

github-actions bot commented Jan 5, 2026

Thanks for your pull request! Before this can be merged, we need the following documentation for your module:

super(
update_info(
info,
'Name' => 'FreePB endpoint SQLi to RCE',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
'Name' => 'FreePB endpoint SQLi to RCE',
'Name' => 'FreePBX endpoint SQLi to RCE',

super(
update_info(
info,
'Name' => 'FreePBX firmeware file upload',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
'Name' => 'FreePBX firmeware file upload',
'Name' => 'FreePBX firmware file upload',

@msutovsky-r7 msutovsky-r7 changed the title WIP: Adds modules for multiple CVEs for FreePBX (CVE-2025-61675, CVE-2025-61678, CVE-2025-66039) Adds modules for multiple CVEs for FreePBX (CVE-2025-61675, CVE-2025-61678, CVE-2025-66039) Jan 7, 2026
@msutovsky-r7 msutovsky-r7 marked this pull request as ready for review January 8, 2026 07:26
info,
'Name' => 'FreePBX Custom Extension SQL Injection',
'Description' => %q{
FreePBX versions prior to 16.0.44 and 17.0.23 are vulnerable to multiple CVEs, specifically CVE-2025-66039 and CVE-2025-61675, in the context of this module. The former represents an authentication bypass: when FreePBX uses Webserver Authorization Mode (an option the admin can enable), it allows an attacker to authenticate as any user. The latter CVE describes multiple SQL injections; this module exploits the SQL injection in the custom extension component. The module chains these vulnerabilities into an unauthenticated SQL injection attack that creates a new fake user and effectively grants an attacker access to the administration.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
FreePBX versions prior to 16.0.44 and 17.0.23 are vulnerable to multiple CVEs, specifically CVE-2025-66039 and CVE-2025-61675, in the context of this module. The former represents an authentication bypass: when FreePBX uses Webserver Authorization Mode (an option the admin can enable), it allows an attacker to authenticate as any user. The latter CVE describes multiple SQL injections; this module exploits the SQL injection in the custom extension component. The module chains these vulnerabilities into an unauthenticated SQL injection attack that creates a new fake user and effectively grants an attacker access to the administration.
FreePBX versions prior to 16.0.44 and 17.0.23 are vulnerable to multiple CVEs, specifically CVE-2025-66039 and CVE-2025-61675, in the context of this module. The former represents an authentication bypass: when FreePBX uses Webserver Authorization Mode (an option the admin can enable), it allows an attacker to authenticate as any user. The latter CVE describes multiple SQL injections; this module exploits the SQL injection in the custom extension component. The module chains these vulnerabilities into an unauthenticated SQL injection attack that creates a new administrative user.

)
)
register_options([
OptString.new('USERNAME', [true, 'The valid FreePBX user', 'admin']),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
OptString.new('USERNAME', [true, 'The valid FreePBX user', 'admin']),
OptString.new('USERNAME', [true, 'A valid FreePBX user', 'admin']),

authenticate as any user. The latter CVE describes multiple SQL injections; this module exploits the
SQL injection in the custom extension component.
The module chains these vulnerabilities into an unauthenticated SQL injection attack that creates a
new fake user and effectively grants an attacker access to the administration.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
new fake user and effectively grants an attacker access to the administration.
new administrative user.

### USERNAME

Performing authentication bypass requires the username of an existing user.
This username is used in the Authorization header along with a random password.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
This username is used in the Authorization header along with a random password.

This line is confusing and necessary in my opinion.

Comment on lines +33 to +39
### FAKE_USERNAME

Username for fake injected user.

### FAKE_PASSWORD

Password for fake injected user.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A quick git grep shows that NEW_USER or/and NEW_USERNAME are the prefered nomenclature.

There is nothing "fake" about the new user.

def exploit
@job_name = Rex::Text.rand_text_alpha(4..7)

rce_payload = 'INSERT INTO cron_jobs (modulename,jobname,command,class,schedule,max_runtime,enabled,execution_order)'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if there is already a cronjob with the random name?

@@ -0,0 +1,140 @@
##
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the point/advantage of this module compared to the cron-based one? Couldn't' the two be merged?


register_options(
[
OptString.new('USERNAME', [true, 'The valid FreePBX user', 'admin']),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
OptString.new('USERNAME', [true, 'The valid FreePBX user', 'admin']),
OptString.new('USERNAME', [true, 'A valid FreePBX user', 'admin']),

Comment on lines +97 to +106
form_data.add_part(SecureRandom.uuid, nil, nil, 'form-data; name="dzuuid"')
form_data.add_part('0', nil, nil, 'form-data; name="dzchunkindex"')
form_data.add_part(payload.encoded.length.to_s, nil, nil, 'form-data; name="dztotalfilesize"')
form_data.add_part('2000000', nil, nil, 'form-data; name="dzchunksize"')
form_data.add_part('1', nil, nil, 'form-data; name="dztotalchunkcount"')
form_data.add_part('0', nil, nil, 'form-data; name="dzchunkbyteoffset"')
form_data.add_part("../../../var/www/html/#{@target_dir}", nil, nil, 'form-data; name="fwbrand"')
form_data.add_part('1', nil, nil, 'form-data; name="fwmodel"')
form_data.add_part('1', nil, nil, 'form-data; name="fwversion"')
form_data.add_part(payload.encoded, 'application/octet-stream', nil, %(form-data; name="file"; filename="#{@target_payload}"))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can the values be randomized a bit?

form_data.add_part('2000000', nil, nil, 'form-data; name="dzchunksize"')
form_data.add_part('1', nil, nil, 'form-data; name="dztotalchunkcount"')
form_data.add_part('0', nil, nil, 'form-data; name="dzchunkbyteoffset"')
form_data.add_part("../../../var/www/html/#{@target_dir}", nil, nil, 'form-data; name="fwbrand"')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is FreePBX always installed in /var/www/?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants