[8560] in bugtraq
Re: (spoofed) RPC portmapper set/unset
daemon@ATHENA.MIT.EDU (Theo de Raadt)
Sat Nov 14 20:35:53 1998
Date: Sat, 14 Nov 1998 13:13:01 -0700
Reply-To: Theo de Raadt <deraadt@CVS.OPENBSD.ORG>
From: Theo de Raadt <deraadt@CVS.OPENBSD.ORG>
X-To: ga <duncan@MYGALE.ORG>
To: BUGTRAQ@NETSPACE.ORG
In-Reply-To: Your message of "Fri, 13 Nov 1998 23:27:35 GMT."
<199811140025.AAA08034@central.napier.ac.uk>
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?