Skip to content

Commit 73f4259

Browse files
committed
Fix based on suggestions
1 parent 514d2b4 commit 73f4259

File tree

1 file changed

+42
-63
lines changed

1 file changed

+42
-63
lines changed

modules/post/windows/gather/enum_prefetch.rb

Lines changed: 42 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
require 'msf/core/post/windows/registry'
1111
class Metasploit3 < Msf::Post
1212

13+
include Msf::Post::File
1314
include Msf::Post::Windows::Priv
15+
include Msf::Post::Windows::Registry
1416

1517
def initialize(info={})
1618
super(update_info(info,
@@ -28,86 +30,62 @@ def initialize(info={})
2830

2931
def prefetch_key_value()
3032
# Checks if Prefetch registry key exists and what value it has.
31-
prefetch_key = session.sys.registry.open_key(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Session\ Manager\\Memory\ Management\\PrefetchParameters", KEY_READ)
32-
key_value = prefetch_key.query_value("EnablePrefetcher").data
33-
34-
if key_value == 0
33+
prefetch_key_value = registry_getvaldata("HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Memory Management\\PrefetchParameters", "EnablePrefetcher")
34+
if prefetch_key_value == 0
3535
print_error("EnablePrefetcher Value: (0) = Disabled (Non-Default).")
36-
elsif key_value == 1
36+
elsif prefetch_key_value == 1
3737
print_good("EnablePrefetcher Value: (1) = Application launch prefetching enabled (Non-Default).")
38-
elsif key_value == 2
38+
elsif prefetch_key_value == 2
3939
print_good("EnablePrefetcher Value: (2) = Boot prefetching enabled (Non-Default, excl. Win2k3).")
40-
elsif key_value == 3
40+
elsif prefetch_key_value == 3
4141
print_good("EnablePrefetcher Value: (3) = Applaunch and boot enabled (Default Value, excl. Win2k3).")
4242
else
4343
print_error("No value or unknown value. Results might vary.")
4444
end
45-
prefetch_key.close
4645
end
4746

4847
def timezone_key_values(key_value)
4948
# Looks for timezone from registry
50-
timezone_key = session.sys.registry.open_key(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation", KEY_READ)
51-
if timezone_key.nil?
49+
timezone = registry_getvaldata("HKLM\\SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation", key_value)
50+
tz_bias = registry_getvaldata("HKLM\\SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation", "Bias")
51+
if timezone.nil? or tz_bias.nil?
5252
print_line("Couldn't find key/value for timezone from registry.")
5353
else
54-
timezone = timezone_key.query_value(key_value).data
55-
tzbias = timezone_key.query_value("Bias").data
56-
if timezone.nil? or tzbias.nil?
57-
print_error("Couldn't find timezone information from registry.")
58-
else
5954
print_good("Remote: Timezone is %s." % timezone)
60-
if tzbias < 0xfff
61-
bias = tzbias
62-
print_good("Remote: Localtime bias to UTC: -%s minutes." % bias)
55+
if tz_bias < 0xfff
56+
print_good("Remote: Localtime bias to UTC: -%s minutes." % tz_bias)
6357
else
6458
offset = 0xffffffff
65-
bias = offset - tzbias
59+
bias = offset - tz_bias
6660
print_good("Remote: Localtime bias to UTC: +%s minutes." % bias)
6761
end
6862
end
6963
end
70-
timezone_key.close
71-
end
7264

73-
def gather_prefetch_info(name_offset, hash_offset, lastrun_offset, runcount_offset, filename, table)
74-
# This function seeks and gathers information from specific offsets.
75-
h = client.railgun.kernel32.CreateFileA(filename, "GENERIC_READ", "FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE", nil, "OPEN_EXISTING", "FILE_ATTRIBUTE_READONLY", nil)
76-
77-
if h['GetLastError'] != 0
78-
print_error("Error opening a file handle on %s." % filename)
65+
def gather_pf_info(name_offset, hash_offset, runcount_offset, filename, table)
66+
# We'll load the file and parse information from the offsets
67+
prefetch_file = read_file(filename)
68+
if prefetch_file.empty? or prefetch_file.nil?
69+
print_error("Couldn't read file: #{filename}")
7970
else
80-
handle = h['return']
81-
82-
# Finds the filename from the prefetch file
83-
client.railgun.kernel32.SetFilePointer(handle, name_offset, 0, nil)
84-
fname = client.railgun.kernel32.ReadFile(handle, 60, 60, 4, nil)
85-
name = fname['lpBuffer']
86-
idx = name.index("\x00\x00")
87-
88-
# Finds the run count from the prefetch file
89-
client.railgun.kernel32.SetFilePointer(handle, runcount_offset, 0, nil)
90-
count = client.railgun.kernel32.ReadFile(handle, 4, 4, 4, nil)
91-
92-
# Finds the file path hash from the prefetch file.
93-
client.railgun.kernel32.SetFilePointer(handle, hash_offset, 0, nil)
94-
hash = client.railgun.kernel32.ReadFile(handle, 4, 4, 4, nil)
95-
96-
# Finds the LastModified/Created timestamp (MACE)
71+
# First we'll get the filename
72+
pf_filename = prefetch_file[name_offset..name_offset+60]
73+
idx = pf_filename.index("\x00\x00")
74+
name = Rex::Text.to_ascii(pf_filename.slice(0..idx))
75+
# Next we'll get the run count
76+
run_count = prefetch_file[runcount_offset..runcount_offset+4].unpack('L*')[0].to_s
77+
# Then file path hash
78+
path_hash = prefetch_file[hash_offset..hash_offset+4].unpack('h8')[0].reverse.upcase.to_s
79+
# Last is mace value for timestamps
9780
mtimes = client.priv.fs.get_file_mace(filename)
98-
99-
# Checking and moving the values
100-
if idx.nil? or count.nil? or hash.nil? or mtimes.nil?
101-
print_error("Error reading file (might be temporary): %s" % filename)
81+
if mtimes.nil? or mtimes.empty?
82+
last_modified = "Error reading value"
83+
created = "Error reading value"
10284
else
103-
pname = Rex::Text.to_ascii(name.slice(0..idx))
104-
prun = count['lpBuffer'].unpack('L*')[0]
105-
phash = hash['lpBuffer'].unpack('h*')[0].reverse
106-
lmod = mtimes['Modified'].utc
107-
creat = mtimes['Created'].utc
108-
table << [lmod, creat,prun,phash,pname]
85+
last_modified = mtimes['Modified'].utc.to_s
86+
created = mtimes['Created'].utc.to_s
10987
end
110-
client.railgun.kernel32.CloseHandle(handle)
88+
table << [last_modified, created, run_count, path_hash, name]
11189
end
11290
end
11391

@@ -123,6 +101,9 @@ def run
123101
error_msg = "You don't have enough privileges. Try getsystem."
124102

125103
if sysnfo =~/(Windows XP|2003|.NET)/
104+
# For some reason we need system privileges to read file
105+
# mace time on XP/2003 while we can do the same only
106+
# as admin on Win7.
126107
if not is_system?
127108
print_error(error_msg)
128109
return nil
@@ -131,7 +112,6 @@ def run
131112
print_good("Detected #{sysnfo} (max 128 entries)")
132113
name_offset = 0x10
133114
hash_offset = 0x4C
134-
lastrun_offset = 0x78
135115
runcount_offset = 0x90
136116
# Registry key for timezone
137117
key_value = "StandardName"
@@ -145,7 +125,6 @@ def run
145125
print_good("Detected #{sysnfo} (max 128 entries)")
146126
name_offset = 0x10
147127
hash_offset = 0x4C
148-
lastrun_offset = 0x80
149128
runcount_offset = 0x98
150129
# Registry key for timezone
151130
key_value = "TimeZoneKeyName"
@@ -169,25 +148,25 @@ def run
169148
prefetch_key_value
170149
timezone_key_values(key_value)
171150
print_good("Current UTC Time: %s" % Time.now.utc)
172-
sysroot = client.fs.file.expand_path("%SYSTEMROOT%")
173-
full_path = sysroot + "\\Prefetch\\"
151+
sys_root = expand_path("%SYSTEMROOT%")
152+
full_path = sys_root + "\\Prefetch\\"
174153
file_type = "*.pf"
175154
print_status("Gathering information from remote system. This will take awhile..")
176155

177156
# Goes through the files in Prefetch directory, creates file paths for the
178-
# gather_prefetch_info function that enumerates all the pf info
157+
# gather_pf_info function that enumerates all the pf info
179158

180159
getfile_prefetch_filenames = client.fs.file.search(full_path,file_type,timeout=-1)
181160
if getfile_prefetch_filenames.empty? or getfile_prefetch_filenames.nil?
182-
print_error("Could not find/access any .pf files. Can't continue.")
161+
print_error("Could not find/access any .pf files. Can't continue. (Might be temporary error..)")
183162
return nil
184163
else
185164
getfile_prefetch_filenames.each do |file|
186165
if file.empty? or file.nil?
187-
print_error("Could not open file: %s" % filename)
166+
print_error("Could not open file: %s" % file)
188167
else
189168
filename = File.join(file['path'], file['name'])
190-
gather_prefetch_info(name_offset, hash_offset, lastrun_offset, runcount_offset, filename, table)
169+
gather_pf_info(name_offset, hash_offset, runcount_offset, filename, table)
191170
end
192171
end
193172
end

0 commit comments

Comments
 (0)