FTP Analyzer
From BroWiki
Contents |
Overview
The FTP Analyzer processes traffic associated with the FTP file transfer service RFC-959. Bro instantiates an ftp analyzer for any connection with service port 21/tcp, providing you have loaded the ftp analyzer, or defined a handler for ftp_request or ftp_reply. The analyzer uses a capture filter of port ftp. It generates summaries of FTP sessions; looks for sensitive usernames, access to sensitive files, and possible FTP bounce attacks, in which the host specified in a PORT or PASV directive does not correspond to the host sending the directive; or in which a different host than the server (client) connects to the endpoint specified in a PORT (PASV) directive.
Code Documentation
ftp_session_info record
The main data structure managed by the ftp analyzer is a collection of ftp_session_info records, where the record type is shown below:
| Code: ftp_session_info |
type ftp_session_info: record {
id: count; # unique number associated w/ session
user: string; # username, if determined
request: string; # pending request or requests
num_requests: count; # count of pending requests
request_t: time; # time of request
log_if_not_denied: bool; # unless code 530 on reply, log it
log_if_not_unavail: bool; # unless code 550 on reply, log it
log_it: bool; # if true, log the request(s)
};
|
The corresponding fields are:
- id
- The unique session identifier assigned to this session. Sessions are numbered starting at 1 and incrementing with each new session.
- user
- The username associated with this session (from the initial FTP authentication dialog), or an empty string if not yet determined.
- request
- The pending request, if the client has issued any. Ordinarily there would be at most one pending request, but a client can in fact send multiple requests to the server all at once, and an attacker could do so attempting to confuse the analyzer into mismatching responses with requests, or simply forgetting about previous requests. ; num_requests : A count of how many requests are currently pending.
- request_t
- The time at which the pending request was issued.
- log_if_not_denied
- If true, then when the reply to the current request comes in, Bro should log it, unless the reply code is 530 (“denied”).
- log_if_not_unavail
- If true, then when the reply to the current request comes in, Bro should log it, unless the reply code is 550 (“unavail”).
- log_it
- If true, then when the reply to the current request comes in, Bro should log it.
ftp variables
The standard script defines the following redefinable variables:
- ftp_guest_ids : set[string]
- A set of usernames associated with publicly accessible “guest” services. Bro interprets guest usernames as indicating Bro should use the authentication password as the effective username.
- default:
{ "anonymous", "ftp", "guest", }. - ftp_skip_hot : set[addr, addr, string]
- Entries indicate that a connection from the first given address to the second given address, using the given string username, should not be treated as hot even if the username is sensitive.
- default: empty.
- Example: redefining
ftp_skip_hotusing
redef ftp_skip_hot: set[addr, addr, string] += {
[[bob1.dsl.home.net, bob2.dsl.home.net],
bob.work.com, "root"], };
- would result in Bro not noticing FTP connections as user root from either bob1.dsl.home.net or bob2.dsl.home.net to the server running on bob.work.com.
- ftp_hot_files : pattern
- Bro matches the argument given in each FTP file manipulation request (RETR, STOR, etc.) against this pattern to see if the file is sensitive. If so, and if the request succeeds, then the access is logged.
- default: aggdrop a pattern that matches various flavors of password files, plus any string with eggdrop in it. Note: Eggdrop is an IRC management tool often installed by certain attackers upon a successful break-in.
- ftp_not_actually_hot_files : pattern
- A pattern giving exceptions to ftp_hot_files. It turns out that a pattern like /passwd/ generates a lot of false hits, such as from passwd.c (source for the passwd utility; this can turn up in FTP sessions that fetch entire sets of utility sources using MGET) or passwd.html (a Web page explaining how to enter a password for accessing a particular page).
- default: /(passwd|shadow).*.(c|gif|htm|pl|rpm|tar|zip)/.
- ftp_hot_guest_files pattern
- Files that guests should not attempt to access. :default: .rhosts and .forward. :skip_unexpected : set[addr]
- If a new host (address) unexpectedly connects to the endpoint specified in a PORT or PASV directive, then if either the original host or the new host is in this set, no message is generated. The idea is that you can specify multi-homed hosts that frequently show up in your FTP traffic, as these can generate innocuous warnings about connections from unexpected hosts.
- default: some hp.com hosts, as an example. Most are specified as raw IP addresses rather than hostnames, since the hostnames don’t always consistently resolve.
- skip_unexpected_net : set[addr]
- The same as skip_unexpected, except addresses are masked to /24 and /16 before looked up in this set. :default: empty.
In addition, ftp_log holds the name of the FTP log file to which Bro writes FTP session summaries. It defaults to open_log_file("ftp"). Here is an example of what entries in this file look like:
| Code: example entries in ftp.log |
972499885.784104 #26 131.243.70.68/1899 > 64.55.26.206/ftp start 972499886.685046 #26 response (220 tuvok.ooc.com FTP server (Version wu-2.6.0(1) Fri Jun 23 09:17:44 EDT 2000) ready.) 972499886.686025 #26 USER anonymous/IEUser@ (logged in) 972499887.850621 #26 TYPE I (ok) 972499888.421741 #26 PASV (227 64.55.26.206/2427) 972499889.493020 #26 SIZE /pub/OB/4.0/JOB-4.0.3.zip (213 1675597) 972499890.135706 #26 *RETR /pub/OB/4.0/JOB-4.0.3.zip, ABOR (complete) 972500055.491045 #26 response (225 ABOR command successful.) |
Here we see a transcript of the 26th FTP session seen since Bro started running. The first line gives its start time and the participating hosts and ports. The next line (split across two lines above for clarity) gives the server’s welcome banner. The client then logged in as user anonymous, and because this is one of the guest usernames, Bro recorded their password too, which in this case was IEUser@ (a useless string supplied by their Web browser). The server accepted this authentication, so the status on the line is (logged in).
The client then issues a request for the Image file type, to which the server agreed. Next they issued a PASV directive, and received a response instructing them to connect to the server on port 2427/tcp for the next transfer. At this point, after issuing a SIZE directive (to which the server returned 1,675,597 bytes), they send RETR to fetch the file /pub/OB/4.0/JOB-4.0.3.zip. However, before the transfer completed, they issued ABOR, but the transfer finished before the server processed the abort, so the log shows a status of completed. Furthermore, because the client issued two commands without waiting for an intervening response, these are shown together in the log file, and the line marked with a “*” so it draws the eye.
Finally, because Bro paired up the (completed) with the multirequest line, it then treats the response to the ABOR command as a reply by itself, showing in the last line that the server reported it successfully carried out the abort. The corresponding lines in the ‘conn’ file look like:
972499885.784104 565.836 ftp 118 427 131.243.70.68 64.55.26.206 RSTO L #26 anonymous/IEUser@ 972499888.984116 165.098 ftp-data ? 1675597 131.243.70.68 64.55.26.206 RSTO L
The first line summarizes the FTP control session (over which the client sends its requests and receives the server’s responses). It includes an addl annotation of #26 anonymous/IEUser@, summarizing the session number (so you can find the corresponding records in the ftp log file) and the authentication information.
The second line summarizes the single FTP data transfer, of 1,675,597 bytes. The amount of data sent by the client for this connection is shown as unknown because the client aborted the connection with a RST (hence the state RSTO). For connections that Bro does not look inside (such as FTP data transfers), it learns the amount of data transferred from the sequence numbers of the SYN and FIN connection control packets, and can’t (reliably) learn them for the sender of a RST. (It can for the receiver of the RST).
They also aborted the control session (again, state RSTO), but in this case, Bro captured all of the packets of the session, so it could still assign sizes to both directions.
ftp functions
The standard ftp script provides one function for external use:
- is_ftp_data_conn (c: connection): bool
- Returns true if the given connection matches one we’re expecting as the data connection half of an FTP session. Note: This function is not idempotent: if the connection matches an expected one, then Bro updates its state such that that connection is no longer expected. It also logs a discrepancy if the connection appears to be usurping another one that generated either a PORT or a PASV directive.
- Also returns true if the source port is 20/tcp and there’s currently an FTP session active between the originator and responder, in case for some reason Bro’s bookkeeping is inconsistent.
ftp event handlers
The standard script handles the following events:
- ftp_request (c: connection, command: string, arg: string)
- Invoked upon the client side of connection c having made the request command with the argument arg.The processing depends on the particular command:
- USER
- Specifies the username that the client wishes to use for authentication. If it is sensitive — in
hot_ids(which the ftp analyzer accesses via a@loadofhot-ids) — then the analyzer flags the FTP session as notice-worthy. In addition, if the username is inforbidden_ids, then the analyzer terminates the session. The analyzer also updates the connection’saddlfield with the username. - PASS
- Specifies the password to use for authentication. If the password is empty and the username appears in
forbidden_ids_if_no_password(also from thehot-ids analyzer), then the analyzer terminates the connection. If the username corresponds to a guest account (ftp_guest_ids), then the analyzer updates the connection’saddl<code> field with the password as additional account information. Otherwise, it generates an <code>account_triedevent to facilitate detection of password guessing. - PORT
- Instructs the FTP server to connect to the given IP address and port for delivery of the next FTP data item. The analyzer first checks the address/port specifier for validity. If valid, it will generate a notice if either the address specified in the directive does not match that of the client, or if the port corresponds to a “privileged” port, i.e., one in the range 0–1023. Finally, it establishes state so that
is_ftp_data_conncan identify a subsequent connection corresponding to this directive as belonging to this FTP session. - ACCT
- Specifies additional accounting information associated with a session, which the analyzer simply adds to the connection’s field.
- APPE, CWD, DELE, MKD, RETR, RMD, RNFR, RNTO, STOR, STOU
- All of these manipulate files (and directories). The analyzer checks the filename against the policies to see if it is sensitive in the context of the given username (i.e., guest or non-guest), and, if so, marks the connection to generate a notice unless the operation fails. The analyzer also checks for an excessively long filename, currently by checking its length against a hardwired maximum of 250 bytes (deficiency).
- ftp_reply (c: connection, code: count, msg: string, cont_resp: bool)
- Invoked upon the server side of connection c having replied to a request using the given status code and text message.
cont_respis true if the reply line is tagged as being continued to the next line. The analyzer only processes requests when the last line of a continued reply is received. - The analyzer checks the reply against any expected for the connection (for example,
log_if_not_denied) and generates notices accordingly. If the reply corresponds to a PASV directive, then it parses the address/port specification in the reply and generates notices in an analogous fashion as done by theftp_requesthandler for PORT directives. - Finally, if the reply is not one that the analyzer is hardwired to skip (code 150, used at the beginning of a data transfer, and code 331, used to prompt for a password), then it writes a summary of the request and reply to the FTP log file (see ftp variables). Also, if the reply is an orphan (there was no corresponding request, perhaps because Bro started up after the request was made), then the reply is summarized in the log file by itself.
The standard ftp script defines one other handler, an instance of used to flush FTP session information in case the session terminates abnormally and no reply is seen to the pending request(s).
ftp notices
The FTP analyzer can generate the following Notices:
- FTP::FTP BadPort - Bad format in PORT/PASV
- FTP::FTP ExcessiveFilename - Very long filename seen
- FTP::FTP PrivPort - Privileged port used in PORT/PASV
- FTP::FTP Sensitive -Sensitive connection (as defined in hot)
- FTP::FTP UnexpectedConn - Data transfer from unexpected src. Suppose there’s an FTP session between client A and server B, and either A issues a PORT or B issues a PASV. Then what’s expected is that A will rendezvous with B using the port specified in the PORT/PASV. If instead a new IP address C connects to (or accepts from) the negotiated port, that generated FTP UnexpectedConn.
Examples
References
This article is a Stub. You can help Bro-Wiki by expanding it.
