Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/auxiliary/scanner/ftp/ftp_anonymous.rb
70334 views
1
# frozen_string_literal: true
2
3
##
4
# This module requires Metasploit: https://metasploit.com/download
5
# Current source: https://github.com/rapid7/metasploit-framework
6
##
7
8
class MetasploitModule < Msf::Auxiliary
9
include Msf::Exploit::Remote::Ftp
10
include Msf::Auxiliary::Scanner
11
include Msf::Module::Deprecated
12
moved_from 'auxiliary/scanner/ftp/anonymous'
13
14
def initialize
15
super(
16
'Name' => 'Anonymous FTP Access Detection',
17
'Description' => 'Detect anonymous (read/write) FTP service access.',
18
'References' => [
19
['URL', 'https://en.wikipedia.org/wiki/File_Transfer_Protocol#Anonymous_FTP'],
20
['CVE', '1999-0497'],
21
],
22
'Author' => [
23
'Matteo Cantoni <goony[at]nothink.org>',
24
'g0tmi1k' # @g0tmi1k - additional features
25
],
26
'License' => MSF_LICENSE,
27
'Notes' => {
28
'Stability' => [CRASH_SAFE],
29
'SideEffects' => [IOC_IN_LOGS],
30
'Reliability' => []
31
}
32
)
33
34
register_options(
35
[
36
Opt::RPORT(21),
37
OptBool.new('STORE_LOOT', [false, 'Store the directory listing as loot', true])
38
]
39
)
40
end
41
42
def run_host(target_host)
43
res = connect_login(true, false)
44
45
if res
46
dir = Rex::Text.rand_text_alpha(8)
47
vprint_status("Testing write access, creating test directory: #{dir}")
48
# Alt would be to use STOR
49
write_check = send_cmd(['MKD', dir], true)
50
51
if write_check && write_check =~ /^2/
52
access_type = 'Read/Write'
53
vprint_status("Removing test directory: #{dir}")
54
send_cmd(['RMD', dir], true)
55
else
56
access_type = 'Read-only'
57
end
58
59
print_good("Anonymous #{access_type} access (#{@banner_version})")
60
61
if datastore['STORE_LOOT']
62
vprint_status('Listing directory contents')
63
listing = send_cmd_data(['LS'], nil)
64
if listing.nil?
65
print_warning('Could not retrieve directory listing (data connection failed)')
66
elsif listing[1].nil? || listing[1].empty?
67
vprint_status('Directory listing: (empty)')
68
else
69
vprint_status("Directory listing:\n#{listing[1]}")
70
path = store_loot('ftp.anonymous', 'text/plain', rhost, listing[1], 'ftp_anonymous.txt', 'Anonymous FTP directory listing')
71
print_good("Directory listing stored to: #{path}")
72
end
73
end
74
75
report_vuln(
76
host: rhost,
77
port: rport,
78
proto: 'tcp',
79
sname: 'ftp',
80
name: 'Anonymous FTP Access',
81
info: "Anonymous FTP login accepted with #{access_type} access",
82
refs: references
83
)
84
register_creds(target_host, access_type)
85
elsif banner
86
print_warning("FTP service, but no anonymous access (#{banner_version})")
87
else
88
vprint_warning('No FTP banner received')
89
end
90
rescue ::Rex::TimeoutError, ::Rex::ConnectionError, ::EOFError, ::Errno::ECONNREFUSED => e
91
vprint_error(e.message)
92
report_host(host: rhost)
93
rescue ::Interrupt
94
raise $ERROR_INFO
95
ensure
96
disconnect
97
end
98
99
def register_creds(target_host, access_type)
100
# Build service information
101
service_data = {
102
address: target_host,
103
port: rport,
104
service_name: 'ftp',
105
protocol: 'tcp',
106
workspace_id: myworkspace_id
107
}
108
109
# Build credential information
110
credential_data = {
111
origin_type: :service,
112
module_fullname: fullname,
113
private_data: datastore['FTPPASS'],
114
private_type: :password,
115
username: datastore['FTPUSER'],
116
workspace_id: myworkspace_id
117
}
118
119
credential_data.merge!(service_data)
120
credential_core = create_credential(credential_data)
121
122
# Assemble the options hash for creating the Metasploit::Credential::Login object
123
login_data = {
124
access_level: access_type,
125
core: credential_core,
126
last_attempted_at: DateTime.now,
127
status: Metasploit::Model::Login::Status::SUCCESSFUL,
128
workspace_id: myworkspace_id
129
}
130
131
login_data.merge!(service_data)
132
create_credential_login(login_data)
133
end
134
end
135
136