Hi guys,
There has been some talks about ftp, security and LVS recently and different
opinions appeared. I wasn't aware of the fact the people still heavily use
the ftp protocol through a firewall, rather then putting a completely secluded
box in a corner. Back here at terreActive we have been fighting with the ftp
problem since 4 years already and we have not yet the ultimate solution. As
such we also evaluated the SuSE FTP proxy available from
http://www.suse.de/en/support/proxy_suite/
What follows is an evaluation mostly done by one of our coworkers Martin
Trampler and me (ratz). We're not yet finished with testing everything and
all possible setups (NAT, non-NAT, client behind a firewall, etc.) but the
result looks rather good in terms of improving security. A better paper will
probably follow, but we're too busy right now and ftp is anyway not allowed
in our company policy unless the customer has a special SLA.
Best regards,
Roberto Nibali, ratz
--
mailto: `echo NrOatSz@xxxxxxxxx | sed 's/[NOSPAM]//g'`
Title: SuSE FTP Proxy evaluation (as transparent proxy)
Tests : mt & ratz, countless hours during night.
Author: mt; xx/May/2001, ratz; shortened and edited for LVS
mailinglist
General
Motivated by
1. the general problems related to allowing FTP-traffic through a not
stateful packetfilter
2. the special problems we encountered with the Firewall-1 software
on one of our packetfilter which in the end forced us to deinstall FW1
3. the broken Linux FTP-masquerading module
I started in March/01 with a search for a FTP Proxy-software, which
could be used as a drop-in on pab1/2-machines to increase the security
of the machines (clients and servers) behind the packetfilters. Since
it was a requirement that this Software should be able to
transparently proxy external clients (i.e. the clients don't realize
that there is a proxy inbetween), there was only one package which
deserved a closer look: The FTP-Proxy from the SuSE Proxy Suite (which
actually consists of nothing but this FTP-Proxy). This Proxy since
about 4 months also includes support for transparent proxying mode.
Mode of operation
The Proxy consists of a single binary (ftp-proxy, stripped about 50k).
All configuration-options can be set in a single configuration-file
which by default is named ftp-proxy.conf and searched for in whatever
directory was given with the configure-option --sysconfdir=. If this
option was not given it is searched for in
/usr/local/proxy-suite/etc/, which shows SuSEs braindead BSD-heritage.
Best way is, to give the config-file at runtime with the -f
cmdline-option.
It is very useful to compile debugging-support into the binary during
evaluation and to run it with the cmdline-option -v 4 for maximum
debugging. Debugging output is then appended to /tmp/ftp-proxy.debug.
It can be run from (x)inetd or in standalone-mode as daemon. I only
evaluated the daemon.
It reads the config-file (which must exist) and binds to some local
port (e.g. 3129, which is IANA-unassigned and squid+1). The
Packetfilter has to be configured to redirect all packets which come
in on port 21 to this port (more later). As soon as it gets a request
it handles it by first replying to the client only. After the initial
USER <username> command it connects to the server (or, more exactly,
to port 21 of the host whose IP was the destination of the redirected
package).
The configfile may contain user-specific sections which direct special
users to special servers. This feature may be very useful but was not
evaluated either. It then continues as an agent between client and
server; checking either side's communication for correct syntax, as a
good application-proxy should.
As soon as the client prepares a data connection (either by sending a
PASV or a PORT command, it acknowledges it and, in case of a requested
passive connection, establishes a listener which binds to the server's
IP (!!). This came rather as a surprise to me. It actually works and
means, that the data connection is transparent as well for the client.
The range of port on which it listens is configureable as well as the
range of ports it uses for outgoing connection (to either the server
or to the client in the active-ftp case).
As soon as the client actually wants to retrieve data, the connection
to the server is established and the data is shuffeled around. Since
the connection to the server is completely seperate from the client
connection, its mode doesn't have to be the one the client requests
(also by default it is). The data-connection to the server may also be
configured to always be active or passive. Here it is clearly
desireable to always use passive mode to avoid opening another
listener on the packetfilter.
Evaluation
After initially having some minor problems to compile the proxy (it
has to be configured --with-regex) and to get it running (by default
it thinks it is started by inetd, i.e. standalone-mode is not the
default) it ran without problems and also wrote informative messages
into the debugging file. Almost everything can be configured in the
configuration file (also not everything is documented unambigously)
but in general the quality of the documentation, the logging and the
debugging messages seems quite high.
The proxy is, as already mentioned, completely transparent for the
client and of course intransparent for the server (i.e. the server
sees the connections coming from the client).
First more extensive stress-testing and code-review performed on
04/Apr/01 showed the following irregularities:
* Using active ftp, the data-connection on the server-side often
failed. This problem could be circumvented by forcing the Proxy to
always use passive mode on the server side (which should be used
anyways, see below)
* The control-connection on the server side often could not be
established.
* When running with debugging-output enabled, we found strange
characters in the debugging as well as in the logging-output.
The failed connections result from portnumbers being reused where they
should be increased. I think, this problem would also be found on the
client-side of the connection if the stress-test would issue more than
1 data-retrieving command. It may help to undefine the
Destination[Min|Max]Port configuration directive to get a port
assigned by the system.
The - attack-behaviour vanished after disabling debugging
output but may nevertheless being an issue. We found a questionable
use of a static char* in a formatting routine.
Integration into a firewall suite
Packetfilter-ruleset
First the Packetfilterport on which the proxy listens must be closed.
It is well possible to bind the proxy to e.g. localhost, but the
ipchains ... -j REDIRECT (see below) only allows the specification of
a port, not of port+IP. If the proxy is bound to an IP it doesn't get
the packets. It has to be universally bound and therefore its port
must be closed.
In the following I use:
PASV_PORTS: Configuration-directives "Passive[Min|Max]DataPort"; Ports
on which Listeners for passive connections (to Clients) may be
installed
SC_PORTS: Configuration-directives "Destination[Min|Max]Port"; Ports
which are used for connecting to the server (control-conn., data-conn.
if server in passive mode) or on which the proxy listens for the
server's data (if server in active mode, not documented). For
client-connections it is necessary that:
* In the input-chain (for the IF on which client packets arrive)
there must be a redirect for packets from the client to the
server, port 21 to the port on which the proxy listens.
* In the input-Chain (for the IF on which client packets arrive)
connections from the client to the server on port (UNPRIV->21) and
(UNPRIV->PASV_PORTS) are accepted (as well as the reply-packets in
the output-chain). The redirect-rule already acts as accepting
rule for the incoming packets for port 21.
Furthermore in the output-chain connections from the proxy (but
with IP-adress of the server!), port 20, to the client (UNPRIV)
must be allowed (as well as the corresponging reply-packets in the
input-chain).
For server-connections it is necessary that:
* In the output-chain of the server-side IF connections from the
proxy (SC_PORTS) to port 21 of the server are allowed (and the
reply packets in the input-chain)
* In the output-chain of the server-side IF connections from the
proxy (SC_PORTS) to the server (UNPRIV) are allowed (and the reply
packets in the input-chain)
The latter pair of rules covers the case that all data connections
from the proxy to the server are passive.
Note, that no rules for the forward-chain are necessary at all.
Have a look at this nice ASCII-Art, which shows the
control-connection.
+--------------------------+
| | Proxy | |
| |3129____________| |
+--------+ tcp/21 |----- ^ | -----| tcp/21 +--------+
| Client |----------->|eth0| | +->|eth1|---------->| Server |
+--------+ to server |--------+redirect -----| +--------+
|Packetfilter |
+--------------------------+
The obvious problem is, to formulate a fw-ftp-proxy script which
accepts 2 NEs (external client, internal server) as input and does not
generate redundant rules. Because the server-side connection is
completely independent from the client, its rules must only be added
once for each server while the client-side rules (including the
redirect) are dependent of both server and client. Probably the best
way would be to add a script which only handles the client-side and to
add each ftp-server seperately with a "tcp@fw"-rule. Since tcp@fw does
not allow specification of source-ports, this rule would then be wider
as necessary.
In the client-side script, the portrange used in the proxy-configfile
would then have to be hardwired. It would be necessary to verify, that
for every server used as target in a client-side script there is at
least (or even better exactly one) tcp@fw as described above.
Security considerations
General Aspects
We had a swift look at the code and it looks rather clean and well
documented to me. Unfortunately some features are incorrectly
documented or not documented at all while some features are already
documented but not yet implemented.
As already mentioned, the port on which the proxy listens has to be
closed. The servers should only be driven in passive mode, which
should be possible for any server. The PASV_PORTS should be restricted
to a dozen or so (depending on the load).
For the maintainers of the servers, the major drawback is the proxy's
intransparency.
Features not yet evaluated
* User-specific configurations
* Use with LDAP and the TCP-Wrapper library (configure-options
--with-ldap and --with-libwrap
* Limiting the set of allowed commands
* Proc-Filesystem Interface (module)
* chroot of forked processes
Conclusion
General Aspects
Given the current situation, where we shoot huge holes in the firewall
to fully enable (passive) ftp connections to servers located inside,
the use of this proxy would greatly increase the security of these
systems.
Prior to deployment I think the code should be reviewed more closely
(remember that the proxy opens listeners on the PF!) and some more
efforts should be undertaken to find a configuration which is as tight
as possible by providing the required functionality (cf. the section
above).
Extensions
It should, in general, be possible to have a second proxy running for
inside clients. There we still have the problem, that we have to open
the whole UNPRIV-Range for connections coming from sourceport 20.
Basically I think, that this problem should be handled differently:
Providing the functionality is the business of the server (hence the
name) . The FTP-Protocol provides passive mode exactly for this case
(firewalled client). So we should in general not allow clients behind
our Firewalls/Packetfilters to make active FTP connections.
We found out that it should not be too difficult to enable
"bidirectional transparency".
|