Bugtraq mailing list archives

Re: (spoofed) RPC portmapper set/unset


From: deraadt () CVS OPENBSD ORG (Theo de Raadt)
Date: Sat, 14 Nov 1998 13:13:01 -0700


Regarding:

-pmap_set : it is called when a rpc program wants to register itself in the
portmapper list (rpcinfo -p returns this list).

-pmap_unset : same as above but it's used to unregister a rpc program.
Again, Wietse' portmapper fixed almost all the holes related to pset/punset
rpc calls.

However, due to a restriction in the protocol, all the security problems
cannot be fixed easily. When a rpc program (such as rpc.mountd) wants to
un/register itself on the portmapper list, it sends an udp || tcp packet to
the portmapper (port 111) using the pmap_set or pmap_unset respectively.
The portmapper checks the validity of the call by determining if the rpc
packet comes from the localhost using a priviledged source port (between
512 and 1024 when -DCHECK_PORT option is used while compiling portmapper).
Unix authentification is not checked.

The unfortunate problem being that the typical Sun-based rpc library
uses a function called get_myaddress() to determine where it should
send the packet.  This function returns the machine's local IP
address, when it really should return 127.0.0.1.  This then causes
problems because a specially hacked portmap still cannot differentiate
between a spoofed or non-spoofed request.

As you can see, it's not big deal. By spoofing a pmap_set/pmap_unset udp
packet, it's possible to register or unregister any RPC programs on the
remote host (the program I attached to this mail illustrates this). All in
all, this can only lead to a DoS on the server for a _remote_ attacker (by
flooding the portmapper with pmap_set request or by unregistering services
such as mountd, nfsd or ypserv) but it can be worse because a _local_
attacker can set up rogue rpc programs on the server (registering his own
ypbind/ypserv program for example). This last local attack can lead to root
compromise (including the hosts which trust the ypserver); but well, it's
fairly clear that when an attacker cracked into one of your server, all
your systems are almost already compromised.

However, if we can tell for sure that a request is coming from
127.0.0.1, and that it is from a reserved port, then we will be doing
the right thing.

And that is what I did to the OpenBSD portmap and our libc, a long
time ago:

RCS file: /cvs/src/usr.sbin/portmap/portmap.c,v
revision 1.3
date: 1996/06/29 19:03:50;  author: deraadt;  state: Exp;  lines: +135 -64
multiple receivers, port checking. testing help from bitblt

As you can see, this isn't a new issue, since it was fixed in OpenBSD
more than two years ago.  There was also a whole bunch of bugtraq
postings which talked about this, or rather 'talked around this'... a
very vague sort of thing that happened back when der mouse stupidly
started spreading information I had asked him to keep private.  Other
vendor systems (especially statically linked programs) cannot fix this
as easily since it requires a change to get_myaddress() in libc.

possible solutions :

   - compile your portmapper with -DLOOPBACK_SETUNSET flag.. notice that
it's damn hard to implement because you have to change other things in your
rpc services as well as in your kernel config.

That functionality in Wietse's portmap appears to be based on the work
that we did earlier on in OpenBSD.  And as I've said, proper operation
requires a couple other changes to libc.  You can tell if a portmap
supports this by noting that port 111 is multiply bound:

tcp        0      0  127.0.0.1.111          *.*                    LISTEN
tcp        0      0  *.111                  *.*                    LISTEN
udp        0      0  127.0.0.1.111          *.*
udp        0      0  *.111                  *.*

Other portmappers may do this differently by using socket options which
return the address of the sender.

in libc-5.3.12 code, we can see that the xid of an rpc message is not
totally random :

Mithrandir:/tmp/libsrc/libc/rpc# grep call_msg.rm_xid clnt* -n
clnt_tcp.c:207: call_msg.rm_xid = getpid() ^ now.tv_sec ^ now.tv_usec;
clnt_udp.c:176: call_msg.rm_xid = getpid() ^ now.tv_sec ^ now.tv_usec;

getpid is usually not a high value so higher bits of the xid are defined by
the now.tv_usec value. An attacker may easily retrieve the date of the
system (ie. port 13) so, with a lot of luck and time, he should be able to
guess the next xid (ypbind uses a timeout of 10sec I think). Anyway, this
is pure theory and I haven't tried it yet so xid prediction may not be
easily done but, guess what, crackers are usually lucky and they have
plenty of time to spend on their computers...

Yes, a second problem.  This problem was also fixed almost two years
ago in OpenBSD; and I've also told many people about it in the past
(hi Oliver!)  I think that an attack on this was very possible against
/etc/rc-started services which have a known pid (of course in OpenBSD
pid numbers are now random too).  For instance, on a typically
compiled SunOS box... ypbind is almost always around pid 666...

clnt_udp.c:     call_msg.rm_xid = arc4random();
clnt_tcp.c:     call_msg.rm_xid = arc4random();
pmap_rmt.c:     msg.rm_xid = xid = arc4random();

RCS file: /cvs/src/lib/libc/rpc/clnt_udp.c,v
revision 1.10
date: 1997/01/02 09:21:05;  author: deraadt;  state: Exp;  lines: +2 -6
use arc4random for xid generation


Hmm.. These problems don't seem nearly as fresh & new when someone had
them fixed (in freely available source) two years ago, do they?



Current thread: