New issue
Advanced search Search tips
Starred by 1 user

Issue metadata

Status: Duplicate
Merged: issue 1644
Owner:
Closed: Nov 17
Cc:

Blocking:
issue 1644



Sign in to add a comment
link

Issue 1646: Windows: DfMarshal Shared Allocator Elevation of Privilege

Reported by forshaw@google.com, Aug 24 Project Member

Issue description

Windows: DfMarshal Shared Allocator Elevation of Privilege
Platform: Windows 10 1803 (not tested earlier, although code looks similar on Win8+)
Class: Elevation of Privilege

Note, this is a report on a single issue class in the DfMarshal unmarshaler. For background see the master issue.

Summary: The unmarshaler for Storage objects stores C++ objects in the shared allocation region allowing control of VTable pointers or allocated objects leading to EoP.

Description:

The storage implementation uses the shared memory region as an allocation region through a custom allocator. While most of the pointers stored in this region are relative (although as demonstrated in an another issue, not bounds checked) the code uses the allocator to also allocate memory for C++ objects which including VTables. Looking at the function names it seems likely that someone has implemented the custom allocator with support for new/delete and so doesn’t necessarily realize they’re allocating such data into shared memory.

Most of the time the implementation probably doesn’t notice because any absolute pointers are into the coml2 or combase DLLs which will be loaded to the same address in different processes. However, because the memory is shared between processes the malicious process can change things like VTable pointers to arbitrary addresses resulting in gaining control of execution. 

While you could modify objects after creation there’s also cases where existing objects are considered to be in process already. An example of this is any object allocated through a CContextList. A context list is a linked list of allocated objects (using relative pointers) which are keyed by the PID of the creator. This allows the implementation to find objects allocated inside the process so that it can use them directly. An example of a vulnerable function is CFileStream::Unmarshal which is called during the unmarshal process. The vulnerable code looks like the following:

HRESULT CFileStream::Unmarshal(CGlobalFileStream *pgfst, <-- This is in shared memory.
                                                       void **ppv, 
                                                       unsigned int mshlflags) {
  CContext *ctxp = ctxp = pgfst->_pctxHead.Find(GetCurrentProcessId());
  CFileStream *fstm = CONTAINING_STRUCT(CFileStream, ctxp); <-- Get context pointer.
  if (ctxp)
    fstm = NULL;
  if (fstm) {
    fstm->AddRef(); <-- Calls via VTable in shared memory.
  }
  ...
}

This code gets a pointer to the CGlobalFileStream object (which is in shared memory) then tries to look up an existing CFileStream object in the global context list. This is keyed by the PID, so an attacker can just modify an existing allocation context ID to the PID of the target process the unmarshal is running in. This results in getting a reference to a CFileStream object which implements a number of COM interfaces, which require VTables. A call is made to AddRef which can be hijacked by the malicious attacker just by modifying shared memory.

Of course this isn’t the only issue here, the instances are too numerous to list. An attacker can obviously modify the data inside the allocated objects at will. Basically hiding the allocation through a new overload looks to be a bad idea as it makes developers think they can allocate anything they like.

Fixing wise, stop allocating C++ objects in the shared memory region at an absolute minimum.

Proof of Concept:


I’ve provided a PoC as a C# project, I’ve provided one solution for all issues, but separate projects for each bug. This PoC uses the Audio Server to create a shared section and sends the marshaled object to the BITS service. This abuses the CFileStream::Unmarshal issue I highlighted above. It’s the simplest one to demonstrate the general class of issue.

Note I’ve only tested this on Windows 10 1803. While I expect the underlying bugs exist on other versions offsets/behaviors I’m relying on might differ. Also note that once the BITS service crashes the DCOM activator might not realize for a while and so starting COM object will take a long time. You can get around this by manually starting the BITS service if it doesn’t auto-start. A final note, as this uses the Audio Server it might not work on VMs with the sound card disabled.

1) Compile the C# project. It will need to grab NtApiDotNet from NuGet to work.
2) Run the PoC HijackVTable as a normal user.
3) When requested attach a debugger to the BITS service process to see the crash.
4) Hit enter in the PoC.

Expected Result:
The marshal fails, or the code falls back to using standard marshaled object.

Observed Result:
The BITS service crashes dereferencing an invalid address.

This bug is subject to a 90 day disclosure deadline. After 90 days elapse or a patch has been made broadly available (whichever is earlier), the bug report will become visible to the public.

Example Crash Report:

(3154.3164): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
coml2!CFileStream::Unmarshal+0x72:
00007ff9`40b6c166 488b4008        mov     rax,qword ptr [rax+8] ds:00000000`00001250=????????????????
0:003> !analyze -v
*******************************************************************************
*                                                                             *
*                        Exception Analysis                                   *
*                                                                             *
*******************************************************************************

GetUrlPageData2 (WinHttp) failed: 12002.

KEY_VALUES_STRING: 1


TIMELINE_ANALYSIS: 1

Timeline: !analyze.Start
    Name: <blank>
    Time: 2018-08-24T21:05:34.534Z
    Diff: 534 mSec

Timeline: Dump.Current
    Name: <blank>
    Time: 2018-08-24T21:05:34.0Z
    Diff: 0 mSec

Timeline: Process.Start
    Name: <blank>
    Time: 2018-08-24T21:05:09.0Z
    Diff: 25000 mSec

Timeline: OS.Boot
    Name: <blank>
    Time: 2018-08-24T20:15:56.0Z
    Diff: 2978000 mSec


DUMP_CLASS: 2

DUMP_QUALIFIER: 0

FAULTING_IP: 
coml2!CFileStream::Unmarshal+72
00007ff9`40b6c166 488b4008        mov     rax,qword ptr [rax+8]

EXCEPTION_RECORD:  (.exr -1)
ExceptionAddress: 00007ff940b6c166 (coml2!CFileStream::Unmarshal+0x0000000000000072)
   ExceptionCode: c0000005 (Access violation)
  ExceptionFlags: 00000000
NumberParameters: 2
   Parameter[0]: 0000000000000000
   Parameter[1]: 0000000000001250
Attempt to read from address 0000000000001250

FAULTING_THREAD:  00003164

PROCESS_NAME:  svchost.exe

FOLLOWUP_IP: 
coml2!CFileStream::Unmarshal+72
00007ff9`40b6c166 488b4008        mov     rax,qword ptr [rax+8]

READ_ADDRESS:  0000000000001250 

ERROR_CODE: (NTSTATUS) 0xc0000005 - The instruction at 0x%p referenced memory at 0x%p. The memory could not be %s.

EXCEPTION_CODE: (NTSTATUS) 0xc0000005 - The instruction at 0x%p referenced memory at 0x%p. The memory could not be %s.

EXCEPTION_CODE_STR:  c0000005

EXCEPTION_PARAMETER1:  0000000000000000

EXCEPTION_PARAMETER2:  0000000000001250

WATSON_BKT_PROCSTAMP:  a38b9ab2

WATSON_BKT_PROCVER:  10.0.17134.1

PROCESS_VER_PRODUCT:  Microsoft® Windows® Operating System

WATSON_BKT_MODULE:  coml2.dll

WATSON_BKT_MODSTAMP:  53d8837d

WATSON_BKT_MODOFFSET:  3c166

WATSON_BKT_MODVER:  10.0.17134.1

MODULE_VER_PRODUCT:  Microsoft® Windows® Operating System

BUILD_VERSION_STRING:  17134.1.amd64fre.rs4_release.180410-1804

MODLIST_WITH_TSCHKSUM_HASH:  870ea246ea374ed5f27b074bfdab4fc2906c2a26

MODLIST_SHA1_HASH:  7ffa7cdbce9c0ca31cb239756da59b79a72bb592

NTGLOBALFLAG:  0

PROCESS_BAM_CURRENT_THROTTLED: 0

PROCESS_BAM_PREVIOUS_THROTTLED: 0

APPLICATION_VERIFIER_FLAGS:  0

PRODUCT_TYPE:  1

SUITE_MASK:  272

DUMP_TYPE:  fe

GROUP:  netsvcs

FAULTING_SERVICE_NAME:  BITS

ANALYSIS_SESSION_HOST:  ONYX

ANALYSIS_SESSION_TIME:  08-24-2018 22:05:34.0534

ANALYSIS_VERSION: 10.0.17134.1 amd64fre

THREAD_ATTRIBUTES: 
OS_LOCALE:  ENU

PROBLEM_CLASSES: 

    ID:     [0n309]
    Type:   [@ACCESS_VIOLATION]
    Class:  Addendum
    Scope:  BUCKET_ID
    Name:   Omit
    Data:   Omit
    PID:    [Unspecified]
    TID:    [0x3164]
    Frame:  [0] : coml2!CFileStream::Unmarshal

    ID:     [0n281]
    Type:   [INVALID_POINTER_READ]
    Class:  Primary
    Scope:  DEFAULT_BUCKET_ID (Failure Bucket ID prefix)
            BUCKET_ID
    Name:   Add
    Data:   Omit
    PID:    [Unspecified]
    TID:    [0x3164]
    Frame:  [0] : coml2!CFileStream::Unmarshal

    ID:     [0n353]
    Type:   [SVCHOSTGROUP]
    Class:  Mandatory
    Scope:  DEFAULT_BUCKET_ID (Failure Bucket ID prefix)
            BUCKET_ID
    Name:   Add
    Data:   Add
            String: [netsvcs]
    PID:    [0x3154]
    TID:    [0x3164]
    Frame:  [Unspecified]

BUGCHECK_STR:  SVCHOSTGROUP_netsvcs_APPLICATION_FAULT_INVALID_POINTER_READ

DEFAULT_BUCKET_ID:  SVCHOSTGROUP_netsvcs_INVALID_POINTER_READ

PRIMARY_PROBLEM_CLASS:  SVCHOSTGROUP_netsvcs_APPLICATION_FAULT

LAST_CONTROL_TRANSFER:  from 00007ff940b6d508 to 00007ff940b6c166

STACK_TEXT:  
0000001d`d7d7cfd0 00007ff9`40b6d508 : 000001e0`396e02e0 0000001d`d7d7d068 00000000`00000000 00000000`00000000 : coml2!CFileStream::Unmarshal+0x72
0000001d`d7d7d000 00007ff9`40b6ba9f : 00000000`00000000 0000001d`d7d7d0e0 0000001d`00000000 0000001d`00000001 : coml2!UnmarshalContext+0x1c0
0000001d`d7d7d0b0 00007ff9`40b6da50 : 00000000`00000000 0000001d`d7d7d2c0 00000000`00000000 0000001d`d7d7d720 : coml2!CExposedDocFile::Unmarshal+0x25f
0000001d`d7d7d250 00007ff9`4196509b : 000001e0`310a2dc0 00000000`00000001 0000001d`d7d7d3f0 000001e0`310a2dc0 : coml2!DfUnMarshalInterface+0x198
0000001d`d7d7d2f0 00007ff9`41ab7527 : 00000000`00000000 00000000`00000000 0000001d`d7d7d828 000001e0`2fa6c0e8 : combase!_CoUnmarshalInterface+0x4ab
0000001d`d7d7d640 00007ff9`41a4e5b9 : 00000000`00000000 0000001d`d7d7d828 00400000`00000100 00007ff9`41a4e454 : combase!CObjServer::GetPersistentInstance+0x247
0000001d`d7d7d7b0 00007ff9`412146f3 : 00000000`00000004 0000001d`d7d7de90 00007ff9`41989a60 000001e0`310edd60 : combase!CObjServer::CreateInstance+0xc4b59
0000001d`d7d7d990 00007ff9`411c2829 : 00007ff9`41b86612 000001e0`310e8670 0000001d`d7d7de70 00000000`00000004 : RPCRT4!Invoke+0x73
0000001d`d7d7d9f0 00007ff9`411c5553 : 000001e0`2f8718c0 00000000`02cd0001 00000000`0000002b 00000000`00000001 : RPCRT4!NdrStubCall2+0x9e9
0000001d`d7d7e0c0 00007ff9`419b3942 : 00000000`00000000 0000001d`d7d7e2c0 00007ff9`41b438d0 000001e0`2fafcef0 : RPCRT4!NdrStubCall3+0xe3
0000001d`d7d7e120 00007ff9`4194e80b : 00000000`00000001 000001e0`2fa56878 00007390`5f1b1bed 0000001d`d7d7e1b8 : combase!CStdStubBuffer_Invoke+0x62
0000001d`d7d7e160 00007ff9`4194e485 : 00000000`00000016 0000001d`d7d7e260 0000001d`d7d7e210 00007390`5f1b1a1d : combase!ObjectMethodExceptionHandlingAction<<lambda_76d9e92c799d246a4afbe64a2bf5673d> >+0x4b
0000001d`d7d7e1c0 00007ff9`4194ef06 : 00000000`00000000 00000001`00000000 000001e0`2fafcef0 000001e0`31097820 : combase!DefaultStubInvoke+0x295
0000001d`d7d7e340 00007ff9`4194aae8 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : combase!ServerCall::ContextInvoke+0x496
0000001d`d7d7e770 00007ff9`41949fcc : 000001e0`310a2dc0 000001e0`2fa56be0 000001e0`2fafcef0 000001e0`2fafd5a0 : combase!AppInvoke+0x328
0000001d`d7d7e880 00007ff9`41942f00 : 00007ff9`41b17500 000001e0`2fa567f0 000001e0`310a2dc0 000001e0`2fa567f0 : combase!ComInvokeWithLockAndIPID+0x59c
0000001d`d7d7eb10 00007ff9`411af914 : 00007390`5f1b09bd 00000000`00000000 000001e0`2fa1d6a0 00007ff9`41b234c0 : combase!ThreadInvoke+0x1320
0000001d`d7d7f470 00007ff9`411aea78 : 0000001d`d7d7f6c8 000001e0`2fa49be8 0000001d`d7d7f690 0000001d`d7d7f6c8 : RPCRT4!DispatchToStubInCNoAvrf+0x24
0000001d`d7d7f4c0 00007ff9`411af554 : 000001e0`2fa1d754 00000000`00000000 00000000`00000000 00000000`00000000 : RPCRT4!RPC_INTERFACE::DispatchToStubWorker+0x1d8
0000001d`d7d7f590 00007ff9`411b834d : 00000000`00000000 000001e0`2f870070 00000000`00000000 000001e0`2fa4bce0 : RPCRT4!RPC_INTERFACE::DispatchToStubWithObject+0x154
0000001d`d7d7f630 00007ff9`411b8f0c : 00000000`0004f055 00000000`00000002 0000001d`d7d7f7d9 000001e0`310ed2a0 : RPCRT4!LRPC_SCALL::DispatchRequest+0x18d
0000001d`d7d7f710 00007ff9`411b4d6d : 000001e0`2fa02340 000001e0`2fa4bce0 00000000`00000000 000001e0`39510000 : RPCRT4!LRPC_SCALL::HandleRequest+0x86c
0000001d`d7d7f830 00007ff9`411b646d : 00000000`00000000 000001e0`2fa3a350 00000000`00000001 0000001d`d7d7f9d0 : RPCRT4!LRPC_ADDRESS::HandleRequest+0x33d
0000001d`d7d7f8d0 00007ff9`411d9318 : 000001e0`310ae440 0000001d`d7d7fc98 00007ff9`41293c14 00000000`00000000 : RPCRT4!LRPC_ADDRESS::ProcessIO+0x8ad
0000001d`d7d7fa10 00007ff9`41f50c8e : 0000001d`d7d7fab0 00000000`00000000 0000001d`d7d7fc98 000001e0`2fa3a530 : RPCRT4!LrpcIoComplete+0xd8
0000001d`d7d7fab0 00007ff9`41f4f578 : 00000000`00000000 000001e0`2fa0d900 00000000`00000000 00000000`00000000 : ntdll!TppAlpcpExecuteCallback+0x22e
0000001d`d7d7fb30 00007ff9`40c03034 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!TppWorkerThread+0x258
0000001d`d7d7fe20 00007ff9`41fa1431 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : KERNEL32!BaseThreadInitThunk+0x14
0000001d`d7d7fe50 00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlUserThreadStart+0x21


STACK_COMMAND:  ~3s ; .cxr ; kb

THREAD_SHA1_HASH_MOD_FUNC:  1fe291dbc7e7174f9c4c6015b1752e6fa0af6e69

THREAD_SHA1_HASH_MOD_FUNC_OFFSET:  27d4a144c2c9ff8b083c1cab62d6563d1a7c4484

THREAD_SHA1_HASH_MOD:  725a180e03cdaea58f8d1fabb10829fd3b852f64

FAULT_INSTR_CODE:  8408b48

SYMBOL_STACK_INDEX:  0

SYMBOL_NAME:  coml2!CFileStream::Unmarshal+72

FOLLOWUP_NAME:  MachineOwner

MODULE_NAME: coml2

IMAGE_NAME:  coml2.dll

DEBUG_FLR_IMAGE_TIMESTAMP:  53d8837d

FAILURE_BUCKET_ID:  SVCHOSTGROUP_netsvcs_INVALID_POINTER_READ_c0000005_coml2.dll!CFileStream::Unmarshal

BUCKET_ID:  SVCHOSTGROUP_netsvcs_APPLICATION_FAULT_INVALID_POINTER_READ_coml2!CFileStream::Unmarshal+72

FAILURE_EXCEPTION_CODE:  c0000005

FAILURE_IMAGE_NAME:  coml2.dll

BUCKET_ID_IMAGE_STR:  coml2.dll

FAILURE_MODULE_NAME:  coml2

BUCKET_ID_MODULE_STR:  coml2

FAILURE_FUNCTION_NAME:  CFileStream::Unmarshal

BUCKET_ID_FUNCTION_STR:  CFileStream::Unmarshal

BUCKET_ID_OFFSET:  72

BUCKET_ID_MODTIMEDATESTAMP:  53d8837d

BUCKET_ID_MODCHECKSUM:  7b14e

BUCKET_ID_MODVER_STR:  10.0.17134.1

BUCKET_ID_PREFIX_STR:  SVCHOSTGROUP_netsvcs_APPLICATION_FAULT_INVALID_POINTER_READ_

FAILURE_PROBLEM_CLASS:  SVCHOSTGROUP_netsvcs_APPLICATION_FAULT

FAILURE_SYMBOL_NAME:  coml2.dll!CFileStream::Unmarshal

WATSON_STAGEONE_URL:  http://watson.microsoft.com/StageOne/svchost.exe/10.0.17134.1/a38b9ab2/coml2.dll/10.0.17134.1/53d8837d/c0000005/0003c166.htm?Retriage=1

TARGET_TIME:  2018-08-24T21:05:36.000Z

OSBUILD:  17134

OSSERVICEPACK:  1

SERVICEPACK_NUMBER: 0

OS_REVISION: 0

OSPLATFORM_TYPE:  x64

OSNAME:  Windows 10

OSEDITION:  Windows 10 WinNt SingleUserTS

USER_LCID:  0

OSBUILD_TIMESTAMP:  2020-08-28 05:38:41

BUILDDATESTAMP_STR:  180410-1804

BUILDLAB_STR:  rs4_release

BUILDOSVER_STR:  10.0.17134.1.amd64fre.rs4_release.180410-1804

ANALYSIS_SESSION_ELAPSED_TIME:  599e

ANALYSIS_SOURCE:  UM

FAILURE_ID_HASH_STRING:  um:svchostgroup_netsvcs_invalid_pointer_read_c0000005_coml2.dll!cfilestream::unmarshal

FAILURE_ID_HASH:  {4f91a963-e728-07ef-d292-c699bb9d0878}

Followup:     MachineOwner
--------
 

Comment 1 by forshaw@google.com, Aug 24

Project Member
Blocking: 1644

Comment 2 by forshaw@google.com, Aug 29

Project Member
Labels: MSRC-47438

Comment 3 by forshaw@google.com, Nov 17

Project Member
Mergedinto: 1644
Status: Duplicate (was: New)
Marking as a duplicate of the master issue as only one fix was issue for all the bugs.

Comment 4 by forshaw@google.com, Nov 20

Project Member
Labels: -Restrict-View-Commit

Sign in to add a comment