A while back we came across an exploitation scenario with an FTP server that we were assessing that we thought was interesting enough to share - largely because its an issue that has been known about since 1999, but doesn’t seem to be widely exploited - at least publicly.
First its important to understand how FTP works when in passive mode, which is the most common configuration we come across in deployment nowadays. FTP uses two separate TCP connections to the FTP server - a command channel and a data channel. FTP commands are sent over the command channel, which is usually on port 21. The data channel is the connection that is used for a transfers of data, including directory listings or file downloads and uploads, and in passive mode this is another connection from the client to the FTP server on a port opened by the FTP server in order to send or receive the data.
For example, this is how a sample passive FTP session might go, including the commands that will be issued to the FTP server in the background. Note the response to the PASV command, which supplies the IP address and port (in high/low byte order) for the client to connect to:
220 foo.bar.com FTP server ready.
---> USER user
331 Password required for user.
---> PASS password
230 User user logged in.
215 UNIX Type: L8
Remote system type is UNIX.
Using binary mode to transfer files.
Passive mode on.
227 Entering Passive Mode (192,168,1,1,195,149).
150 Opening ASCII mode data connection for file list
drwx------ 3 user users 104 Jul 27 01:45 my_files
226 Transfer complete.
Visually this will look something like the following:
Interestingly, looking at the RFC for FTP (RFC959) shows that the two connections do not both have to come from the same client, which allows FTP to support some less common usage scenarios such as server to server transfers using a common client. For our purposes it raises the possibility that if we can hit the data port that is allocated on the FTP server at the right time, we will get the file transfer or directory listing that another client has requested, like follows:
This race condition issue, as it turns out, has been known since 1999 as the “Pizza Thief” exploit (CVE-1999-0351), and turns out to be fairly easy to exploit in actual usage scenarios that we’ve come across.
In practice, guessing the port comes down to a combination of two factors - how much load the FTP server is under, and how randomly it allocates the data ports for downloads. If the port allocation is sequential (which is not uncommon) this is fairly trivial, however as enterprise FTP deployments commonly have a small fixed range of ports allowed through a firewall for passive FTP, this can also be practical to exploit in cases where the data port allocation is randomised (even aside from any weaknesses in just how random the allocation actually is). If the server allows anonymous FTP, or you can obtain an account through other means, this just makes the job of predicting the data ports easier for you.
We ended up exploiting this scenario by writing a quick Python script to brute-force connect to the range of ports the server we were looking at was using, and grabbed a number of documents the organisation was sharing with an international business partner. Turns out FTP isn’t so secure after all? ;)