# NET::Ftp allows command injection in filenames

Ruby's Net::FTP gettextfile passes server-controlled filenames to Kernel#open, so a malicious FTP server can inject `| cmd` and achieve RCE on the client.

- Payout: hidden
- Severity: low
- Program: Ruby
- Found by: staaldraad
- Disclosed: 2017-12-19
- CVE: CVE-2017-17405
- Write-up quality: 6/10
- Original: https://hackerone.com/reports/294462
- Library page: https://bugbountylibrary.com/r/h1%3A294462
- Tags: area:oss domain:oss impact:rce kind:bounty platform:hackerone sev:low tech:ruby technique:source-review vuln:command-injection vuln:rce

**Target:** Net::FTP gettextfile localfile handling
**Root cause:** gettextfile calls Kernel#open(localfile, "w") on a value defaulting to File.basename(remotefile); Kernel#open treats a leading `|` as a pipe to a shell command.
**Steps:**
1. Set up a malicious FTP server returning a filename like `|id > pang` in LIST/NLIST output.
2. Client iterates remote files and calls `gettextfile(remotefile)` without supplying localfile.
3. Default localfile becomes `File.basename(remotefile)` = `|id > pang`.
4. `open(localfile, "w")` executes `id > pang`, creating file `pang` with command output.
**How found:** Reading Net::FTP source, noticed gettextfile uses Kernel#open with a default localfile derived from the server-supplied remotefile; recognized the `| cmd` pipe behavior of Kernel#open.
**Exploitation:** Attacker controls an FTP server the victim connects to; when the victim bulk-downloads files relying on the default localfile, the crafted filename is passed to Kernel#open and executed as a shell command.
**Insight:** Grep Ruby code for Kernel#open/`open(` with variables that can start with `|`; any filename or path derived from a remote/untrusted source passed to open() is a command injection sink, even when it looks like a plain file path.

