Skip to content

FTP Permission & Upload Testing

5 min read Created Dec 29, 2025 Last updated Aug 11, 2026

This phase identifies write access and dangerous misconfigurations. Upload permission on FTP often indicates a broader problem: weak ACLs, anonymous write access, or a shared directory exposed to a web server. Any writable path that overlaps with a web root can turn a file upload into remote code execution. Even without web overlap, writable directories are worth documenting as a misconfiguration finding.

  • Permission scanning look for drwxrwxrwt or world-write bits in directory listings, especially /incoming, /upload, /pub, /tmp.
  • mkdir/rmdir test create and remove a test directory to confirm write and delete access without leaving artifacts.
  • curl upload test quick one-liner upload with a timestamped test file to confirm write access non-interactively.
  • lftp interactive upload navigate the tree and upload with tab completion when curl fails on server quirks.
  • FTPS upload add --ssl-reqd or set ssl:verify-certificate no for servers requiring TLS.
  • Cleanup remove test artifacts immediately with DELE to avoid detection by monitoring tools.

Spot Writable Directories

Look for directories showing drwxrwxrwt or group/world write bits during enumeration. Common targets: /incoming, /upload, /pub, /tmp. World-writable directories are the most interesting. Group-writable directories may require valid credentials to exploit. Note every path with permissive bits. Cross-reference them against any web server document root you identify separately.

Manual verification inside an active session confirms what the listing shows. Creating and removing a test directory gives write and delete proof without leaving artifacts on disk.

┌──(kali㉿kali)-[~]
└─$ ftp $TARGET_IP
ftp> pwd
ftp> ls -la
ftp> mkdir .testdir
ftp> rmdir .testdir

Successful creation and removal confirms write access in the current directory. If mkdir succeeds but rmdir fails, the directory is sticky , you can create but not delete others' files. That still enables upload. If both commands fail, the directory is read-only from your current user context. Test each candidate path separately, since permissions often differ between subdirectories.

Basic Upload Test

A timestamped test file keeps uploads identifiable. The timestamp in the filename makes it easy to correlate against server logs if needed. Use curl for quick one-liner uploads without entering an interactive session. Target the most permissive directory you identified: /incoming is the most common drop zone on misconfigured FTP servers.

┌──(kali㉿kali)-[~]
└─$ echo "HackIndex upload test - $(date)" > test.txt
┌──(kali㉿kali)-[~]
└─$ curl -T test.txt ftp://anonymous:anonymous@$TARGET_IP/incoming/

Retrieving the file immediately after upload confirms both write and read access. If the file is readable, the directory is not a write-only drop zone. A readable upload directory is more exploitable: attackers can stage, retrieve, and iterate on payloads in place. Note whether the file content is intact to rule out transfer encoding issues on binary uploads.

┌──(kali㉿kali)-[~]
└─$ curl ftp://anonymous:anonymous@$TARGET_IP/incoming/test.txt

For FTPS: FTPS requires TLS and may reject self-signed certificates by default. The --ssl-reqd flag forces the connection to use encryption. Add --insecure to bypass certificate validation when the server uses a self-signed certificate, which is common on internal targets.

┌──(kali㉿kali)-[~]
└─$ curl --ssl-reqd -T test.txt ftps://anonymous:anonymous@$TARGET_IP/incoming/

Upload with lftp

lftp gives you a persistent interactive session with tab completion and scripting support. It handles both FTP and FTPS natively. Use it when you need to navigate the directory tree before uploading, or when curl returns a protocol error you want to debug interactively. The session lets you ls and confirm directory contents between commands.

┌──(kali㉿kali)-[~]
└─$ lftp -u anonymous,anonymous ftp://$TARGET_IP
> cd incoming
> put test.txt
> ls -l test.txt
> bye

For FTPS: Disable certificate verification inline with set ssl:verify-certificate no. This is commonly required against self-signed certificates on internal FTP servers. The -e flag passes a semicolon-separated command sequence so you can run the entire session non-interactively from a single shell command.

┌──(kali㉿kali)-[~]
└─$ lftp -u anonymous,anonymous ftps://$TARGET_IP -e "set ssl:verify-certificate no; cd incoming; put test.txt; ls -l test.txt; bye"

Cleanup

Remove test artifacts immediately after confirming upload access. Uploaded files can be flagged by monitoring tools, antivirus scanners, or picked up by other users with access to the same directory. The DELE FTP command removes a remote file. Passing it via curl --quote sends the raw FTP command before any data transfer. Follow up with a directory listing or a failed retrieval to confirm the file is gone.

┌──(kali㉿kali)-[~]
└─$ curl ftp://user:pass@$TARGET_IP/incoming/ --quote "DELE test.txt"

Writable directories combined with weak authentication or web exposure often lead to full compromise. If any writable FTP path maps to a web-accessible directory, upload a webshell and request it over HTTP to confirm execution. Even without web overlap, a writable directory can stage payloads for retrieval via a separate vector. Document all writable paths, their permission bits, whether anonymous access is sufficient, and whether the server allows overwriting existing files.