Skip to content

Comments

Security: Fix CVE-1999-0017 FTP bounce attack in net_ftp_server#131

Open
jmrplens wants to merge 1 commit intoARM-software:mainfrom
jmrplens:fix/cve-1999-0017-ftp-bounce
Open

Security: Fix CVE-1999-0017 FTP bounce attack in net_ftp_server#131
jmrplens wants to merge 1 commit intoARM-software:mainfrom
jmrplens:fix/cve-1999-0017-ftp-bounce

Conversation

@jmrplens
Copy link

Summary

The FTP server in MDK-Middleware does not validate whether the IP address provided in PORT and EPRT commands matches the IP of the connected client. This allows any authenticated user to instruct the server to open data connections toward arbitrary third-party hosts, which is a well-known attack vector documented as CVE-1999-0017.

This patch adds IP validation to the PORT/EPRT handler in net_ftp_server.c, rejecting commands that specify an IP address different from the client's. It follows the recommendation in RFC 2577, Section 3.

The problem

When a client sends a PORT command, the current implementation extracts only the port number via ftp_scan_dport() and immediately responds 200 Command okay, regardless of what IP address the command contains. The IP portion of the argument is never checked against the client's actual address.

In practice, this means an attacker who is authenticated on the FTP server can do the following:

$ ftp 192.168.1.50
> USER myuser
> PASS mypass
230 User logged in.
> PORT 8,8,8,8,0,80
200 Command okay.
> LIST

At this point the FTP server opens a TCP connection from its own address to 8.8.8.8 on port 80. The attacker never touches 8.8.8.8 directly -- the server does it on their behalf. This is the FTP bounce attack.

The same applies to EPRT:

> EPRT |1|10.0.0.5|22|
200 Command okay.

The server would then connect to an internal machine at 10.0.0.5 on the SSH port.

This lets an attacker:

  • Scan ports on internal machines behind the firewall (using loopback 127.0.0.1 or private addresses like 10.x.x.x, 192.168.x.x).
  • Relay traffic through the FTP server to reach hosts that the attacker cannot contact directly.
  • Obscure the origin of connections, since they appear to come from the FTP server's IP.

This class of vulnerability is catalogued as CWE-441: Unintended Proxy or Intermediary, which specifically lists CVE-1999-0017 as an observed example.

How to reproduce

You need an FTP client (or just a raw TCP socket) and access to a running MDK-Middleware FTP server. Python's ftplib is enough:

import ftplib

ftp = ftplib.FTP()
ftp.connect("192.168.1.50", 21)     # your FTP server
ftp.login("user", "pass")

# Ask the server to connect to an external host
resp = ftp.sendcmd("PORT 8,8,8,8,0,80")
print(resp)  # "200 Command okay" means the server accepted it -- vulnerable

If the server responds with 200, it will attempt to open a data connection to 8.8.8.8:80 on the next transfer command. A fixed server should respond with 504 Command not implemented for that parameter.

Additional cases to test:

Command Expected (fixed) Reason
PORT 8,8,8,8,0,80 504 External IP, bounce attack
PORT 127,0,0,1,0,22 504 Loopback, port scan
PORT 192,168,204,1,0,23 504 Different private IP
EPRT |1|8.8.8.8|80| 504 EPRT bounce variant
PORT <client_ip>,195,88 200 Legitimate, own IP

What this patch does

Files changed:

  • Components/Network/Source/net_ftp_server.c (4 functions added, PORT/EPRT handler modified)
  • Components/Network/Source/net_ftp_server.h (2 response codes added)

The patch introduces four static helper functions before ftp_listener():

  1. ftp_parse_port_ip() -- parses the IP address from PORT command arguments (h1,h2,h3,h4,p1,p2), using the existing net_atoi() function. Validates that each octet is in the 0-255 range.

  2. ftp_parse_eprt_ip() -- parses the IP address from EPRT command arguments (|1|addr|port|), following the format specified in RFC 2428. Currently supports IPv4 only (address family 1).

  3. ftp_validate_port_ip() -- compares the parsed IP against ftp_s->Client.addr using memcmp(). Returns false and logs with ERRORF() when there is a mismatch.

  4. ftp_validate_port_range() -- validates that the port number falls within the 1-65535 range.

The PORT/EPRT handler in ftp_listener() is modified to call these functions before accepting the command. If parsing fails, the server responds with 501 Syntax error in parameters. If the IP does not match the client's address, it responds with 504 Command not implemented for that parameter. Both codes are standard FTP response codes defined in RFC 959.

Two new response code constants are added to the header:

  • FTP_RESP_BADPARAM (maps to 501)
  • FTP_RESP_NOTIMPL (maps to 504)

Backward compatibility

This change does not affect legitimate FTP clients. Any client that uses PORT or EPRT with its own IP address (which is the normal behavior) will continue to work exactly as before. Clients using PASV or EPSV are not affected at all.

The only traffic that gets rejected is PORT/EPRT commands where the specified IP does not match the client's connection -- something that only happens intentionally (i.e., an attack or proxy FTP). Proxy FTP through third-party PORT commands is explicitly discouraged by RFC 2577.

References


Implementation Status

Add IP address validation to PORT and EPRT command handlers to prevent
FTP bounce attacks. The server now verifies that the IP specified in the
command matches the client's actual connection address before accepting it.

The current implementation blindly accepts any IP in PORT/EPRT commands,
allowing authenticated users to instruct the server to open data connections
toward arbitrary third-party hosts. This is documented as CVE-1999-0017
and explicitly addressed in RFC 2577, Section 3.

Changes in net_ftp_server.c:
- Add ftp_parse_port_ip() to extract and validate IP from PORT arguments
- Add ftp_parse_eprt_ip() to extract and validate IP from EPRT arguments
- Add ftp_validate_port_ip() to compare parsed IP against client address
- Add ftp_validate_port_range() to reject out-of-range port numbers
- Modify PORT/EPRT handler to call validation before accepting the command

Changes in net_ftp_server.h:
- Add FTP_RESP_BADPARAM (501) for malformed command parameters
- Add FTP_RESP_NOTIMPL (504) for rejected bounce attempts

Legitimate clients that specify their own IP in PORT/EPRT are not affected.
Clients using PASV or EPSV are not affected.

References:
- CVE-1999-0017
- RFC 2577 (FTP Security Considerations), Section 3
- RFC 959 (FTP), response codes 501, 504
- RFC 2428 (EPRT command format)
- CWE-441 (Unintended Proxy or Intermediary)
@jkrech jkrech requested a review from furbanc February 18, 2026 16:45
@jkrech jkrech added the bug Something isn't working label Feb 18, 2026
@furbanc
Copy link
Collaborator

furbanc commented Feb 20, 2026

Thank you for your contribution to improving the safety of our network middleware. I truly appreciate the effort you have put into this enhancement.

I will review your pull request as soon as I have the opportunity and will proceed with merging it afterward. This is an important safety improvement for our FTP server, and your work is greatly valued.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants