SLMail 3.0.2421 Stack Overflow...

From: Aleph One (aleph1at_private)
Date: Thu Jul 09 1998 - 09:54:17 PDT

  • Next message: Casper Dik: "Re: ncurses 4.1 security bug"

    ---------- Forwarded message ----------
    Date: Wed, 8 Jul 1998 17:32:02 PDT
    From: Ezekial Morrow <paceflowat_private>
    To: NTBUGTRAQat_private
    Subject: SLMail 3.0.2421 Stack Overflow...
    
    Product:             SLMail 3.0.2421 from Seattle Lab.
    Vulnerability:       Stack overflow - Remote execution of code.
                         Jeremy Kothe (paceflowat_private)
    
       If the "mail from" field exceeds 256 bytes, it will pass through the
    receive
       process without being trimmed... When the mail dispatcher picks up
    the mail
       file to process, it copies it into a stack buffer of only 256 bytes,
       overwriting the function return address and normally halting the
    SLMail
       server.
    
       The DOS attack is simple - simply send an e-mail with "mail from" >
    256 bytes.
    
       To exploit the attack to remotely execute code is difficult but NOT
       impossible. The main difficulty is that the string which overflows
    the stack
       (the "mail from" name) can contain only valid email address
    characters.
    
       But don't think that makes it impossible...
    
    Introduction
    
       Stack overflows under xnix are usually a simple affair - create a
    shell
       and pipe it to the attacker.
    
       Under Windows 95 or Windows NT, however, the task is a little more
    complex.
    
       If you are not familiar with basic win32 stack overflow methods, see
       dildog's excellent (although 40 iq points too dumb for most of us:})
    article
       at http:\\www.cultdeadcow, as well as his contributions at
       http:\\www.l0pht.com.
    
    Tools
    
       Microsoft's under-rated (though limited) WinDbg to debug and examine
       the fault.
    
       Borland's Turbo Assembler and DataRescue's IDA (disassembler) for
       converting my code into data bytes (no, sorry, I refuse to remember
    that
       0x50 is push eax... oh shit).
    
       Borland Delphi - my 3gl of choice for the Windows environment to
    create
       and send the e-mail. Any ip-capable platform could of course be used
    here.
    
    Gaining Control
    
       The idea behind ANY overflow execution exploit is to leverage a bug
    or crash
       to execute data. To do anything, we must first "snag the EIP".
    
       To do this, we must examine the environment produced by the initial
       crash, find somewhere a pointer to our data, and then somhow get it
    into the
       eip register...
    
       So let's take a look at the environment created when SLMail
    overflows...
    
       Fire up SLMail.exe (it's a service, so use "net start slmail" or the
       control panel), then start WinDbg and Attach (F6) to the SLMail
       process. Press F5 to continue execution...
    
       Now we create a test program to send a buffer of 1600-odd 0x61
    ("a")'s as
       the email from address. Running this program, our e-mail is accepted
    and
       placed, as a file, into SLMail's "In" subdirectory. SLMail.exe then
    picks up
       this file and bang... WinDbg reports our first-chance-exception at
    0x42264f.
    
    0042263C                 mov     ecx, [esp+114h+arg_0]
    00422643                 mov     edx, [esp+114h+arg_4]
    0042264A                 mov     eax, [esp+114h+var_104]
    0042264E                 pop     edi
    0042264F ==> exception   mov     [ecx], esi
    00422651                 mov     [edx], eax
    00422653                 mov     eax, ebp
    00422655                 pop     esi
    00422656                 pop     ebp
    00422657                 pop     ebx
    00422658                 add     esp, 104h
    0042265E                 retn
    
       The memory address which is being written to here happens to be
    0x61616161,
       which we see four lines above as being the procedure's first argument
    on the
       stack...  Looking at the registers, we find that the stack area has
    been
       well and truly overwritten by our test data, and that several
    registers
       (esp, esi, edi) are pointing to areas within this data area. And if
    we can
       stop the exception at 0x42264f, and the next one at 0x422651, then
    the retn
       will return to 0x61616161, or whatever else we choose to feed it...
    
       To stop the crash, we need to find an address which is writable, and
    place
       two copies of it into our buffer in the appropriate place...
    
       This would be no real problem except for our main limitation, the
       alphanumeric-only content of our buffer allows us only 1/1024 of the
       address space... So we search and search... Nothing in the main
    program,
       so one-by-one we check the dlls used. Now, this is where the issue of
       platform-dependency comes along. If we use an address in a dll, we
    are
       binding the exploit to that version of the dll. Any other versions
    would
       crash... Luckily, the proliferation of NT 4.0 sp3 platforms provide a
    number
       of large dlls which are fairly constant... (ie: user32.dll,
    kernel32.dll).
       It's worth remembering that NT server and workstation binaries are
    identical,
       so even by targeting only this one platform, an attacker could
    probable
       achieve a > 70% success rate on a random basis.
    
       So eventually, I found an address in a dll data segment which was
    valid for
       us to use, and plugged it in. Now we're past the crash...
    
    Returning to the stack via Microsoftware...
    
       Normally, at this point, you could open up the main executable in
    IDA, turn
       on showing of op-codes, then do a string search for a " 54 " (the
    op-code
       for push esp). Ideally, what you're looking for is:
    
            push esp
            retn
    
       Of course this would not usually be done, but by seaching for " 54 ",
    you
       can almost always find something like:
    
            add esp, 54h
            retn
    
       Which is really the same thing! Just ignore the "add esp, " and
    voila.
    
       Again, this is made enormously difficult because of the 1/1024
       limitation... And in this case, dig as I might, I couldn't find
    anything
       at a valid address... The closest thing I could use were a few bits
       like this:
    
            push esp (actually an add esp, 54h)
            pop eax/ebx
            pop edi
            ...
            retn
    
       Now all this does is to get esp into eax. Doesnt seem like much until
    you
       realise thats it's relatively common to do a "call eax" or "call
    ebx".
       So, we go and find ourselves a "call eax/ebx" statement again with a
    valid
       (alphanumeric) address. We find a "call ebx" which we can use, so we
    go
       back and find a variant of the above code snippet which moves our esp
    into
       ebx.
    
       Positioning these two addresses at the correct position in the buffer
    can be
       tricky, but eventually we end up returning to what was originally our
    stack.
       The first stage of the attack is over, and were it not for the
    alphanumeric
       limitations, the battle would be over.
    
    
    Executing Text
    
       We have control of the eip... cheer, rest, think.
    
       What can we put in our buffer to execute? Not bloody much.
       Every byte in our buffer MUST be valid alphanumeric.
    
       I wouldn't have come this far without a plan, though. My idea is to
    use
       what small instruction set we DO have to dynamically CREATE a more
    flexible
       piece of code.
    
       Checking the instructions available to us in the character set we
    have, I
       find that we have all of the "push"es and most of the "pop"s.
       Along with, luckily, the "-" character, which turns into a "sub eax,
    ...",
       I came up with a plan... The initial code would PUSH the program onto
    the
       stack, then execute it from there. The first trick is to push bytes
    which
       cannot be in our buffer, I came up with the following:
    
          push xxxxxxxxh
          pop eax
          sub eax, xxxxxxxxh
          ...
          sub eax, xxxxxxxxh
          push eax
    
       Effectively, this means that for each DWORD of the target program, we
    need
       to calculate a series of valid DWORDs which subtract from one-another
    to
       produce the target DWORD... Sounds tough, but it turns out that a bit
    of
       brute force solves this one easily. I wrote a fairly simple program
    ()
       which calculated these numbers and produced code for me to cut and
    paste.
    
       After we've pushed this program onto the stack however, we need then
    to
       jump or call to it. Unfortunately our limited instruction set has
    only short
       jumps, which limits our range so much we'd have to chain them. The
    initial
       location of the stack pointer, and therefore the pushed program, is
    just
       above our current location ( where we are pushing the program ).
       So, instead of chaining short upwards jumps which would be hell to
    position
       and maintain, I inserted a series of "popad" instructions to move the
    stack
       pointer down, over and past the push code, allowing only enough room
    for
       the target program. The program is then pushed onto the stack and
    voila,
       no jump or call needed. We have created the program in front
       of our eip and we naturally execute into it. Tricky, but by leaving a
    bit
       of room at the end of the "push"ing routing filled with harmless "inc
    esi"
       instructions, it works fine.
    
       So, by using about 6-16 bytes per DWORD, we can create and run a
       program. At this rate, we would rapidly run out of room in our buffer
    to do
       anything. So, we add another trick. The program we produce is a small
       decompression routine. Using a simple nibble to byte compression
    routine to
       encrypt our main program and place it elsewhere in the buffer. This
    allows
       a 2 DWORD to 1 DWORD compression ratio, and a larger main program.
    
    
       The decompression routine is simple enough:
    
    
          ; assume edx points to source area
    
          mov esi, esp
          add esi, 122 ; source from esp...
          ; get length of code...
    
          xor ecx, ecx
          mov cx, word ptr [esi]
          add esi, 2
          sub cx, 6161h
          mov bx, cx
          shr cx, 4
          or cl, bl
    
          ; decode code...
          decode:
             mov eax, [esi]
             add esi, 4
             sub eax, 61616161h
             mov ebx, eax
             shr eax, 4
             or al, bl
             mov ebx, eax
             shr eax, 4
             mov al, bl
             ror eax, 0ch
             shr al, 4
             rol eax, 0ch
             push ax
    
             loop decode
    
          call esp
    
    
    Where Do We Want To Go Today?
    
       Game over, We can run ANY code we want at this point.
    
       I have included a full exploit program which simply create a file in
    the
       current called "md9.exe" containing the text string
          "SLMail contains a stack overflow",
       but it could just as easily be downloading a complete .exe using
    sockets,
       the inet32 api, or other means. This program could in turn re-start
    the
       SLMail service, remove any offensive log entries etc...
    
    
    Conclusion
    
       Seattle Lab have played down response to concerns over overflows in
       the VRFY argument of versions 2.5 and 2.6 of SLMail. They said that
    the
       security risk was minimal. Too hard to exploit, they said.
    
       As it turns out, the overflows in 2.5&6 are THE SIMPLEST POSSIBLE
    KIND.
       They are direct overflows with no major limitations on character set.
    
       So you can skip all the de-compression and pushing-of-programs, and
    locating
       valid addresses now means only avoiding 0's...
    
       I wrote this exploit in less than two days. Thats from the time I
    downloaded
       the evaluation copy of SLMail to the time I had arbitrary code
    executing on
       it. Now I'm not a bad guy, and I'm not paid to do this. Imagine what
    even
       governments around the world would be able to do with even a minimal
    "tiger
       team".
    
       The real message here is that this is not an isolated flaw. Buffer
    overflows
       of one kind or another are notoriously common even today on the more
    secure
       xnix platforms, and even more common on Windows Services written by
       programmers who do not realise or understand how serious these
    problems are.
    
       Recent posting to security sites reveal buffer overflows in COMMON
    products
       such as WS-FTP, SLMail, MDaemon, sendmail!!! and others.
    
       Any serious group of hackers would no doubt be yawning over my
    techniques
       here. They would have pre-fabricated routines to slot into place for
       various kinds of common overflows, allowing any server to be attacked
       potentially via any service it offers. Of course the entire DOMAIN of
    the
       attacked machine is subverted as well, so machines connected via LANs
    and
       even WAN/IP are also vulnerable, even if they don't run any
    vulnerable
       services.
    
       WAKE UP PLEASE!!!
    
       The US Congress is deliberating legislation which would make it
    illegal for
       the sites which distribute information like this illegal.
    
       The effect of this would be that the developers ( in this case
    Seattle Lab )
       would NOT EVEN KNOW the problem existed... Whilst ANY serious hacker
    would
       have found and exploited it months ago...
    
       As an example, it is not hard to write an overflow test program for a
    given
       protocol - be it SMTP, FTP, etc.
    
       Simply by running these test suites over each new server as it is
    released,
       the hackers identify vulnerabilities quickly and painlessly, then
    exploit.
    
       The large number of Server providers, and the LACK OF EDUCATION
    amongst
       the authors of these programs remains a huge security risk to
    business
       and privacy on the internet.
    
       The legislation assumes that what I am doing here is providing a
    "how-to"
       manual for would be "bedroom teen-superhackers" (script kiddies).
       Instead, what I am doing is SHOWING WHAT OTHERS ALREADY KNOW. No
    teenager
       from his bedroom will be able to use this technique to do any real
    damage.
       If he or she were to try, they would be logged and caught without too
    much
       trouble.
    
       The government teams and whoever else has a professional interest
    however,
       ALREADY KNOW IT.
    
       I hope Seattle Lab and others will read and understand, then STOP
    using
       the "It would be too hard to exploit" excuse.
    
    
    Jeremy Kothe (paceflowat_private)
    
    P.S. Seattle Lab has been informed... No response yet.
    
    
    ______________________________________________________
    Get Your Private, Free Email at http://www.hotmail.com
    



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