Re: Exploit of rpc.cmsd

From: Andy Polyakov (approat_private)
Date: Sat Jul 10 1999 - 08:01:09 PDT

  • Next message: Darren Reed: "Re: your mail"

    Hi, everybody!
    
    > > The calendar manager (rpc.cmsd) on Solaris 2.5 and 2.5.1 is vulnerable
    > > to a buffer overflow
    > > attack...
    > Can you confirm that compromised system(s) were equipped with CDE? Or in
    > other words was it /usr/dt/bin/rpc.cmsd that was assigned to do the job
    > in /etc/inetd.conf?
    > > Further, it appears that even patched versions may be
    > > vulnerable.
    > Could you be more specific here and tell exactly which patches are you
    > talking about?
    I've got reply from Bob that it's whatever patches included into
    corresponding "Recommended Patch Cluster" he's talking about and it's
    /usr/openwin/bin/rpc.cmsd he had engaged. I still want to point out here
    that CDE patches are not included into those clusters and if you have
    CDE installed you have to do better than just ./install_cluster. Well,
    this of course helps only *if* the problem in question was brought to
    Sun's attention earlier *and* was actually fixed.
    > > Also, rpc.cmsd under
    > > Solaris 2.6 could also be problematic.
    In mean time I made some observations...
    
    Note that both /usr/openwin/bin/rpc.cmsd and /usr/dt/bin/rcp.cmsd drop
    their root privileges all the way down to euid=ruid=suid=1 under
    2.5[.1]. It's definitely not the case under 2.6 and 7 where rpc.cmsd
    runs as euid=1,ruid=suid=0 and can regain root priveleges at any time.
    What does it mean? If 2.5[.1] does exhibit buffer overflow, then root
    exploit has to be two-stage. While in 2.6 and 7 case it might be a
    classic one... Of course *if* they do exhibit buffer overflow... Well,
    the very least we know is that Sun considers some buffer overflows fixed
    in 2.6 by 105566-07. Shall we have a look? Let's 'cm_lookup -c
    blah-blahat_private' and simultaneously 'truss -p <rpc.cmsd's pid> on
    2.6.host:
    
    ...
    statvfs("/var/spool/calendar/callog.blah-blah", 0xEFFFF88C) Err#2 ENOENT
    open("/usr/spool/calendar/callog.blah-blah", O_RDONLY) Err#2 ENOENT
    ...
    
    Aha! I can choose whatever name I like! Well, doesn't necessarily mean a
    shit... But statvfs is a rare system call so let's 'dis
    /usr/dt/bin/rpc.cmsd' and look for calls to statvfs... There're only
    two! Fist call to statvfs in FCS version looks like following:
    
    	...
            1fb80:  40 01 1d 02        call         malloc
            1fb84:  90 10 21 01        mov          257, %o0
            1fb88:  b8 10 00 08        mov          %o0, %i4
    	...
            1fbc4:  90 10 00 1c        mov          %i4, %o0
            1fbc8:  40 01 1d 0e        call         sprintf
            1fbcc:  94 10 00 10        mov          %l0, %o2
            1fbd0:  90 07 bf 24        add          %fp, -220, %o0
            1fbd4:  40 01 1d 38        call         strcat
            1fbd8:  92 10 00 1c        mov          %i4, %o1
            1fbdc:  90 07 bf 24        add          %fp, -220, %o0
            1fbe0:  40 01 1d 38        call         statvfs
            1fbe4:  92 07 bf 64        add          %fp, -156, %o1
    	...
    
    Doesn't look good, huh? Indeed! %i4 points at 257 large buffer allocated
    with malloc. Then they do sprintf to it and then strcat it to %fp-220
    resulting in %fp-220 pointing at "/var/spool/calendar/callog.blah-blah".
    What makes me worried is that nor sprintf or strcat performs boundary
    checks. Well, one can still instruct sprintf in the format line... BUT!
    The buffer %i4 points at is 257 bytes large. And how much do we have
    left in %fp-220? What do they smash with stack overruns? Something
    between %fp and %fp-96, right? Secondly "/var/spool/calendar/callog." is
    a 27 char long constant. So that we can't have more than 220-96-27=97
    bytes left in %fp-220 which is way less than 257 %i4 points to...
    
    But let's have a look at rpc.cmsd coming with 105566-07:
    
    	...
            1fbf4:  40 01 1d c4        call         malloc
            1fbf8:  90 10 21 01        mov          257, %o0
            1fbfc:  b8 10 00 08        mov          %o0, %i4
    	...
            1fc3c:  90 10 00 1c        mov          %i4, %o0
            1fc40:  92 10 21 01        mov          257, %o1
            1fc44:  40 01 1d 98        call         snprintf
            1fc48:  96 10 00 10        mov          %l0, %o3
            1fc4c:  40 01 1d 8a        call         strlen
            1fc50:  90 07 bf 24        add          %fp, -220, %o0
            1fc54:  b0 10 00 08        mov          %o0, %i0
            1fc58:  40 01 1d 87        call         strlen
            1fc5c:  90 10 00 1c        mov          %i4, %o0
            1fc60:  90 06 00 08        add          %i0, %o0, %o0
            1fc64:  80 a2 20 3f        cmp          %o0, 63
            1fc68:  a2 10 20 00        clr          %l1
            1fc6c:  ba 10 20 00        clr          %i5
            1fc70:  08 80 00 04        bleu         0x1fc80
            1fc74:  90 07 bf 24        add          %fp, -220, %o0
    	...
            1fc80:  40 01 1d ec        call         strcat
            1fc84:  92 10 00 1c        mov          %i4, %o1
            1fc88:  90 07 bf 24        add          %fp, -220, %o0
            1fc8c:  40 01 1d ec        call         statvfs
            1fc90:  92 07 bf 64        add          %fp, -156, %o1
    	...
    
    Wow! Much, much better! First they make sure %i4 is intact with snprintf
    and secondly they make sure that strlen(%fp-220)+strlen(%i4) is no
    larger than 63 before calling strcat. It definitely looks like a stack
    overrun being actually fixed here, doesn't it?
    
    But we still don't know if this is the statvfs corresponding to the
    truss log shown above and FCS version doesn't necessarily have to
    exploitable. So let's have a look at the second statvfs call. That piece
    of code look exactly the same in *both* FCS and 105566-07 versions:
    
    	...
            39b50:  40 00 b7 01        call         umask
            39b54:  90 10 20 02        mov          2, %o0
            39b58:  7f ff fc dd        call         init_dir
            39b5c:  01 00 00 00        nop
            39b60:  11 00 01 57        sethi        %hi(0x55c00), %o0
            39b64:  92 02 20 40        add          %o0, 0x40, %o1
            39b68:  11 00 01 57        sethi        %hi(0x55c00), %o0
            39b6c:  94 02 20 44        add          %o0, 0x44, %o2
            39b70:  40 00 b6 03        call         sprintf
            39b74:  90 07 be e4        add          %fp, -284, %o0
            39b78:  90 07 be e4        add          %fp, -284, %o0
            39b7c:  40 00 b6 30        call         statvfs
            39b80:  92 07 bf 24        add          %fp, -220, %o1
    	...
    
    Two things. They again sprintf to a (%fp-220)-(%fp-284)=64 bytes large
    buffer which is dangerous. Yes, I know it doesn't necessarily means it's
    exploitable. BUT! On the other hand it's definitely not the code
    corresponding to the truss log, because I haven't seen no umask before
    statvfs.
    
    Yeah! Do apply 105566-07 a.s.a.p., it does fix something! But what about
    2.5[.1] and 7? Well, 2.5[.1] rpc.cmsd (i.e., both /usr/dt and
    /usr/openwin versions) unfortunately do not make any distinguishable
    system calls in reply to 'cm_lookup -c blah-blahat_private[.1].host' and I
    can't easily locate relevant code as analyzing the whole disassembler
    list doesn't really turn me on. As for 7, I leave it for your
    homework...
    
    Andy.
    



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