Background
rpc.statd and rpc.lockd are designed to work in conjunction with each other to manage NFS lock information in the event of a crash of an NFS client or server.
The rpc service rpc.statd is a program designed to communicate status information to other 'interested' computers on the network. That is, rpc.statd is designed to notify other computers when the host computer has crashed, and to receive notification when other systems have crashed.
The notification of crashes is delivered to another program, rpc.lockd. rpc.lockd manages locks for NFS clients and servers. When rpc.lockd is notified that a system has crashed, it will take appropriate action for any NFS locks that might exist between itself and the crashed system.
automountd is a program designed to automatically mount certain filesystems when files residing in those filesystems are referenced. This functionality is commonly used in conjunction with NFS file systems, though automountd can be used with other filesystems as well.
The "certain" file systems that will be mounted by automountd are specified in a file named /etc/auto_master. By default, /etc/auto_master contains the following entries:
# Master map for automounter # +auto_master /net -hosts -nosuid /home auto_home /xfn -xfn
The first column is a list of autofs (the automountd file system) mount points. Any reference to a file in one of the autofs file systems (by default, /net, /home, /xfn, and the special entry +auto_master) will cause automountd to attempt to mount the right filesystem.
The "right" filesystem is determined by the second column in /etc/auto_master. The second column is the name of an automount "map" used to locate the filesystem. The map is used to find the file system (for example, by specifying the name of an appropriate NFS mount point) and is assumed to be a filename relative to /etc. For example, the map for the /home filesystem is the file /etc/auto_home. The maps -hosts and -xfn are not really files, but rather special directives to the automounter. The meaning of the special directives is beyond the scope of this document. For more information, see the automount man page.
When a reference to a file in an autofs filesystem (as determined by the first column of the /etc/auto_master file) is made, the automountd daemon attempts to locate and mount the "right" filesystem (as determined by the corresponding map).
The interface to automountd is an rpc call. Automountd does not normally listen on either the UDP or TCP interfaces, but instead listens only on the TLI interface. Technically, automountd listens on the ticlts, ticotsord, and/or ticots transports as defined in /etc/netconfig. You can see this by using the rpcinfo command:
(45) unix3 % rpcinfo program version netid address service owner 100000 4 ticots unix3.green.cert.org.rpc rpcbind superuser 100000 3 ticots unix3.green.cert.org.rpc rpcbind superuser 100000 4 ticotsord unix3.green.cert.org.rpc rpcbind superuser 100000 3 ticotsord unix3.green.cert.org.rpc rpcbind superuser 100000 4 ticlts unix3.green.cert.org.rpc rpcbind superuser 100000 3 ticlts unix3.green.cert.org.rpc rpcbind superuser 100000 3 tcp 0.0.0.0.0.111 rpcbind superuser 100000 2 tcp 0.0.0.0.0.111 rpcbind superuser 100000 4 udp 0.0.0.0.0.111 rpcbind superuser 100000 3 udp 0.0.0.0.0.111 rpcbind superuser 100000 2 udp 0.0.0.0.0.111 rpcbind superuser . . .
This example shows the entries for rpcbind, aka portmapper, program.
Furthermore, automountd will act on requests only if they come from "root." Other users, even if they can send requests over the TLI interface, should not be able to precipitate the automounting of a filesystem.
Finally, if the map corresponding to the mount request is an executable file, automountd will attempt to execute it. The output of the executed map is expected to be a map itself, which automountd will use to locate the filesystem.
Thus, the relationship between automountd and rpc.statd is ordinarily limited to the fact that both automountd and rpc.statd are used in conjunction with NFS. They (automountd and rpc.statd) ordinarily have no direct relationship to one another.
Registering interest using rpc.statd
In order to know which other machines to notify in the event of a crash, rpc.statd maintains a list of machines that have registered their "desire" to be notified. In the parlance of rpc.statd, system A "monitors" system B by sending a SM_MON message to system B. System B records system A in a list of machines-to-be-notified, called the notification queue.
Ordinarily, the rpc.statd program of an NFS client would notify the rpc.statd program on the NFS server in the event of a crash, and vice-versa. When a crash occurs, the appropriate machines are notified using the SM_NOTIFY call in rpc.statd.
It is possible to specify an arbitrary rpc procedure as the target of the notification. That is, some of the arguments in the SM_MON procedure specify the rcp program number and IP address of the machine to be notified in the event of a crash. Ordinarily, the rpc program number used is the number for rpc.statd, which happens to be 100024.
Notification by rpc.statd
When a status change occurs, rpc.statd traverses its notification queue, and sends a message to each of the machines on that list, using the rpc program and IP address specified in the original SM_MON call. Because rpc.statd is designed to work with other instances of rpc.statd, it sends a message with a structure known to rpc.statd, and not ordinarily used by other rpc procedures. The structure of the notification message is listed in /usr/include/rpcsvc/sm_inter.x, and is given as
struct stat_chge { string mon_name<SM_MAXSTRLEN>; int state; };
That is, a null-terminated string of size less than 1024, followed by an integer.
The "rpc.statd bounce" vulnerability
By specifying an rpc program other than an instance of rpc.statd, an intruder can cause rpc.statd to send a stat_chge structure, containing data influenced by the intruder, to the rpc program specified by the intruder.
For instance, by specifying rpc program number 100099 in the SM_MON request, an intruder can cause rpc.statd to send a stat_chge structure to the rpc program AUTOFS_PROG, which is automountd. The automountd program will interpret the stat_chge structure as if it were "normal" input to the automountd program.
Additionally, the intruder is able to specify an IP address as part of the SM_MON call. If the intruder specifies the IP address of the victim machine, rpc.statd on the victim machine will notify itself in the event of a status change.
Furthermore, rpc.statd will use the /etc/netconfig database in an attempt to locate a suitable transport through which to contact the specified program (in our example, automountd). Thus, an intruder is able to "bounce" information from rpc.statd to any other rpc service, even if the other rpc service does not accept packets via TCP or DP. This allows remote intruders greater access than was probably intended. That is, intruders can send data via the Internet to an rpc service that normally only accepts packets that originated locally.
Vulnerabilities in automountd
There are a number of related vulnerabilities in automountd.
See VU#15371, VU#4878, VU#18833, VU#11731.
Combining VU#18287 with automountd vulnerabilities
It is possible for an intruder to combine the rpc.statd bounce vulnerability with vulnerabilities in automountd. In particular, if an intruder is able to produce a stat_chge structure using rpc.statd that contains data that would exercise a vulnerability in automountd, then an intruder can exploit that vulnerability in automountd remotely.
We are aware of at least one instance where this sort of combination is useful for an intruder. We have confirmed in our own lab that it is possible for an intruder to combine VU#18287 with VU#4878. We were able to execute arbitrary commands with the privileges of the automountd process.
In the course of our testing, we were not able to devise a way to execute commands when the victim system was patched with 104654-04 or 104654-05, or the corresponding patches for systems other than 2.5.1.
Logging
As mentioned above, rpc.statd maintains a notification queue of system to be notified in the event of a status change. There appear to be two representations of the notification queue in rpc.statd. One representation is an in-memory data structure, the other is a set of on-disk files. This duplicate representation of the notification queue has implications regarding the amount of data that will be logged by default by syslog.
In the event of a system crash, the on-disk representation is necessary to notify other systems once the local system has crashed. Ordinarily, statd will create a file named /var/statmon/sm/<system> where system is the name of a computer to be notified upon reboot after a crash.
It appears that rpc.statd was always sensitive to the problem of creating relative files, and rpc.statd was apparently modified statd in such a way so as to prevent the monitoring of systems with a "/" or ".." in their names. That prevented the problem of an intruder trying to "monitor" a system named "../../<somefile>" and thus getting rpc.statd to create the file /var/statmon/sm/../../<somefile>.
The modification was apprently made to the section of code responsible for the on-disk representation of the notification queue, but not the section of code responsible for the in-memory representation of the notification queue.
Further, the modification was such that rpc.statd would not create the file, and it would create a log entry similar to this:
Apr 15 00:00:00 statd[2468]: attempt to create "/var/statmon/sm/; echo "ingreslock stream tcp nowait root /bin/sh sh -i" >>/tmp/bob; /usr/sbin/inetd -s /tmp/bob &"
This log line is an indication by rpc.statd that an attempt to monitor a system called "; echo .... /usr/sbin/inetd -s /tmp/bob &" failed to make it into the on-disk representation of the notification queue.
However, it appears that rpc.statd maintains a system with that name in the memory-resident representation of the notification queue.
Thus, even though the log line suggests that the system named "; echo .... /usr/sbin/inetd -s /tmp/bob &" failed to make it into the notification queue, it still exists in the memory-resident version of the queue. This is why the SM_NOTIFY call still works despite that fact that the system didn't make it to the on-disk version of the queue.
Significantly greater logging information can be obtained by using the -T and -v options of automountd and the -D switch in statd, and configuring syslog so that debugging and user level events are saved to a file.
|