Software Engineering Institute Carnegie Mellon

rlogin(1): The Untold Story

2 The rlogin Program

2.1 Description of rlogin

Many UNIX systems provide the rlogin program. rlogin establishes a remote login session from its user’s terminal to a remote host computer. Here is an excerpt from Request for Comment (RFC) 1282 that describes the elemental functionality of rlogin:

The rlogin facility provides a remote-echoed, locally flow-controlled virtual terminal with proper flushing of output. It is widely used between UNIX hosts because it provides transport of more of the UNIX terminal environment semantics than does the Telnet protocol, and because on many UNIX hosts it can be configured not to require user entry of passwords when connections originate from trusted hosts [Kantor 91].

One feature of rlogin is that it passes the terminal type description from the local host computer to the remote host computer.2 This functionality allows terminal-aware programs such as full-screen text editors to operate properly across the computer-to-computer connection created with rlogin.

To do this, rlogin passes the user’s current terminal definition as identified by the TERM environment variable to the remote host computer. RFC 1282 describes how this terminal information is passed from the local host computer, where the rlogin client program is running, to the remote host computer, where service is sought.



2.2 Coding Defect in rlogin

Many implementations of the rlogin program contain a coding defect where the value of the TERM environment variable is copied without due care to an internal buffer. This means that the buffer holding the copied value of TERM can be overflowed. On some computer systems, the buffer is a variable local to the main subroutine, meaning that the local host computer’s subroutine linkage information can be overwritten with data from the TERM environment variable.1 Once overwritten, control can be transferred to an arbitrary address in a computer system’s memory.

Overrunning a local variable on the subroutine call stack is called stack smashing [Smith 97]. If the data that smashes the stack are carefully selected, control can be transferred to that data. These data are then interpreted as instructions that are subsequently executed by the local host computer. The nature of this code is completely under the control of the rlogin program user.

In addition, rlogin requires set-user-id root privileges so it can obtain a port in the required range, as described in the in.rlogind manual page. Here is an excerpt from that page:

The server checks the client's source port. If the port is not in the range 0-1023, the server aborts the connection. [Sun 97a]

More specifically, Figure 1 shows the fragment from rlogin that contains the defective code. In this code, data controlled by the user – the TERM environment variable – are copied with strcpy into the stack-based variable, term. If those data in TERM contain instructions appropriate for the local host computer that are properly synchronized with the subroutine linkage requirements, then when strcpy returns to its caller, it will instead return to the code that just smashed the stack. To compound the problem, rlogin has not yet shed its root privileges at the time that the strcpy subroutine is called. That happens with the setuid call later in the code. This means that when the smashed stack instructions are executed, they run with full root privileges.


Figure 1: Defective Code Segment
Figures in this file are displayed in a separate browser window. This window will remain open to display figures in this file, although it might be hidden behind other browser windows.

To exploit this coding defect, one need only craft the appropriate value for the TERM environment variable, place it in the environment that rlogin will inherit, and then run rlogin. In the exploitation scripts that we have seen at the CERT/CC, the code that smashes the stack starts a copy of /bin/sh, one of several standard command language interpreters typically found on a UNIX system. The user can then execute any commands that he or she chooses, and execute them as root.



2.3 Determining Vulnerability

For a computer system to be at risk, the computer system’s hardware and software architecture must support a program’s ability to determine the location of the subroutine linkage information. Further, once located, that architecture must support a program’s ability to change that information so that execution can continue at an arbitrary location in memory.

On most modern computer hardware and software architectures, a subroutine’s local variables are intermixed with subroutine linkage information. This means that the location of the linkage information can be computed given the addresses of local variables. In fact, several architectures place linkage information adjacent to a subroutine’s local variables. Because of this adjacency, exceeding the size of the storage allocated to one of the subroutine’s local variables can also change the subroutine linkage information. The key points here are the ability to determine the location of the linkage information and to change it. The adjacency attribute simplifies the location determination step. It is an aid, not a necessity.

The ability to execute instructions located in an arbitrary portion of a computer system’s memory is another key hardware and software architectural requirement. Some hardware architectures, notably Sun Microsystems’ SPARC® architecture, support the operating system’s ability to define a section of memory as being non-executable. This means that on a SPARC-based machine, the operating system can mark the instruction segments as executable and all other segments as non-executable. Execution control can be successfully transferred only to instruction segments, not an arbitrary location in memory. On the other hand, the Intel Pentium® hardware architecture does not have the ability to enforce these restrictions. Control can be transferred to an arbitrary location in memory where execution can continue.




1 We now know that buffer overflows that are not stack based can be just as bad as their stack-based counterparts. for details.

2 There are many references that describe how to select these data: [One 96, Mudge 96, Mudge 95, Lefty 96, Prym 96].

[Contents] [Figures] [References]

[next] [prev]

PDF file