> 2. Theres no check for the src address and port of the replies to > forwarded calls to match the dst address and port of the original > call. > > rpcbind does not check that RPC reply messages, received on the > socket used to forward CALLIT requests, have a valid source address, > > port, prognum, progvers, etc. Heh. This is actually a generic RPC vulnerability, dating back to the reference RPC implementation from Sun. This is the relevant excerpt from clnt_udp.c. Modern versions of this part of the code have not fixed this. (They mostly deal with the ugly cast at the end.) do { fromlen = sizeof(struct sockaddr); inlen = recvfrom(cu->cu_sock, cu->cu_inbuf, (int) cu->cu_recvsz, 0, (struct sockaddr *)&from, &fromlen); } while (inlen < 0 && errno == EINTR); if (inlen < 0) { if (errno == EWOULDBLOCK) continue; cu->cu_error.re_errno = errno; return (cu->cu_error.re_status = RPC_CANTRECV); } if (inlen < sizeof(u_long)) continue; /* see if reply transaction id matches sent id */ if (*((u_long *)(cu->cu_inbuf)) != *((u_long *)(cu->cu_outbuf))) continue; /* we now assume we have the proper reply */ break; This condition opens a window of vulnerability for an attacker. Suppose a privileged process makes an RPC query. Before the server replies, the attacker can guess the XID and inject a bogus reply back to the process, with no spoofing involved. Some examples: 1) The SunOS NFS client code allocates XIDs from a monotonically increasing counter (`clnt_xid'). (In SunOS 4.x, I think the counter was initially zero, but that's a hazy recollection. In SunOS 5.x, it is initialized upon the first RPC request to the number nanoseconds since the system booted.) It is therefore possible for a local attacker to e.g. make an executable file appear to be setuid root by injecting a bogus GETATTR reply. (But please read my note further on.) 2) The NIS library utilizes RPC to receive password information. Attackers could therefore inject bogus NIS replies to programs such as su(1M) to get root. 3) Similar to the above attack, attackers can poison the passwd cache of the Solaris name service cache daemon (nscd(1M)). So, what's the catch? To successfully carry out this attack, the attacker has to correctly guess the RPC xid before the RPC server sends its reply back to the client. The xid is typically generated using the oh-so-common method of xid = getpid() ^ now.tv_sec ^ now.tv_usec; Guessing this under this time constraint proves to be quite difficult. (It's sometimes difficult to know the value of `tv_sec' exactly, never mind iterating over `tv_usec'.) So it does not make for a very reliable attack. The rpcbind attack described in the previous message was unique in this respect; the xid aspect of the attack had to do with a fake server, so there was no race to win. Therefore, the general rule of thumb is that if - You have a privileged program making an RPC - And you can make the server `go away' - And you can perform a brute force of the xid within the RPC timeout Then you can do some interesting things; the point being that because of the failure to check where RPC replies came from, this attack works well for local, unprivileged attackers. Wrt to the NFS attack, it is pretty far fetched; I'd imagine that an environment in which it works would be quite rare. (It'd require relatively long timeouts and a VERY quiet client.) Ob-OpenBSD: OpenBSD started randomizing RPC xids (in the kernel, too) in early 1997, when I pointed this out to Theo de Raadt. Ob-other-BSDs: The NFS attack I described against SunOS above does not apply to the U of Guelph NFS implementation, because the code does a soconnect() to the NFS server. This causes an implicit check for the source of returned queries, performed by the socket level. (But someone should probably check this again; it's been a while.)
This archive was generated by hypermail 2b30 : Fri Apr 13 2001 - 14:57:54 PDT