Re: Solaris rpcbind tricks

From: Adam Morrison (adamat_private)
Date: Sun Aug 22 1999 - 04:59:45 PDT

  • Next message: Anonymous: "(no subject)"

    >   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