10
10
require 'msf/core/post/windows/registry'
11
11
class Metasploit3 < Msf ::Post
12
12
13
+ include Msf ::Post ::File
13
14
include Msf ::Post ::Windows ::Priv
15
+ include Msf ::Post ::Windows ::Registry
14
16
15
17
def initialize ( info = { } )
16
18
super ( update_info ( info ,
@@ -28,86 +30,62 @@ def initialize(info={})
28
30
29
31
def prefetch_key_value ( )
30
32
# 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
35
35
print_error ( "EnablePrefetcher Value: (0) = Disabled (Non-Default)." )
36
- elsif key_value == 1
36
+ elsif prefetch_key_value == 1
37
37
print_good ( "EnablePrefetcher Value: (1) = Application launch prefetching enabled (Non-Default)." )
38
- elsif key_value == 2
38
+ elsif prefetch_key_value == 2
39
39
print_good ( "EnablePrefetcher Value: (2) = Boot prefetching enabled (Non-Default, excl. Win2k3)." )
40
- elsif key_value == 3
40
+ elsif prefetch_key_value == 3
41
41
print_good ( "EnablePrefetcher Value: (3) = Applaunch and boot enabled (Default Value, excl. Win2k3)." )
42
42
else
43
43
print_error ( "No value or unknown value. Results might vary." )
44
44
end
45
- prefetch_key . close
46
45
end
47
46
48
47
def timezone_key_values ( key_value )
49
48
# 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?
52
52
print_line ( "Couldn't find key/value for timezone from registry." )
53
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
54
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 )
63
57
else
64
58
offset = 0xffffffff
65
- bias = offset - tzbias
59
+ bias = offset - tz_bias
66
60
print_good ( "Remote: Localtime bias to UTC: +%s minutes." % bias )
67
61
end
68
62
end
69
63
end
70
- timezone_key . close
71
- end
72
64
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 } " )
79
70
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
97
80
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"
102
84
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
109
87
end
110
- client . railgun . kernel32 . CloseHandle ( handle )
88
+ table << [ last_modified , created , run_count , path_hash , name ]
111
89
end
112
90
end
113
91
@@ -123,6 +101,9 @@ def run
123
101
error_msg = "You don't have enough privileges. Try getsystem."
124
102
125
103
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.
126
107
if not is_system?
127
108
print_error ( error_msg )
128
109
return nil
@@ -131,7 +112,6 @@ def run
131
112
print_good ( "Detected #{ sysnfo } (max 128 entries)" )
132
113
name_offset = 0x10
133
114
hash_offset = 0x4C
134
- lastrun_offset = 0x78
135
115
runcount_offset = 0x90
136
116
# Registry key for timezone
137
117
key_value = "StandardName"
@@ -145,7 +125,6 @@ def run
145
125
print_good ( "Detected #{ sysnfo } (max 128 entries)" )
146
126
name_offset = 0x10
147
127
hash_offset = 0x4C
148
- lastrun_offset = 0x80
149
128
runcount_offset = 0x98
150
129
# Registry key for timezone
151
130
key_value = "TimeZoneKeyName"
@@ -169,25 +148,25 @@ def run
169
148
prefetch_key_value
170
149
timezone_key_values ( key_value )
171
150
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\\ "
174
153
file_type = "*.pf"
175
154
print_status ( "Gathering information from remote system. This will take awhile.." )
176
155
177
156
# 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
179
158
180
159
getfile_prefetch_filenames = client . fs . file . search ( full_path , file_type , timeout = -1 )
181
160
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..) " )
183
162
return nil
184
163
else
185
164
getfile_prefetch_filenames . each do |file |
186
165
if file . empty? or file . nil?
187
- print_error ( "Could not open file: %s" % filename )
166
+ print_error ( "Could not open file: %s" % file )
188
167
else
189
168
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 )
191
170
end
192
171
end
193
172
end
0 commit comments