Lucene search
K

Anonymous FTP Access Detection

🗓️ 06 May 2026 19:01:18Reported by Matteo Cantoni <[email protected]>, g0tmi1kType 
metasploit
 metasploit
🔗 www.rapid7.com👁 361 Views

Detect anonymous FTP access, including read/write permissions.

Related
Code
ReporterTitlePublishedViews
Family
ATTACKERKB
CVE-1999-0497
1 Jan 199905:00
attackerkb
Circl
CVE-1999-0497
6 May 202613:28
circl
CVE
CVE-1999-0497
4 Feb 200005:00
cve
Cvelist
CVE-1999-0497
4 Feb 200005:00
cvelist
EUVD
EUVD-1999-0496
7 Oct 202500:30
euvd
Tenable Nessus
Anonymous FTP Enabled
22 Jun 199900:00
nessus
NVD
CVE-1999-0497
1 Jan 199905:00
nvd
OpenVAS
Anonymous FTP Login Reporting
23 Oct 201800:00
openvas
Positive Technologies
PT-1999-1174
1 Jan 199900:00
ptsecurity
Rapid7 Blog
Metasploit Wrap-Up 05/08/2026
8 May 202618:26
rapid7blog
Rows per page
# frozen_string_literal: true

##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Auxiliary
  include Msf::Exploit::Remote::Ftp
  include Msf::Auxiliary::Scanner
  include Msf::Module::Deprecated
  moved_from 'auxiliary/scanner/ftp/anonymous'

  def initialize
    super(
      'Name' => 'Anonymous FTP Access Detection',
      'Description' => 'Detect anonymous (read/write) FTP service access.',
      'References' => [
        ['URL', 'https://en.wikipedia.org/wiki/File_Transfer_Protocol#Anonymous_FTP'],
        ['CVE', '1999-0497'],
      ],
      'Author' => [
        'Matteo Cantoni <goony[at]nothink.org>',
        'g0tmi1k' # @g0tmi1k - additional features
      ],
      'License' => MSF_LICENSE,
      'Notes' => {
        'Stability' => [CRASH_SAFE],
        'SideEffects' => [IOC_IN_LOGS],
        'Reliability' => []
      }
    )

    register_options(
      [
        Opt::RPORT(21),
        OptBool.new('STORE_LOOT', [false, 'Store the directory listing as loot', true])
      ]
    )
  end

  def run_host(target_host)
    res = connect_login(true, false)

    if res
      dir = Rex::Text.rand_text_alpha(8)
      vprint_status("Testing write access, creating test directory: #{dir}")
      # Alt would be to use STOR
      write_check = send_cmd(['MKD', dir], true)

      if write_check && write_check =~ /^2/
        access_type = 'Read/Write'
        vprint_status("Removing test directory: #{dir}")
        send_cmd(['RMD', dir], true)
      else
        access_type = 'Read-only'
      end

      print_good("Anonymous #{access_type} access (#{@banner_version})")

      if datastore['STORE_LOOT']
        vprint_status('Listing directory contents')
        listing = send_cmd_data(['LS'], nil)
        if listing.nil?
          print_warning('Could not retrieve directory listing (data connection failed)')
        elsif listing[1].nil? || listing[1].empty?
          vprint_status('Directory listing: (empty)')
        else
          vprint_status("Directory listing:\n#{listing[1]}")
          path = store_loot('ftp.anonymous', 'text/plain', rhost, listing[1], 'ftp_anonymous.txt', 'Anonymous FTP directory listing')
          print_good("Directory listing stored to: #{path}")
        end
      end

      report_vuln(
        host: rhost,
        port: rport,
        proto: 'tcp',
        sname: 'ftp',
        name: 'Anonymous FTP Access',
        info: "Anonymous FTP login accepted with #{access_type} access",
        refs: references
      )
      register_creds(target_host, access_type)
    elsif banner
      print_warning("FTP service, but no anonymous access (#{banner_version})")
    else
      vprint_warning('No FTP banner received')
    end
  rescue ::Rex::TimeoutError, ::Rex::ConnectionError, ::EOFError, ::Errno::ECONNREFUSED => e
    vprint_error(e.message)
    report_host(host: rhost)
  rescue ::Interrupt
    raise $ERROR_INFO
  ensure
    disconnect
  end

  def register_creds(target_host, access_type)
    # Build service information
    service_data = {
      address: target_host,
      port: rport,
      service_name: 'ftp',
      protocol: 'tcp',
      workspace_id: myworkspace_id
    }

    # Build credential information
    credential_data = {
      origin_type: :service,
      module_fullname: fullname,
      private_data: datastore['FTPPASS'],
      private_type: :password,
      username: datastore['FTPUSER'],
      workspace_id: myworkspace_id
    }

    credential_data.merge!(service_data)
    credential_core = create_credential(credential_data)

    # Assemble the options hash for creating the Metasploit::Credential::Login object
    login_data = {
      access_level: access_type,
      core: credential_core,
      last_attempted_at: DateTime.now,
      status: Metasploit::Model::Login::Status::SUCCESSFUL,
      workspace_id: myworkspace_id
    }

    login_data.merge!(service_data)
    create_credential_login(login_data)
  end
end

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

12 Jul 2026 19:03Current
5.9Medium risk
Vulners AI Score5.9
EPSS0.07085
361