Talos Vulnerability Report

VRT-2014-0301

Microsoft Windows FastFAT NumberOfFATs Buffer Overflow Vulnerability

Mar 7, 2014

Description

An exploitable local privileged code execution vulnerability exists in the Microsoft Windows FastFAT system driver. The FastFAT system driver is responsible for handling FAT32 disk partitions. An attacker who can control the NumberOfFATs value of a FAT32 boot sector can cause an undersized allocation which can later be used to write controlled data into the kernel pool.

Tested Versions

Windows XP SP3 Vulnerable Windows 7 Not Vulnerable Windows 8 Not Vulnerable

Product URLS

http://windows.microsoft.com/

Details

The FatCommonWrite function in FastFAT.sys is responsible for parsing the FAT32 boot sector. The boot sector contains a BIOS Parameter Block which is represented in the partial BPB_FAT32 structure below:

Member                                "Value (dec)" "Value (hex)"   Size
        "00000000 struct BOOTSECTOR_FAT32"  {...}                           00000200
        "  00000000 int8 jmp[00000003]"                                     00000003
        "  00000003 char OemName[00000008]"     MSDOS5.0                    00000008
        "  0000000B struct BPB_FAT32"   {...}                               00000035
        "   0000000B uint16 BytesPerSector"     512           0200          00000002
        "   0000000D int8 SectorsPerCluster"    1             01            00000001
        "   0000000E uint16 ReservedSectors"    36            0024          00000002
        "   00000010 int8 NumberOfFATs"         1             01            00000001
        -- snip --
        

The below pseudo code is responsible for parsing part of the BIOS Parameter Block. The first clause shows that the NumberOfFATs value, if greater than ‘2’, is used as the size of a kernel pool allocation:

 1   NumberOfFATs = *(_BYTE *)(VCB + 150);
         2   if ( NumberOfFATs <= 2u )
         3   {
         4      ptrPool = &v100;
         5   }
         6   else
         7   {
         8      ptrPool = ExAllocatePoolWithTag((POOL_TYPE)17, NumberOfFATs, ''itaF'');
         9      v14 = VCB;
        10   }
        

As we continue, the function also performs a loop using the NumberOfFATs value as the iteration count:

11   counter = 0;
        12   if ( *(_BYTE *)(v14 + 0x96) )
        13   {
        14      v18 = offsetToFirstFAT;
        15      unknow1 = offsetToFirstFAT - unknow2;
        16      v20 = (int)((char *)ptrPool + 12);
        17      do
        18      {
        19         *(_DWORD *)(v20 - 4) = offsetToFirstFAT;
        20         *(_DWORD *)(v20 - 12) = v18;
        21         *(_DWORD *)(v20 - 8) = 0;
        22         *(_DWORD *)v20 = unknow1;
        23         *(_DWORD *)(v20 + 4) = unknow3;
        24         ++counter;
        25         v18 += BytesPerFat;
        26         v20 += 24;
        27      }
        28      while ( counter < NumberOfFATs );
        29   }
        

Within the loop, the code expects there to be an array of 24-byte structures in the allocated buffer for each FAT indicated by the NumberOfFATs field. Since the allocation size was not multiplied by the size of the structure, memory will be written outside the bounds of the buffer.

Crash Information

eax=8a01100c ebx=8a7ece90 ecx=00186c00 edx=00000800 esi=89a14b18 edi=00004800
        eip=b7ae63da esp=bacdf934 ebp=bacdfab4 iopl=0         nv up ei ng nz ac pe cy
        cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000            efl=00010297
        Fastfat!FatCommonWrite+0x444:
        b7ae63da 8978fc         mov     dword ptr [eax-4],edi ds:0023:8a011008=????????

        STACK_TEXT:
        bacdf848 8051cc4f 00000050 8a011008 00000001 nt!KeBugCheckEx+0x1b
        bacdf8a8 8054051c 00000001 8a011008 00000000 nt!MmAccessFault+0x8e7
        bacdf8a8 b7ae63da 00000001 8a011008 00000000 nt!KiTrap0E+0xcc
        bacdfab4 b7adab9a 89a14b18 8a7ece90 89c59020 Fastfat!FatCommonWrite+0x444
        bacdfaf8 804ee119 89c59020 8a7ece90 806d12a4 Fastfat!FatFsdWrite+0xad
        bacdfb08 8064d628 89ada170 00004000 89c59020 nt!IopfCallDriver+0x31
        bacdfb2c 804ef411 bacdfb68 bacdfd40 00000000 nt!IovCallDriver+0xa0
        bacdfb40 8050c497 89ada107 bacdfb68 bacdfbfc nt!IoSynchronousPageWrite+0xaf
        bacdfc24 8050ce3d e10ec820 e10ec828 e10ec828 nt!MiFlushSectionInternal+0x3bf
        bacdfc60 804e38a2 89c33d70 e10ec820 00000004 nt!MmFlushSection+0x1b5
        bacdfce8 804e3bc4 00001000 00000000 00000001 nt!CcFlushCache+0x386
        bacdfd2c 804e61ee 89da0290 8055b0c0 89da1da8 nt!CcWriteBehind+0xdc
        bacdfd74 80534c02 89da0290 00000000 89da1da8 nt!CcWorkerThread+0x126
        bacdfdac 805c6160 89da0290 00000000 00000000 nt!ExpWorkerThread+0x100
        bacdfddc 80541dd2 80534b02 00000000 00000000 nt!PspSystemThreadStartup+0x34
        00000000 00000000 00000000 00000000 00000000 nt!KiThreadStartup+0x16
        

Credit

Discovered by Marcin ‘Icewall’ Noga of Sourcefire VRT