Skip to content

Commit 514d2b4

Browse files
committed
Fix to make msftidy happy.
1 parent 0cc499f commit 514d2b4

File tree

1 file changed

+186
-195
lines changed

1 file changed

+186
-195
lines changed

modules/post/windows/gather/enum_prefetch.rb

Lines changed: 186 additions & 195 deletions
Original file line numberDiff line numberDiff line change
@@ -4,208 +4,199 @@
44
# web site for more information on licensing and terms of use.
55
# http://metasploit.com/
66
##
7+
78
require 'msf/core'
89
require 'rex'
910
require 'msf/core/post/windows/registry'
1011
class Metasploit3 < Msf::Post
1112

12-
include Msf::Post::Windows::Priv
13-
14-
def initialize(info={})
15-
super(update_info(info,
16-
'Name' => 'Windows Gather Prefetch File Information',
17-
'Description' => %q{This module gathers prefetch file information from WinXP, Win2k3 and Win7 systems.
18-
File offset reads for run count, hash and filename are collected from each prefetch file
19-
using WinAPI through Railgun while Last Modified and Create times are file MACE values.},
20-
'License' => MSF_LICENSE,
21-
'Author' => ['TJ Glad <fraktaali[at]gmail.com>'],
22-
'Platform' => ['win'],
23-
'SessionType' => ['meterpreter']
24-
))
25-
end
26-
27-
28-
def prefetch_key_value()
29-
# Checks if Prefetch registry key exists and what value it has.
30-
prefetch_key = session.sys.registry.open_key(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Session\ Manager\\Memory\ Management\\PrefetchParameters", KEY_READ)
31-
key_value = prefetch_key.query_value("EnablePrefetcher").data
32-
33-
if key_value == 0
34-
print_error("EnablePrefetcher Value: (0) = Disabled (Non-Default).")
35-
elsif key_value == 1
36-
print_good("EnablePrefetcher Value: (1) = Application launch prefetching enabled (Non-Default).")
37-
elsif key_value == 2
38-
print_good("EnablePrefetcher Value: (2) = Boot prefetching enabled (Non-Default, excl. Win2k3).")
39-
elsif key_value == 3
40-
print_good("EnablePrefetcher Value: (3) = Applaunch and boot enabled (Default Value, excl. Win2k3).")
41-
else
42-
print_error("No value or unknown value. Results might vary.")
43-
end
44-
prefetch_key.close
45-
end
46-
47-
def timezone_key_values(key_value)
48-
# Looks for timezone from registry
49-
timezone_key = session.sys.registry.open_key(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation", KEY_READ)
50-
if timezone_key.nil?
51-
print_line("Couldn't find key/value for timezone from registry.")
52-
else
53-
timezone = timezone_key.query_value(key_value).data
54-
tzbias = timezone_key.query_value("Bias").data
55-
if timezone.nil? or tzbias.nil?
56-
print_error("Couldn't find timezone information from registry.")
57-
else
58-
print_good("Remote: Timezone is %s." % timezone)
59-
if tzbias < 0xfff
60-
bias = tzbias
61-
print_good("Remote: Localtime bias to UTC: -%s minutes." % bias)
62-
else
63-
offset = 0xffffffff
64-
bias = offset - tzbias
65-
print_good("Remote: Localtime bias to UTC: +%s minutes." % bias)
66-
end
67-
end
68-
end
69-
timezone_key.close
70-
end
71-
72-
73-
def gather_prefetch_info(name_offset, hash_offset, lastrun_offset, runcount_offset, filename, table)
74-
75-
# This function seeks and gathers information from specific offsets.
76-
h = client.railgun.kernel32.CreateFileA(filename, "GENERIC_READ", "FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE", nil, "OPEN_EXISTING", "FILE_ATTRIBUTE_READONLY", nil)
77-
78-
if h['GetLastError'] != 0
79-
print_error("Error opening a file handle on %s." % filename)
80-
else
81-
handle = h['return']
82-
83-
# Finds the filename from the prefetch file
84-
client.railgun.kernel32.SetFilePointer(handle, name_offset, 0, nil)
85-
fname = client.railgun.kernel32.ReadFile(handle, 60, 60, 4, nil)
86-
name = fname['lpBuffer']
87-
idx = name.index("\x00\x00")
88-
89-
# Finds the run count from the prefetch file
90-
client.railgun.kernel32.SetFilePointer(handle, runcount_offset, 0, nil)
91-
count = client.railgun.kernel32.ReadFile(handle, 4, 4, 4, nil)
92-
93-
# Finds the file path hash from the prefetch file.
94-
client.railgun.kernel32.SetFilePointer(handle, hash_offset, 0, nil)
95-
hash = client.railgun.kernel32.ReadFile(handle, 4, 4, 4, nil)
96-
97-
# Finds the LastModified/Created timestamp (MACE)
98-
mtimes = client.priv.fs.get_file_mace(filename)
99-
100-
# Checking and moving the values
101-
if idx.nil? or count.nil? or hash.nil? or mtimes.nil?
102-
print_error("Error reading file (might be temporary): %s" % filename)
103-
else
104-
pname = Rex::Text.to_ascii(name.slice(0..idx))
105-
prun = count['lpBuffer'].unpack('L*')[0]
106-
phash = hash['lpBuffer'].unpack('h*')[0].reverse
107-
lmod = mtimes['Modified'].utc
108-
creat = mtimes['Created'].utc
109-
table << [lmod, creat,prun,phash,pname]
110-
end
111-
client.railgun.kernel32.CloseHandle(handle)
112-
end
113-
end
114-
115-
116-
def run
117-
118-
print_status("Prefetch Gathering started.")
119-
120-
# Check to see what Windows Version is running.
121-
# Needed for offsets.
122-
# Tested on WinXP, Win2k3 and Win7 systems.
123-
# http://www.forensicswiki.org/wiki/Prefetch
124-
# http://www.forensicswiki.org/wiki/Windows_Prefetch_File_Format
13+
include Msf::Post::Windows::Priv
14+
15+
def initialize(info={})
16+
super(update_info(info,
17+
'Name' => 'Windows Gather Prefetch File Information',
18+
'Description' => %q{
19+
This module gathers prefetch file information from WinXP, Win2k3 and Win7 systems.
20+
File offset reads for run count, hash and filename are collected from each prefetch file
21+
using WinAPI through Railgun while Last Modified and Create times are file MACE values.
22+
},
23+
'License' => MSF_LICENSE,
24+
'Author' => ['TJ Glad <fraktaali[at]gmail.com>'],
25+
'Platform' => ['win'],
26+
'SessionType' => ['meterpreter']))
27+
end
28+
29+
def prefetch_key_value()
30+
# 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
35+
print_error("EnablePrefetcher Value: (0) = Disabled (Non-Default).")
36+
elsif key_value == 1
37+
print_good("EnablePrefetcher Value: (1) = Application launch prefetching enabled (Non-Default).")
38+
elsif key_value == 2
39+
print_good("EnablePrefetcher Value: (2) = Boot prefetching enabled (Non-Default, excl. Win2k3).")
40+
elsif key_value == 3
41+
print_good("EnablePrefetcher Value: (3) = Applaunch and boot enabled (Default Value, excl. Win2k3).")
42+
else
43+
print_error("No value or unknown value. Results might vary.")
44+
end
45+
prefetch_key.close
46+
end
47+
48+
def timezone_key_values(key_value)
49+
# 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?
52+
print_line("Couldn't find key/value for timezone from registry.")
53+
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
59+
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)
63+
else
64+
offset = 0xffffffff
65+
bias = offset - tzbias
66+
print_good("Remote: Localtime bias to UTC: +%s minutes." % bias)
67+
end
68+
end
69+
end
70+
timezone_key.close
71+
end
72+
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)
79+
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)
97+
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)
102+
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]
109+
end
110+
client.railgun.kernel32.CloseHandle(handle)
111+
end
112+
end
113+
114+
def run
115+
print_status("Prefetch Gathering started.")
116+
# Check to see what Windows Version is running.
117+
# Needed for offsets.
118+
# Tested on WinXP, Win2k3 and Win7 systems.
119+
# http://www.forensicswiki.org/wiki/Prefetch
120+
# http://www.forensicswiki.org/wiki/Windows_Prefetch_File_Format
125121

126122
sysnfo = client.sys.config.sysinfo['OS']
127123
error_msg = "You don't have enough privileges. Try getsystem."
128124

129-
if sysnfo =~/(Windows XP|2003|.NET)/
130-
if not is_system?
131-
print_error(error_msg)
132-
return nil
133-
end
134-
# Offsets for WinXP & Win2k3
135-
print_good("Detected #{sysnfo} (max 128 entries)")
136-
name_offset = 0x10
137-
hash_offset = 0x4C
138-
lastrun_offset = 0x78
139-
runcount_offset = 0x90
140-
# Registry key for timezone
141-
key_value = "StandardName"
142-
143-
elsif sysnfo =~/(Windows 7)/
144-
if not is_admin?
145-
print_error(error_msg)
146-
return nil
147-
end
148-
# Offsets for Win7
149-
print_good("Detected #{sysnfo} (max 128 entries)")
150-
name_offset = 0x10
151-
hash_offset = 0x4C
152-
lastrun_offset = 0x80
153-
runcount_offset = 0x98
154-
# Registry key for timezone
155-
key_value = "TimeZoneKeyName"
156-
157-
else
158-
print_error("No offsets for the target Windows version. Currently works only on WinXP, Win2k3 and Win7.")
159-
return nil
160-
end
161-
162-
table = Rex::Ui::Text::Table.new(
163-
'Header' => "Prefetch Information",
164-
'Indent' => 1,
165-
'Columns' =>
166-
[
167-
"Modified (mace)",
168-
"Created (mace)",
169-
"Run Count",
170-
"Hash",
171-
"Filename"
172-
])
173-
174-
prefetch_key_value
175-
176-
timezone_key_values(key_value)
177-
178-
print_good("Current UTC Time: %s" % Time.now.utc)
179-
180-
sysroot = client.fs.file.expand_path("%SYSTEMROOT%")
181-
full_path = sysroot + "\\Prefetch\\"
182-
file_type = "*.pf"
183-
print_status("Gathering information from remote system. This will take awhile..")
184-
185-
# Goes through the files in Prefetch directory, creates file paths for the
186-
# gather_prefetch_info function that enumerates all the pf info
187-
188-
getfile_prefetch_filenames = client.fs.file.search(full_path,file_type,timeout=-1)
189-
if getfile_prefetch_filenames.empty? or getfile_prefetch_filenames.nil?
190-
print_error("Could not find/access any .pf files. Can't continue.")
191-
return nil
192-
else
193-
getfile_prefetch_filenames.each do |file|
194-
if file.empty? or file.nil?
195-
print_error("Could not open file: %s" % filename)
196-
else
197-
filename = File.join(file['path'], file['name'])
198-
gather_prefetch_info(name_offset, hash_offset, lastrun_offset, runcount_offset, filename, table)
199-
end
200-
end
201-
end
202-
203-
# Stores and prints out results
204-
results = table.to_s
205-
loot = store_loot("prefetch_info", "text/plain", session, results, nil, "Prefetch Information")
206-
print_line("\n" + results + "\n")
207-
print_status("Finished gathering information from prefetch files.")
208-
print_status("Results stored in: #{loot}")
209-
210-
end
125+
if sysnfo =~/(Windows XP|2003|.NET)/
126+
if not is_system?
127+
print_error(error_msg)
128+
return nil
129+
end
130+
# Offsets for WinXP & Win2k3
131+
print_good("Detected #{sysnfo} (max 128 entries)")
132+
name_offset = 0x10
133+
hash_offset = 0x4C
134+
lastrun_offset = 0x78
135+
runcount_offset = 0x90
136+
# Registry key for timezone
137+
key_value = "StandardName"
138+
139+
elsif sysnfo =~/(Windows 7)/
140+
if not is_admin?
141+
print_error(error_msg)
142+
return nil
143+
end
144+
# Offsets for Win7
145+
print_good("Detected #{sysnfo} (max 128 entries)")
146+
name_offset = 0x10
147+
hash_offset = 0x4C
148+
lastrun_offset = 0x80
149+
runcount_offset = 0x98
150+
# Registry key for timezone
151+
key_value = "TimeZoneKeyName"
152+
153+
else
154+
print_error("No offsets for the target Windows version. Currently works only on WinXP, Win2k3 and Win7.")
155+
return nil
156+
end
157+
158+
table = Rex::Ui::Text::Table.new(
159+
'Header' => "Prefetch Information",
160+
'Indent' => 1,
161+
'Columns' =>
162+
[
163+
"Modified (mace)",
164+
"Created (mace)",
165+
"Run Count",
166+
"Hash",
167+
"Filename"
168+
])
169+
prefetch_key_value
170+
timezone_key_values(key_value)
171+
print_good("Current UTC Time: %s" % Time.now.utc)
172+
sysroot = client.fs.file.expand_path("%SYSTEMROOT%")
173+
full_path = sysroot + "\\Prefetch\\"
174+
file_type = "*.pf"
175+
print_status("Gathering information from remote system. This will take awhile..")
176+
177+
# Goes through the files in Prefetch directory, creates file paths for the
178+
# gather_prefetch_info function that enumerates all the pf info
179+
180+
getfile_prefetch_filenames = client.fs.file.search(full_path,file_type,timeout=-1)
181+
if getfile_prefetch_filenames.empty? or getfile_prefetch_filenames.nil?
182+
print_error("Could not find/access any .pf files. Can't continue.")
183+
return nil
184+
else
185+
getfile_prefetch_filenames.each do |file|
186+
if file.empty? or file.nil?
187+
print_error("Could not open file: %s" % filename)
188+
else
189+
filename = File.join(file['path'], file['name'])
190+
gather_prefetch_info(name_offset, hash_offset, lastrun_offset, runcount_offset, filename, table)
191+
end
192+
end
193+
end
194+
195+
# Stores and prints out results
196+
results = table.to_s
197+
loot = store_loot("prefetch_info", "text/plain", session, results, nil, "Prefetch Information")
198+
print_line("\n" + results + "\n")
199+
print_status("Finished gathering information from prefetch files.")
200+
print_status("Results stored in: #{loot}")
201+
end
211202
end

0 commit comments

Comments
 (0)