Impact
The ftp OTP application provides an FTP client. It is deprecated and scheduled for removal in OTP-30.
ftp_internal:handle_command/3 supports two passive-mode data connection paths depending on the ftp_extension option. The ftp_extension=true path (EPSV) correctly derives the data connection IP from the control socket peer address via peername(CSock), ignoring the server-supplied value. The ftp_extension=false path (PASV, lines 1505-1531) parses the IP directly from the server's 227 response and passes it to gen_tcp:connect/4 without any validation against the control connection peer address.
The default configuration uses the vulnerable path: mode=passive, ipfamily=inet, and ftp_extension=false are all defaults.
A malicious or compromised FTP server can include an arbitrary IP address and port in its 227 response, causing the client to open its data connection to that target instead of back to the server. On ftp:ls/1,2, ftp:nlist/1,2, and ftp:recv/2,3 operations, data read from the redirected target is returned to the caller. On ftp:send/2,3 and ftp:append/2,3 operations, the file content is written to the redirected target. This enables server-side request forgery (SSRF) against internal hosts, cloud metadata endpoints, or other services reachable from the FTP client host, as well as FTP bounce attacks against third-party hosts.
RFC 2577 (FTP Security Considerations, 1999) section 3 explicitly recommends that clients verify the IP address in a PASV response matches the control connection peer. The EPSV handlers in the same module implement this correctly.
Workarounds
- Pass
{ftp_extension, true} to ftp:open/2 to use EPSV instead of PASV. EPSV does not include an IP in the server response and is not affected.
- Pass
{mode, active} to ftp:open/2 to use active mode, where the client listens and the server connects back.
- Pass
{ipfamily, inet6} to ftp:open/2 to force IPv6, which also selects the EPSV path.
Affected/Unaffected Versions
A version larger than or equal to one of the listed patched versions is unaffected; otherwise, a version that satisfies an expression listed under affected versions is affected, and if it does not, it is unaffected.
The documentation of the OTP version scheme describes how versions should be compared. Note that versions used prior to OTP 17.0, when the new OTP version scheme was introduced, are never listed since it is not well defined how to compare those versions.
The vulnerability was introduced in OTP 17.4 (inets 5.10.4). In OTP 21.0 the ftp client was split out of inets into a standalone ftp OTP application (ftp 1.0). OTP versions before 17.4 are not affected.
Credits
Thanks to Jonatan Männchen for finding and responsibly disclosing this vulnerability to the Erlang/OTP project.
Impact
The
ftpOTP application provides an FTP client. It is deprecated and scheduled for removal in OTP-30.ftp_internal:handle_command/3supports two passive-mode data connection paths depending on theftp_extensionoption. Theftp_extension=truepath (EPSV) correctly derives the data connection IP from the control socket peer address viapeername(CSock), ignoring the server-supplied value. Theftp_extension=falsepath (PASV, lines 1505-1531) parses the IP directly from the server's 227 response and passes it togen_tcp:connect/4without any validation against the control connection peer address.The default configuration uses the vulnerable path:
mode=passive,ipfamily=inet, andftp_extension=falseare all defaults.A malicious or compromised FTP server can include an arbitrary IP address and port in its 227 response, causing the client to open its data connection to that target instead of back to the server. On
ftp:ls/1,2,ftp:nlist/1,2, andftp:recv/2,3operations, data read from the redirected target is returned to the caller. Onftp:send/2,3andftp:append/2,3operations, the file content is written to the redirected target. This enables server-side request forgery (SSRF) against internal hosts, cloud metadata endpoints, or other services reachable from the FTP client host, as well as FTP bounce attacks against third-party hosts.RFC 2577 (FTP Security Considerations, 1999) section 3 explicitly recommends that clients verify the IP address in a PASV response matches the control connection peer. The EPSV handlers in the same module implement this correctly.
Workarounds
{ftp_extension, true}toftp:open/2to use EPSV instead of PASV. EPSV does not include an IP in the server response and is not affected.{mode, active}toftp:open/2to use active mode, where the client listens and the server connects back.{ipfamily, inet6}toftp:open/2to force IPv6, which also selects the EPSV path.Affected/Unaffected Versions
A version larger than or equal to one of the listed patched versions is unaffected; otherwise, a version that satisfies an expression listed under affected versions is affected, and if it does not, it is unaffected.
The documentation of the OTP version scheme describes how versions should be compared. Note that versions used prior to OTP 17.0, when the new OTP version scheme was introduced, are never listed since it is not well defined how to compare those versions.
The vulnerability was introduced in OTP 17.4 (inets 5.10.4). In OTP 21.0 the
ftpclient was split out ofinetsinto a standaloneftpOTP application (ftp 1.0). OTP versions before 17.4 are not affected.Credits
Thanks to Jonatan Männchen for finding and responsibly disclosing this vulnerability to the Erlang/OTP project.