The final application currently built into Bro is Telnet, a service for remote interactive access [PR83a]. There are several significant difficulties with monitoring Telnet traffic. The first is that, unlike FTP, Telnet traffic is virtually unstructured. There are no nice ``USER xyz'' directives that make it trivial to identify the account associated with the activity; instead, one must employ a series of heuristics and hope for the best. This problem makes Telnet particularly susceptible to subterfuge attacks, since if the heuristics have holes, an attacker can slip through them undetected.
Our present goal is to determine Telnet usernames in a robust fashion, which we discuss in the remainder of this section. Scanning Telnet sessions for strings reflecting questionable activity is of course also highly interesting, but must wait for us to first add regular expression matching to Bro.
Recognizing the authentication dialog. The first facet of analyzing Telnet activity is to accurately track the initial authentication dialog and extract from it the usernames associated with both login failures and successes. Initially we attempted to build a state machine that would track the various authentication steps: waiting for the username, scanning the login prompt (this comes after the username, since the processing is line-oriented, and the full, newline-terminated prompt line does not appear until after the username has been entered), waiting for the password, scanning the password prompt, and then looking for an indication that the password was accepted or rejected (in which case the process repeats). This approach, though, founders on the great variety of authentication dialogs used by different operating systems, some of which sometimes do not prompt for passwords, or re-prompt for passwords rather than login names after a password failure, or utilize two steps of password authentication, or extract usernames from environment variables, and so on. We now are working on a simpler approach, based on associating particular strings (such as ``Password:'') with particular information, and not attempting to track the authentication states explicitly. It appears to work better, and its workings are certainly easier to follow.
The Telnet analyzer generates telnet_logged_in upon determining that a user has successfully authenticated, telnet_failure when a user has failed to authenticate, authentication_skipped if it recognizes the authentication dialog as one specified by the policy script as not requiring further analysis, and telnet_confused if the analyzer becomes confused regarding the authentication dialog. (This last could, for example, trigger full-packet recording of the subsequent session, for later manual analysis.)
Type-ahead. A basic difficulty that complicates the analysis is type-ahead. We cannot rely on the most-recently entered string as corresponding to the current prompt line. Instead, we keep track of user input lines separately, and consume them as we observe different prompts. For example, if the analyzer scans ``Password:'', then it associates with the prompt the first unread line in the user type-ahead buffer, and consumes that line. The hazard of this approach is if the Telnet server ever flushes the type-ahead buffer (due to part of its authentication dialog, or upon an explicit signal from the user), then if the monitor misses this fact it will become out of sync. This opens the monitor to a subterfuge attack, in which an attacker passes off an innocuous string as a username, and the policy script in turn fails to recognize that the attacker in fact has authenticated as a privileged user. One fix to this problem--reflecting a strategy we adopt for the more general ``keystroke editing'' problem discussed below--is to test both usernames and passwords against any list of sensitive usernames.
Unless we are careful, type-ahead also opens the door to another subterfuge attack. For example, an attacker can type-ahead the string ``Password:'', which, when echoed by the Telnet server, would be interpreted by the analyzer as corresponding to a password prompt, when in fact the dialog is in a different state. The analyzer defends against these attacks by checking each typed-ahead string against the different dialog strings it knows about, generating possible_telnet_ploy upon a match.
Usernames can also become disguised due to use of keystroke editing.
For example, we would like to recognize that ``rb
does indeed correspond to a username of root, assuming that
> is the single-character deletion operator. We find
this assumption, however, problematic, since some systems use
> and others use
We address this problem
by applying both forms of editing to usernames, yielding possibly
three different strings, each of which the script then assesses in turn.
So, for example, the string
is tested both directly, as
and as ``
Editing is not limited to deleting individual characters, however. Some systems support deleting entire words or lines; others allow access to previously-typed lines using an escape sequence. Word and line deletion do not allow an attacker to hide their username, if tests for sensitive usernames check for any embedded occurrence of the username within the input text. ``History'' access to previous text is more problematic; presently, the analyzer recognizes the operating system that supports this (VMS) and, for it only, expands the escape sequence into the text of the previous line.
The Telnet protocol supports a rich, complex mechanism for exchanging
options between the client and server [PR83b] (there are more than
50 RFCs discussing different Telnet options). Unhappily, we cannot
ignore the possible presence of these options in our analysis, because
an attacker can embed one in the middle of text they transmit in
order to disguise their intent--for example,
The Telnet server will dutifully strip out the option before passing along
the remaining text to the authentication system. We must do the same.
On the other hand, parsing options also yields some benefits: we
can detect connections that successfully negotiate to encrypt the
data session, and skip subsequent analysis (rather than generating
telnet_confused events), as well as analyzing options used for
authentication (for example, Kerberos) and to transmit the user's environment
variables (some systems use $USER as the default
username during subsequent authentication).