Microsoft Windows FastFAT. sys FAT partition Denial Of Service Vulnerability Reproduction
Do you still remember the MS14-063 FAT32 driver kernel Overflow Vulnerability last year? The sequent is coming out today, but this time it is in the FAT12 partition.
Analysis
-Affected Systems
From Windows NT to Windows 7 SP1
-Models I tested
* Windows XP SP3 x86
* Windows 7 SP1 x86/x64
BUG reproduction: Create a FAT12 partition and set a WORD in 0 × 16 (Sectors per FAT), for example, 0 × 3000
Note: The value cannot exceed 0x3FFF.
For more information about Loopback Device, we recommend that you set the parameter bs = 512 count = 32067.
The image can be empty.
Details: an error occurs in the value of the "Sectors per FAT" field in the FAT12 boot sector. As a result, the FAT1 partition attempts to read unallocated memory areas during the ing to the cache.
The error partition is shown as follows:
Crash
Windows 7 SP1 x86
kd> !analyze -v******************************************************************************** ** Bugcheck Analysis ** ******************************************************************************** PAGE_FAULT_IN_NONPAGED_AREA (50)Invalid system memory was referenced. This cannot be protected by try-except,it must be protected by a Probe. Typically the address is just plain bad or itis pointing at freed memory.Arguments:Arg1: a3f00000, memory referenced.Arg2: 00000000, value 0 = read operation, 1 = write operation.Arg3: 82a6a05e, If non-zero, the instruction address which referenced the bad memory address.Arg4: 00000000, (reserved) Debugging Details:------------------ READ_ADDRESS: a3f00000 FAULTING_IP:nt!CcMapData+ae82a6a05e 8a0e mov cl,byte ptr [esi] MM_INTERNAL_CODE: 0DEFAULT_BUCKET_ID: WIN7_DRIVER_FAULTBUGCHECK_STR: 0x50PROCESS_NAME: explorer.exeCURRENT_IRQL: 2 TRAP_FRAME: a2447414 -- (.trap 0xffffffffa2447414)ErrCode = 00000000eax=000006e2 ebx=86eb8b98 ecx=a2447400 edx=00000011 esi=a3f00000 edi=0000000feip=82a6a05e esp=a2447488 ebp=a24474c8 iopl=0 nv up ei pl nz ac po nccs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010212nt!CcMapData+0xae:82a6a05e 8a0e mov cl,byte ptr [esi] ds:0023:a3f00000=??Resetting default scope LAST_CONTROL_TRANSFER: from 82916d5f to 828b27b8 STACK_TEXT:a2446f64 82916d5f 00000003 6641e18b 00000065 nt!RtlpBreakWithStatusInstructiona2446fb4 8291785d 00000003 00000000 00082982 nt!KiBugCheckDebugBreak+0x1ca2447378 828c5879 00000050 a3f00000 00000000 nt!KeBugCheck2+0x68ba24473fc 82878aa8 00000000 a3f00000 00000000 nt!MmAccessFault+0x104a24473fc 82a6a05e 00000000 a3f00000 00000000 nt!KiTrap0E+0xdca24474c8 975dbb32 86e819c0 004474ec 00721e00 nt!CcMapData+0xaea24474f4 975d9e1d a2b52fb8 85dad920 00001000 fastfat!FatReadVolumeFile+0x3aa2447580 975da534 a2b52fb8 a2447524 00000002 fastfat!FatExamineFatEntries+0x11fa24475e8 975ecd64 a2b52fb8 85dad920 3519a638 fastfat!FatSetupAllocationSupport+0x38aa2447774 975ee3cf a2b52fb8 8a9b0da8 a3392fa8 fastfat!FatMountVolume+0x418a2447794 975ee478 a2b52fb8 93528e90 3519a6ac fastfat!FatCommonFileSystemControl+0x3fa24477e0 82b696c3 82275620 93528e90 93528e90 fastfat!FatFsdFileSystemControl+0x82a2447804 8286ebd5 00000001 93528ff4 82275620 nt!IovCallDriver+0x258a2447818 85499a56 270d61d5 8229bde8 93528e90 nt!IofCallDriver+0x1ba2447878 85499c5b 8229bde8 93528e90 86f2c678 fltmgr!FltpFsControlMountVolume+0x180a24478a8 82b696c3 8229bde8 93528e90 93528e90 fltmgr!FltpFsControl+0x5ba24478cc 8286ebd5 00000001 8296fb88 8229bde8 nt!IovCallDriver+0x258a24478e0 829d1dd9 82804870 8a9b0da8 82804900 nt!IofCallDriver+0x1ba2447944 828df92e 8a9b0da8 85dac000 00000000 nt!IopMountVolume+0x1d8a244797c 82a7ddfb 85dac008 a2447aa8 a2447a40 nt!IopCheckVpbMounted+0x64a2447a60 82a5dd1e 8a9b0da8 851cfde8 85d66750 nt!IopParseDevice+0x7dba2447adc 82a6e147 00000000 a2447b30 00000040 nt!ObpLookupObjectName+0x4faa2447b38 82a64c25 02effc44 851cfde8 828b1d01 nt!ObOpenObjectByName+0x165a2447bb4 82a884a4 02effca0 00100081 02effc44 nt!IopCreateFile+0x673a2447c00 828758c6 02effca0 00100081 02effc44 nt!NtCreateFile+0x34a2447c00 776170f4 02effca0 00100081 02effc44 nt!KiSystemServicePostCall02effc00 77615614 7573a9d9 02effca0 00100081 ntdll!KiFastSystemCallRet02effc04 7573a9d9 02effca0 00100081 02effc44 ntdll!ZwCreateFile+0xc02effca8 772ce99f 00004000 00100081 00000007 KERNELBASE!CreateFileW+0x35e02effcd4 761a2fc5 03cc0038 00000001 00000007 kernel32!CreateFileWImplementation+0x6902effd38 761a2bc9 03cc0038 00000001 00000000 SHELL32!CLocalInterruptSource::v_CreateEvent+0x4102effd5c 761aac0f 0368f598 00000000 02effd94 SHELL32!CFSInterruptSource::GetEvent+0x7b02effd9c 761aa92a 02effdc0 00000000 006e7a90 SHELL32!CChangeNotify::_GetInterruptEvents+0x9302effdc8 7611561b 00000000 00000000 00000067 SHELL32!CChangeNotify::_MessagePump+0x6702effde0 75fd43c0 006e7a90 00000000 00000000 SHELL32!CChangeNotify::s_ThreadProc+0x4f02effe68 772cee1c 0201ed74 02effeb4 776337eb SHLWAPI!WrapperThreadProc+0x1b502effe74 776337eb 0201ed74 758640f9 00000000 kernel32!BaseThreadInitThunk+0xe02effeb4 776337be 75fd42ed 0201ed74 00000000 ntdll!__RtlUserThreadStart+0x7002effecc 00000000 75fd42ed 0201ed74 00000000 ntdll!_RtlUserThreadStart+0x1b STACK_COMMAND: kb FOLLOWUP_IP:nt!CcMapData+ae82a6a05e 8a0e mov cl,byte ptr [esi] SYMBOL_STACK_INDEX: 5SYMBOL_NAME: nt!CcMapData+aeFOLLOWUP_NAME: MachineOwnerMODULE_NAME: ntIMAGE_NAME: ntkrpamp.exeDEBUG_FLR_IMAGE_TIMESTAMP: 521e9cb6FAILURE_BUCKET_ID: 0x50_VRF_nt!CcMapData+aeBUCKET_ID: 0x50_VRF_nt!CcMapData+aeFollowup: MachineOwner---------
Vulnerability code:
\ Wrk-v1.2 \ base \ ntos \ cache \ pinsup. c
Line 72:BOOLEANCcMapData ( __in PFILE_OBJECT FileObject, __in PLARGE_INTEGER FileOffset, __in ULONG Length, __in ULONG Flags, __out PVOID *Bcb, __deref_out_bcount(Length) PVOID *Buffer )... Line 155: ULONG PageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES((ULongToPtr(FileOffset->LowPart)), Length); PETHREAD Thread = PsGetCurrentThread(); BOOLEAN ReturnStatus; DebugTrace(+1, me, "CcMapData\n", 0 ); MmSavePageFaultReadAhead( Thread, &SavedState ); ReturnStatus = CcMapDataCommon( FileObject, FileOffset, Length, Flags, &TempBcb, Buffer );...Line 193 // // Loop to touch each page // BaseAddress = *Buffer; while (PageCount != 0) { MmSetPageFaultReadAhead( Thread, PageCount - 1 ); ch = *((volatile UCHAR *)(BaseAddress)); // BaseAddress = (PCHAR) BaseAddress + PAGE_SIZE; PageCount -= 1; }
PageCount is calculated based on the control length value. In this case, (read FATx) includes:
Sectors per FAT * Bytes per sector
kd> . frame /c 5kd> dd ebp+10 L1 //get Length valuef53e1510 00721e00kd> ?00721e00 / 0x200(= Bytes per sector)Evaluate expression: 14607 = 0000390f (= Sectors per FAT)
FileOffset is equal:
kd> dt _LARGE_INTEGER poi(ebp+c)nt!_LARGE_INTEGER 0x200 +0x000 LowPart : 0x200 +0x004 HighPart : 0 +0x000 u : __unnamed +0x000 QuadPart : 512
The following values are calculated by calling PageCount:
Evaluate expression: 1826 = 00000722
While iteration loop, add the BaseAddress pointer through PAGE_SIZE. In this case, the memory area will be overwritten ":
kd> ?(0x722 * 0x1000) / 0x400------------^-----------^----------^----PageCount PAGE_SIZE 1KB Evaluate expression: 7304 = 00001c88kd> ?00001c88 / 0x400Evaluate expression: 7 = 00000007 ~ 7MB
Next, we will check how many bytes can be cached:
\ Wrk-v1.2 \ base \ ntos \ cache \ pinsup. c
Line 241:BOOLEANCcMapDataCommon ( IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN ULONG Flags, OUT PVOID *Bcb, OUT PVOID *Buffer ) ...Line 350: // // Get pointer to SharedCacheMap. // SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; // // Call local routine to Map or Access the file data. If we cannot map // the data because of a Wait condition, return FALSE. // if (FlagOn(Flags, MAP_WAIT)) { *Buffer = CcGetVirtualAddress( SharedCacheMap, *FileOffset, (PVACB *)&TempBcb, &ReceivedLength ); ASSERT( ReceivedLength >= Length ); // maybe convert it to IF ? }
Check cancelength in CcGetVirtualAddress:
\ Wrk-v1.2 \ base \ ntos \ cache \ vacbsup. c
Line 388:ULONG VacbOffset = FileOffset.LowPart & (VACB_MAPPING_GRANULARITY - 1);...Line 449:*ReceivedLength = VACB_MAPPING_GRANULARITY - VacbOffset;
What is the value of VACB_MAPPING_GRANULARITY?
\ Wrk-v1.2 \ base \ ntos \ inc \ cache. h
Line 31:
# Define VACB_MAPPING_GRANULARITY (0x40000)
From the code snippet above, we know that the length of elength is greater than or equal to 0 × 40000 bytes, that is, kb.
MSDN CcMapData
Microsoft official CcMapData documentation
In the cache manager, CcMapData cannot map data through the view boundary. The standard file size in the system cache manager is 256 KB (The View Size of the cache manager is specified by the system defined constant VACB_MAPPING_GRANULARITY, its size is in ntifs. h is set to 256 KB), The ing area cannot exceed 256 KB. Therefore, the maximum ing area is 256 KB, starting from 256 KB in the file.
The code and documentation clearly state that the data in the ing file cannot exceed 256 KB. In our example, the kernel is larger than 7 MB of available space, and the iteration exceeding 256 KB will cause a crash.
Why is this BUG?
If the length value is missing verification, this iteration will be infinite.
\ Wrk-v1.2 \ base \ ntos \ cache \ pinsup. c
Line 198 while (PageCount != 0) { MmSetPageFaultReadAhead( Thread, PageCount - 1 ); ch = *((volatile UCHAR *)(BaseAddress)); //
The available ing/allocation area is exceeded.
Not every time
In the experiment, I found that not every Sectors per FAT value will exceed 0 × 0200, leading to a crash. For example, setting Sectors per FAT to 0 × 4000 is an exception! FatCommonRead:
Stack trace: Sectors per FAT = 40 00
Windows XP SP3ChildEBP RetAddr Args to Child bad46fc0 b7e0d505 86a69e50 bad46fec 804e24f1 Fastfat!FatExceptionFilter+0x5bad46fcc 804e24f1 bad46ff4 00000000 bad46ff4 Fastfat!FatFsdRead+0x12bbad46ff4 804db49a bad470d8 bad47518 bad47128 nt!_except_handler3+0x61bad47018 804db46b bad470d8 bad47518 bad47128 nt!ExecuteHandler2+0x26bad470c8 804dc6a1 bad470d8 bad47128 c000000d nt!ExecuteHandler+0x24bad473fc b7e12fc4 c000000d 86a69e50 8667b888 nt!ExRaiseStatus+0xb5bad474b8 b7e0d69a 86a69e50 8667b888 86a501e8 Fastfat!FatCommonRead+0x66bbad47528 804e37f7 8686ba98 8667b888 00000000 Fastfat!FatFsdRead+0x13dbad47538 804f95d8 00000000 86b01ad0 86b01ae0 nt!IopfCallDriver+0x31bad4754c 804f95ff 8686ba98 86b01b08 86b01ae8 nt!IopPageReadInternal+0xf4bad4756c 804f9264 86a501e8 86b01b08 86b01ae8 nt!IoPageRead+0x1bbad475e0 804eba6a 0dead8c0 c7fc0000 c031ff00 nt!MiDispatchFault+0x274bad47630 804e1718 00000000 c7fc0000 00000000 nt!MmAccessFault+0x5bcbad47630 8056d716 00000000 c7fc0000 00000000 nt!KiTrap0E+0xccbad47708 b7e15b25 86a501e8 bad47734 00001000 nt!CcMapData+0xefbad4773c b7e1e8b6 86a84e28 8698b3a8 00000000 Fastfat!FatReadDirectoryFile+0x92bad47770 b7e137b7 86a84e28 8686bb90 bad47880 Fastfat!FatLocateVolumeLabel+0x7fbad4790c b7e10a93 86a84e28 86b6a718 86bd3af0 Fastfat!FatMountVolume+0x49bbad4792c b7e10a38 86a84e28 8690eaf0 8690ec78 Fastfat!FatCommonFileSystemControl+0x49bad47978 804e37f7 86a2d928 8690eaf0 8690ec9c Fastfat!FatFsdFileSystemControl+0x85 EXCEPTION:Fastfat!FatExceptionFilter+0x5:b7e0d485 53 push ebxkd> .exr poi(poi(ebp+c))ExceptionAddress: b7e12fc4 (Fastfat!FatCommonRead+0x0000066b) ExceptionCode: c000000d // STATUS_INVALID_PARAMETER ExceptionFlags: 00000001NumberParameters: 0
I did not go into depth, and of course I could not point out the exception in the code. So I guess there may already be a length verification, but the accuracy is not enough!