Date: Thu, 9 Jul 1998 11:54:17 -0500
From: Aleph One <[email protected]>
To: [email protected]Subject: SLMail 3.0.2421 Stack Overflow...
---------- Forwarded message ----------
Date: Wed, 8 Jul 1998 17:32:02 PDT
From: Ezekial Morrow <[email protected]>
To: [email protected]Subject: SLMail 3.0.2421 Stack Overflow...
Product: SLMail 3.0.2421 from Seattle Lab.
Vulnerability: Stack overflow - Remote execution of code.
Jeremy Kothe ([email protected])
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 ([email protected])
P.S. Seattle Lab has been informed... No response yet.
______________________________________________________
Get Your Private, Free Email at http://www.hotmail.com