ftpd.c DoS Fix

From: Crist J. Clark (crist.clark@attbi.com)
Date: 01/20/03

Date: Mon, 20 Jan 2003 14:10:54 -0800
From: "Crist J. Clark" <crist.clark@attbi.com>
To: security@freebsd.org, net@freebsd.org

The current design of the FTP daemon leaves it open to denial of
service attacks where an attacker can lock out all other users from
making PORT (active) data connections. This DoS is mitigated by the
fact the attacker must have a valid login on the server (although
anonymous access will do) and that PASV (passive) mode is not

The problem lies in the way in which the server fails when it tries to
open a data connection in active mode. If the connection attempt fails
with an EADDRINUSE error, the server waits and tries the connection
again. Durning this wait period, 90 seconds is the hard-coded value,
the process is bound to port 20, using the bind() call. This is an
exclusive bind(). No other processes may bind() to port 20 for this 90
second wait. This locks all other processes from setting up active
data connections during this 90 second wait. Once the 90 seconds is
up, the attacker can easily start another 90 second wait.

The result is that an attacker with limited resources can prevent all
other users from making data connections rendering the server almost

I will describe an example of how to attack. It is trivial to automate
with a Perl script, but I will not be providing such a tool on a
public list.

1) Using a telnet client, log into the test victim FTP server
(obviously, this should be your server and it's availability should
not be critical).

2) Set up a data connection to your attacker host.

3) Set up a listening process on the attacker on the right port for
the data connection.

4) Do a LIST command.

5) Using the same port you used in (2), repeat (2), (3), and (4). (You
can't wait to long between (4) and (5) in this example, since we are
choking things up by trying to run over our previous connection still
in the TIME_WAIT state.)

That's it. You will have locked out all other data connections. During
the 90 seconds, try firing up another FTP session to the host and try
to do anything involving an active data connection (make sure you're
not using passive mode, in FreeBSD's ftp client, type 'pass').

I have a quick fix for this. Instead of holding onto our bind() of 20
while we wait, we release, and bind() again at our next try. The
inline patch below shows the diff without whitespace changes. A
complete diff is attached. The diffs are from HEAD, but it should
apply to any RELENG_* branch fine.

Unless anyone has some objections, I plan to commit this to HEAD and
RELENG_4 today and see about re@ and security-officer@ approval for
other branches.

As a final note, I came across this bug in a different vendor's FTP
daemon before checking if FreeBSD was vulnerable. You might want to
check you favorite FTP daemon today.

Index: ftpd.c
RCS file: /export/freebsd/ncvs/src/libexec/ftpd/ftpd.c,v
retrieving revision 1.132
diff -u -b -r1.132 ftpd.c
--- ftpd.c 16 Jan 2003 14:25:32 -0000 1.132
+++ ftpd.c 20 Jan 2003 21:26:39 -0000
@@ -1772,7 +1772,7 @@
         char sizebuf[32];
         FILE *file;
- int retry = 0, tos;
+ int retry = 0, tos, conerrno;
         file_size = size;
         byte_count = 0;
@@ -1840,6 +1840,7 @@
         if (usedefault)
                 data_dest = his_addr;
         usedefault = 1;
+ do {
         file = getdatasock(mode);
         if (file == NULL) {
                 char hostbuf[BUFSIZ], portbuf[BUFSIZ];
@@ -1852,16 +1853,22 @@
                 return (NULL);
         data = fileno(file);
- while (connect(data, (struct sockaddr *)&data_dest,
- data_dest.su_len) < 0) {
- if (errno == EADDRINUSE && retry < swaitmax) {
+ conerrno = 0;
+ if (connect(data, (struct sockaddr *)&data_dest,
+ data_dest.su_len) == 0)
+ break;
+ conerrno = errno;
+ (void) fclose(file);
+ data = -1;
+ if (conerrno == EADDRINUSE) {
                         sleep((unsigned) swaitint);
                         retry += swaitint;
- continue;
+ } else {
+ break;
+ } while (retry <= swaitmax);
+ if (conerrno != 0) {
                 perror_reply(425, "Can't build data connection");
- (void) fclose(file);
- data = -1;
                 return (NULL);
         reply(150, "Opening %s mode data connection for '%s'%s.",

Crist J. Clark                     |     cjclark@alum.mit.edu
                                   |     cjclark@jhu.edu
http://people.freebsd.org/~cjc/    |     cjc@freebsd.org

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-security" in the body of the message

Relevant Pages

  • Re: Question: FTP via alternate port
    ... The problem with FTP is that it requires two ports to operate. ... FTP command stream in order to dynamically open that port for the data ... Ideally the attacker would want to upload another tool onto the ...
  • Re: cannot access FTP on port 2121 thru the firewall
    ... Internally I can get to it just fine but when I go thru the firewall from the ... the firewall is allowing the traffic to go thru on port 2121. ... No, the problem's on the Cisco, because if it had an FTP Application Layer Gateway that could be told "2121 is hosting FTP traffic", it would be able to open up dynamic holes in the firewall for the data connections. ...
  • [NEWS] Java Sandbox and Stateful Firewalls Interaction
    ... The attacker must lure the victim to a carefully ... The attacker creates a specifically crafted web site. ... The victim's browser downloads the applet and begins to run it. ... A FTP server on the same machine that hosts the originating web site ...
  • Re: Mitigate FTP
    ... You should consider implementing an Network Intrusion Prevention System dependent on your firewall technology and network topology this should not be to hard to implement. ... Sniffing will only be possible if the attacker is in the same network segment as your FTP service, on a vulnerable downstream or upstream router from yourselves or people who access the FTP. ...
  • Re: Question: FTP via alternate port
    ... While FTP can be very hard to use in that kind of situation, the attacker could simply use http or https to transfer files if those port are open. ... Your issue is more than just with FTP server, FTP is probably the worst protocol to use in that kind of situation. ... Check your website for vulnerabilities to SQL injection, Cross site scripting and other web attacks before hackers do! ...