Re: (spoofed) RPC portmapper set/unset

From: Bill Paul (wpaulat_private)
Date: Sun Nov 15 1998 - 08:38:39 PST

  • Next message: Raphael Muzzio: "Re: ISS Security Advisory: Hidden community string in SNMP"

    Of all the gin joints in all the towns in all the world, Theo de Raadt
    had to walk into mine and say:
    
    > 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.
    [...]
    
    There's really only one way to completely fix this problem with portmap,
    and that is simply not to use TCP or UDP. Instead, you need to use a
    local-only transport, such as an AF_LOCAL socket. It's actually very
    easy to do this: I took copies of the TCP transport client and server
    modules from the FreeBSD RPC library and converted them to use AF_LOCAL
    stream sockets instead of AF_INET.
    
    Additionally, if you use an AF_LOCAL socket in conjunction with SCM_CREDS
    credential transfers, you can provide a much more secure mechanism for
    preventing local users from setting/unsetting mappings that don't
    belong to them.
    
    As you say, this does require changes to libc, so it's not something
    to be undertaken lightly and it would be difficult to manage with
    commercial systems for which you don't have the source code.
    
    With TI-RPC, you already have a special loopback transport available
    which provides similar functionality. However TI-RPC is based on TLI,
    and none of the BSD-based systems or Linux have support for TLI or
    STREAMS (yet) so they use the older RPC 4.0 instead, which only
    supports TCP and UDP. I had a choice between trying to implement all
    of the necessary support code to make TI-RPC work in FreeBSD or add
    an additional transport to the existing RPC library. Lacking the
    time and understanding needed to do the former, I instead chose the
    latter.
    
    The advantage to using an AF_LOCAL socket is that right away the server
    can tell if it's handling a remote or local request by checking the
    family type of the socket in its transport handle. TCP or UDP sockets
    will be AF_INET instead of AF_LOCAL. Procedures that really care
    about enforcing access can choose to deny connections from AF_INET
    sockets, which will lock out any non-local process. Also, by using
    SCM_CREDS, the portmapper can check which local user is sending the
    request (and can be relatively sure of the information since it's
    provided by the kernel, not the caller, and is thus harder to spoof).
    This means that if user A registers a service, the portmapper can
    insure that only user A (or root) can unregister it later. Right
    now, access checks are performed in rpcinfo, which is a bad idea
    (access checks should be in the server, not the client).
    
    You still need to allow UDP/TCP access to some of the proceedures
    since remote hosts have to be able to reference the port/program number
    mappings and use the callit routine, but restricting the set/unset
    procedures by only allowing AF_LOCAL connections insures that no
    remote process can ever fiddle with the mapping tables.
    
    I had plans to do this for FreeBSD and actually added code to libc
    to test for an AF_LOCAL socket special file and use that if it's
    present, rolling over to the old mechanism if it isn't. However I
    still need to modify portmap itself, which is a little tricky because
    I want to store the EUID of the caller that registers a service for
    access checks later, and the structure used to store the mappings
    doesn't have room for this. Unfortunately, this structure is set in
    stone in the portmap protocol specification. Before I was able to
    get very far on this, I got sidetracked by other things.
    
    My main reason for creating this extra transport and adding the SCM_CREDS
    support to the kernel was for the Secure RPC keyserv program, which, in
    RPC 4.0, also uses a terrible kludge not too different from the mess in
    portmap to enforce access restrictions to its secret key tables. Keyserv
    normally relies on the bletcherous keyenvoy program, which the client
    has to invoke in order to talk to the key server. The problem here is
    that a client can't use Secure RPC credentials and verifiers until
    the user does a keylogin to load his secret key into the local keyserv,
    but keyserv also needs to use an authentication mechanism to make sure
    that another user can't spoof a request to steal the user's secret key
    once it's been loaded. TI-RPC uses the loopback transport and a special
    TLI routine called t_getinto() to do this, which does away with the need
    for the keyenvoy program. However FreeBSD doesn't have TLI/STREAMS, so
    I had to improvise.
    
    -Bill
    
    --
    =============================================================================
    -Bill Paul            (212) 854-6020 | System Manager, Master of Unix-Fu
    Work:         wpaulat_private | Center for Telecommunications Research
    Home:  wpaulat_private | Columbia University, New York City
    =============================================================================
    "Mulder, toads just fell from the sky!" "I guess their parachutes didn't open."
    =============================================================================
    



    This archive was generated by hypermail 2b30 : Fri Apr 13 2001 - 14:23:28 PDT