Friday, November 30, 2018

Injecting Code into Windows Protected Processes using COM - Part 2

Posted by James Forshaw, Project Zero

In my previous blog I discussed a technique which combined numerous issues I’ve previously reported to Microsoft to inject arbitrary code into a PPL-WindowsTCB process. The techniques presented don’t work for exploiting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 older, stronger Protected Processes (PP) for a few different reasons. This blog seeks to remedy this omission and provide details of how I was able to also hijack a full PP-WindowsTCB process without requiring administrator privileges. This is mainly an academic exercise, to see whecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r I can get code executing in a full PP as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s not much more you can do inside a PP over a PPL.

As a quick recap of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 previous attack, I was able to identify a process which would run as PPL which also exposed a COM service. Specifically, this was cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 “.NET Runtime Optimization Service” which ships with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 .NET framework and uses PPL at CodeGen level to apply cached signing levels to Ahead-of-Time compiled DLLs to allow cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m to be used with User-Mode Code Integrity (UMCI). By modifying cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 COM proxy configuration it was possible to induce a type confusion which allowed me to load an arbitrary DLL by hijacking cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 KnownDlls configuration. Once running code inside cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 PPL I could abuse a bug in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 cached signing feature to create a DLL signed to load into any PPL and through that escalate to PPL-WindowsTCB level.

Finding a New Target

My first thought to exploit full PP would be to use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 additional access we were granted from having code running at PPL-WindowsTCB. You might assume you could abuse cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 cached signed DLL to bypass security checks to load into a full PP. Unfortunately cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel’s Code Integrity module ignores cached signing levels for full PP. How about KnownDlls in general? If we have administrator privileges and code running in PPL-WindowsTCB we can directly write to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 KnownDlls object directory (see anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r of my blog posts link for why you need to be PPL) and try to get cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 PP to load an arbitrary DLL. Unfortunately, as I mentioned in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 previous blog, this also doesn’t work as full PP ignores KnownDlls. Even if it did load KnownDlls I don’t want to require administrator privileges to inject code into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process.

I decided that it’d make sense to rerun my PowerShell script from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 previous blog to discover which executables will run as full PP and at what level. On Windows 10 1803 cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s a significant number of executables which run as PP-Aucá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365nticode level, however only four executables would start with a more privileged level as shown in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following table.

Path
Signing Level
C:\windows\system32\GenValObj.exe
Windows
C:\windows\system32\sppsvc.exe
Windows
C:\windows\system32\WerFaultSecure.exe
WindowsTCB
C:\windows\system32\SgrmBroker.exe
WindowsTCB

As I have no known route from PP-Windows level to PP-WindowsTCB level like I had with PPL, only two of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 four executables are of interest, WerFaultSecure.exe and SgrmBroker.exe. I correlated cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se two executables against known COM service registrations, which turned up no results. That doesn’t mean cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se executables don’t expose a COM attack surface, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 .NET executable I abused last time also doesn’t register its COM service, so I also performed some basic reverse engineering looking for COM usage.

The SgrmBroker executable doesn’t do very much at all, it’s a wrapper around an isolated user mode application to implement runtime attestation of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 system as part of Windows Defender System Guard and didn’t call into any COM APIs. WerFaultSecure also doesn’t seem to call into COM, however I already knew that WerFaultSecure can load COM objects, as Alex Ionescu used my original COM scriptlet code execution attack to get PPL-WindowsTCB level though hijacking a COM object load in WerFaultSecure. Even though WerFaultSecure didn’t expose a service if it could initialize COM perhaps cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re was something that I could abuse to get arbitrary code execution? To understand cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 attack surface of COM we need to understand how COM implements out-of-process COM servers and COM remoting in general.

Digging into COM Remoting Internals

Communication between a COM client and a COM server is over cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 MSRPC protocol, which is based on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Open Group’s DCE/RPC protocol. For local communication cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 transport used is Advanced Local Procedure Call (ALPC) ports. At a high level communication occurs between a client and server based on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following diagram:


In order for a client to find cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 location of a server cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process registers an ALPC endpoint with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DCOM activator in RPCSS ①. This endpoint is registered alongside cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Object Exporter ID (OXID) of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 server, which is a 64 bit randomly generated number assigned by RPCSS. When a client wants to connect to a server it must first ask RPCSS to resolve cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 server’s OXID value to an RPC endpoint ②. With cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 knowledge of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ALPC RPC endpoint cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 client can connect to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 server and call methods on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 COM object ③.

The OXID value is discovered eicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r from an out-of-process (OOP) COM activation result or via a marshaled Object Reference (OBJREF) structure. Under cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 hood cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 client calls cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ResolveOxid method on RPCSS’s IObjectExporter RPC interface. The prototype of ResolveOxid is as follows:

interface IObjectExporter {
  // ...
  error_status_t ResolveOxid(
    [in] handle_t hRpc,
    [in] OXID* pOxid,
    [in] unsigned short cRequestedProtseqs,
    [in] unsigned short arRequestedProtseqs[],
    [out, ref] DUALSTRINGARRAY** ppdsaOxidBindings,
    [out, ref] IPID* pipidRemUnknown,
    [out, ref] DWORD* pAuthnHint
);

In cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 prototype we can see cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 OXID to resolve is being passed in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 pOxid parameter and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 server returns an array of Dual String Bindings which represent RPC endpoints to connect to for this OXID value. The server also returns two ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r pieces of information, an Aucá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ntication Level Hint (pAuthnHint) which we can safely ignore and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 IPID of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 IRemUnknown interface (pipidRemUnknown) which we can’t.

An IPID is a GUID value called cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Interface Process ID. This represents cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 unique identifier for a COM interface inside cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 server, and it’s needed to communicate with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 correct COM object as it allows cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 single RPC endpoint to multiplex multiple interfaces over one connection. The IRemUnknown interface is a default COM interface every COM server must implement as it’s used to query for new IPIDs on an existing object (using RemQueryInterface) and maintain cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 remote object’s reference count (through RemAddRef and RemRelease methods). As this interface must always exist regardless of whecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r an actual COM server is exported and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 IPID can be discovered through resolving cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 server’s OXID, I wondered what ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r methods cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 interface supported in case cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re was anything I could leverage to get code execution.

The COM runtime code maintains a database of all IPIDs as it needs to lookup cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 server object when it receives a request for calling a method. If we know cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 structure of this database we could discover where cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 IRemUnknown interface is implemented, parse its methods and find out what ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r features it supports. Fortunately I’ve done cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 work of reverse engineering cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 database format in my OleViewDotNet tool, specifically cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 command Get-ComProcess in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 PowerShell module. If we run cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 command against a process which uses COM, but doesn’t actually implement a COM server (such as notepad) we can try and identify cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 correct IPID.


In this example screenshot cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s actually two IPIDs exported, IRundown and a Windows.Foundation interface. The Windows.Foundation interface we can safely ignore, but IRundown looks more interesting. In fact if you perform cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same check on any COM process you’ll discover cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y also have IRundown interfaces exported. Are we not expecting an IRemUnknown interface though? If we pass cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ResolveMethodNames and ParseStubMethods parameters to Get-ComProcess, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 command will try and parse method parameters for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 interface and lookup names based on public symbols. With cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 parsed interface data we can pass cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 IPID object to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Format-ComProxy command to get a basic text representation of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 IRundown interface. After cleanup cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 IRundown interface looks like cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following:

[uuid("00000134-0000-0000-c000-000000000046")]
interface IRundown : IUnknown {
   HRESULT RemQueryInterface(...);
   HRESULT RemAddRef(...);
   HRESULT RemRelease(...);
   HRESULT RemQueryInterface2(...);
   HRESULT RemChangeRef(...);
   HRESULT DoCallback([in] struct XAptCallback* pCallbackData);
   HRESULT DoNonreentrantCallback([in] struct XAptCallback* pCallbackData);
   HRESULT AcknowledgeMarshalingSets(...);
   HRESULT GetInterfaceNameFromIPID(...);
   HRESULT RundownOid(...);
}

This interface is a superset of IRemUnknown, it implements cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 methods such as RemQueryInterface and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n adds some more additional methods for good measure. What really interested me was cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DoCallback and DoNonreentrantCallback methods, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y sound like cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y might execute a “callback” of some sort. Perhaps we can abuse cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se methods? Let’s look at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 implementation of DoCallback based on a bit of RE (DoNonreentrantCallback just delegates to DoCallback internally so we don’t need to treat it specially):

struct XAptCallback {
 void* pfnCallback;
 void* pParam;
 void* pServerCtx;
 void* pUnk;
 void* iid;
 int   iMethod;
 GUID  guidProcessSecret;
};

HRESULT CRemoteUnknown::DoCallback(XAptCallback *pCallbackData) {
 CProcessSecret::GetProcessSecret(&pguidProcessSecret);
 if (!memcmp(&pguidProcessSecret,
             &pCallbackData->guidProcessSecret, sizeof(GUID))) {
   if (pCallbackData->pServerCtx == GetCurrentContext()) {
     return pCallbackData->pfnCallback(pCallbackData->pParam);
   } else {
     return SwitchForCallback(
                  pCallbackData->pServerCtx,
                  pCallbackData->pfnCallback,
                  pCallbackData->pParam);
   }
 }
 return E_INVALIDARG;
}

This method is very interesting, it takes a structure containing a pointer to a method to call and an arbitrary parameter and executes cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 pointer. The only restrictions on calling cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 arbitrary method is you must know ahead of time a randomly generated GUID value, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process secret, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 address of a server context. The checking of a per-process random value is a common security pattern in COM APIs and is typically used to restrict functionality to only in-process callers. I abused something similar in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Free-Threaded Marshaler way back in 2014.

What is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 purpose of DoCallback? The COM runtime creates a new IRundown interface for every COM apartment that’s initialized. This is actually important as calling methods between apartments, say calling a STA object from a MTA, you need to call cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 appropriate IRemUnknown methods in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 correct apartment. Therefore while cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 developers were cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y added a few more methods which would be useful for calling between apartments, including a general “call anything you like” method. This is used by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 internals of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 COM runtime and is exposed indirectly through methods such as CoCreateObjectInContext. To prevent cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DoCallback method being abused OOP cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 per-process secret is checked which should limit it to only in-process callers, unless an external process can read cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 secret from memory.

Abusing DoCallback

We have a primitive to execute arbitrary code within any process which has initialized COM by invoking cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DoCallback method, which should include a PP. In order to successfully call arbitrary code we need to know four pieces of information:

  1. The ALPC port that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 COM process is listening on.
  2. The IPID of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 IRundown interface.
  3. The initialized process secret value.
  4. The address of a valid context, ideally cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same value that GetCurrentContext returns to call on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same RPC thread.

Getting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ALPC port and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 IPID is easy, if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process exposes a COM server, as both will be provided during OXID resolving. Unfortunately WerFaultSecure doesn’t expose a COM object we can create so that angle wouldn’t be open to us, leaving us with a problem we need to solve. Extracting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process secret and context value requires reading cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 contents of process memory. This is anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r problem, one of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 intentional security features of PP is preventing a non-PP process from reading memory from a PP process. How are we going to solve cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se two problems?

Talking this through with Alex at Recon we came up with a possible attack if you have administrator access. Even being an administrator doesn’t allow you to read memory directly from a PP process. We could have loaded a driver, but that would break PP entirely, so we considered how to do it without needing kernel code execution.

First and easiest, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ALPC port and IPID can be extracted from RPCSS. The RPCSS service does not run protected (even PPL) so this is possible to do without any clever tricks ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r than knowing where cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 values are stored in memory. For cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 context pointer, we should be able to brute force cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 location as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s likely to be only a narrow range of memory locations to test, made slightly easier if we use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 32 bit version of WerFaultSecure.

Extracting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 secret is somewhat harder. The secret is initialized in writable memory and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365refore ends up in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process’ working set once it’s modified. As cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 page isn’t locked it will be eligible for paging if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 memory conditions are right. Therefore if we could force cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 page containing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 secret to be paged to disk we could read it even though it came from a PP process. As an administrator, we can perform cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following to steal cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 secret:

  1. Ensure cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 secret is initialized and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 page is modified.
  2. Force cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process to trim its working set, this should ensure cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 modified page containing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 secret ends up paged to disk (eventually).
  3. Create a kernel memory crash dump file using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 NtSystemDebugControl system call. The crash dump can be created by an administrator without kernel debugging being enabled and will contain all live memory in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel. Note this doesn’t actually crash cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 system.
  4. Parse cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 crash dump for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Page Table Entry of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 page containing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 secret value. The PTE should disclose where in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 paging file on disk cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 paged data is located.
  5. Open cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 volume containing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 paging file for read access, parse cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 NTFS structures to find cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 paging file and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n find cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 paged data and extract cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 secret.

After coming up with this attack it seemed far too much like hard work and needed administrator privileges which I wanted to avoid. I needed to come up with an alternative solution.

Using WerFaultSecure for its Original Purpose

Up to this point I’ve been discussing WerFaultSecure as a process that can be abused to get arbitrary code running inside a PP/PPL. I’ve not really described why cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process can run at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 maximum PP/PPL levels. WerFaultSecure is used by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Windows Error Reporting service to create crash dumps from protected processes. Therefore it needs to run at elevated PP levels to ensure it can dump any possible user-mode PP. Why can we not just get WerFaultSecure to create a crash dump of itself, which would leak cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 contents of process memory and allow us to extract any information we require?

The reason we can’t use WerFaultSecure is it encrypts cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 contents of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 crash dump before writing it to disk. The encryption is done in a way to only allow Microsoft to decrypt cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 crash dump, using asymmetric encryption to protect a random session key which can be provided to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Microsoft WER web service. Outside of a weakness in Microsoft’s implementation or a new cryptographic attack against cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 primitives being used getting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 encrypted data seems like a non-starter.

However, it wasn’t always this way. In 2014 Alex presented at NoSuchCon about PPL and discussed a bug he’d discovered in how WerFaultSecure created encrypted dump files. It used a two step process, first it wrote out cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 crash dump unencrypted, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n it encrypted cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 crash dump. Perhaps you can spot cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 flaw? It was possible to steal cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 unencrypted crash dump. Due to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 way WerFaultSecure was called it accepted two file handles, one for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 unencrypted dump and one for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 encrypted dump. By calling WerFaultSecure directly cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 unencrypted dump would never be deleted which means that you don’t even need to race cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 encryption process.

There’s one problem with this, it was fixed in 2015 in MS15-006. After that fix WerFaultSecure encrypted cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 crash dump directly, it never ends up on disk unencrypted at any point. But that got me thinking, while cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y might have fixed cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bug going forward what prevents us from taking cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 old vulnerable version of WerFaultSecure from Windows 8.1 and executing it on Windows 10? I downloaded cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ISO for Windows 8.1 from Microsoft’s website (link), extracted cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 binary and tested it, with predictable results:


We can take cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerable version of WerFaultSecure from Windows 8.1 and it will run quite happily on Windows 10 at PP-WindowsTCB level. Why? It’s unclear, but due to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 way PP is secured all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 trust is based on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 signed executable. As cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 signature of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 executable is still valid cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 OS just trusts it can be run at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 requested protection level. Presumably cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re must be some way that Microsoft can block specific executables, although at least cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y can’t just revoke cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir own signing certificates. Perhaps OS binaries should have an EKU in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 certificate which indicates what version cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y’re designed to run on? After all Microsoft already added a new EKU when moving from Windows 8 to 8.1 to block downgrade attacks to bypass WinRT UMCI signing so generalizing might make some sense, especially for certain PP levels.

After a little bit of RE and reference to Alex’s presentation I was able to work out cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 various parameters I needed to be passed to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 WerFaultSecure process to perform a dump of a PP:

Parameter
Description
/h
Enable secure dump mode.
/pid {pid}
Specify cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Process ID to dump.
/tid {tid}
Specify cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Thread ID in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process to dump.
/file {handle}
Specify a handle to a writable file for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 unencrypted crash dump
/encfile {handle}
Specify a handle to a writable file for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 encrypted crash dump
/cancel {handle}
Specify a handle to an event to indicate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 dump should be cancelled
/type {flags}
Specify MIMDUMPTYPE flags for call to MiniDumpWriteDump

This gives us everything we need to complete cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit. We don’t need administrator privileges to start cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 old version of WerFaultSecure as PP-WindowsTCB. We can get it to dump anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r copy of WerFaultSecure with COM initialized and use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 crash dump to extract all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 information we need including cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ALPC Port and IPID needed to communicate. We don’t need to write our own crash dump parser as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Debug Engine API which comes installed with Windows can be used. Once we’ve extracted all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 information we need we can call DoCallback and invoke arbitrary code.

Putting it All Togecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r

There’s still two things we need to complete cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit, how to get WerFaultSecure to start up COM and what we can call to get completely arbitrary code running inside cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 PP-WindowsTCB process.

Let’s tackle cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first part, how to get COM started. As I mentioned earlier, WerFaultSecure doesn’t directly call any COM methods, but Alex had clearly used it before so to save time I just asked him. The trick was to get WerFaultSecure to dump an AppContainer process, this results in a call to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 method CCrashReport::ExemptFromPlmHandling inside cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 FaultRep DLL resulting in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 loading of CLSID {07FC2B94-5285-417E-8AC3-C2CE5240B0FA}, which resolves to an undocumented COM object. All that matters is this allows WerFaultSecure to initialize COM.

Unfortunately I’ve not been entirely truthful during my description of how COM remoting is setup. Just loading a COM object is not always sufficient to initialize cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 IRundown interface or cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 RPC endpoint. This makes sense, if all COM calls are to code within cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same apartment cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n why bocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r to initialize cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 entire remoting code for COM. In this case even though we can make WerFaultSecure load a COM object it doesn’t meet cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 conditions to setup remoting. What can we do to convince cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 COM runtime that we’d really like it to initialize? One possibility is to change cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 COM registration from an in-process class to an OOP class. As shown in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 screenshot below cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 COM registration is being queried first from HKEY_CURRENT_USER which means we can hijack it without needing administrator privileges.


Unfortunately looking at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code this won’t work, a cut down version is shown below:

HRESULT CCrashReport::ExemptFromPlmHandling(DWORD dwProcessId) {
 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
 IOSTaskCompletion* inf;
 HRESULT hr = CoCreateInstance(CLSID_OSTaskCompletion,
     NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&inf));
 if (SUCCEEDED(hr)) {
   // Open process and disable PLM handling.
 }
}

The code passes cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 flag, CLSCTX_INPROC_SERVER to CoCreateInstance. This flag limits cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 lookup code in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 COM runtime to only look for in-process class registrations. Even if we replace cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 registration with one for an OOP class cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 COM runtime would just ignore it. Fortunately cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r way, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code is initializing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 current thread’s COM apartment as a STA using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 COINIT_APARTMENTTHREADED flag with CoInitializeEx. Looking at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 registration of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 COM object its threading model is set to “Both”. What this means in practice is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 object supports being called directly from eicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r a STA or a MTA.

However, if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 threading model was instead set to “Free” cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 object only supports direct calls from an MTA, which means cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 COM runtime will have to enable remoting, create cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 object in an MTA (using something similar to DoCallback) cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n marshal calls to that object from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 original apartment. Once COM starts remoting it initializes all remote features including IRundown. As we can hijack cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 server registration we can just change cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 threading model, this will cause WerFaultSecure to start COM remoting which we can now exploit.

What about cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 second part, what can we call inside cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process to execute arbitrary code? Anything we call using DoCallback must meet cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following criteria, to avoid undefined behavior:

  1. Only takes one pointer sized parameter.
  2. Only cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 lower 32 bits of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 call are returned as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 HRESULT if we need it.
  3. The callsite is guarded by CFG so it must be something which is a valid indirect call target.

As WerFaultSecure isn’t doing anything special cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n at a minimum any DLL exported function should be a valid indirect call target. LoadLibrary clearly meets our criteria as it takes a single parameter which is a pointer to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DLL path and we don’t really care about cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 return value so cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 truncation isn’t important. We can’t just load any DLL as it must be correctly signed, but what about hijacking KnownDlls?

Wait, didn’t I say that PP can’t load from KnownDlls? Yes cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y can’t but only because cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 value of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 LdrpKnownDllDirectoryHandle global variable is always set to NULL during process initialization. When cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DLL loader checks for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 presence of a known DLL if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 handle is NULL cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 check returns immediately. However if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 handle has a value it will do cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 normal check and just like in PPL no additional security checks are performed if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process maps an image from an existing section object. Therefore if we can modify cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 LdrpKnownDllDirectoryHandle global variable to point to a directory object inherited into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 PP we can get it to load an arbitrary DLL.

The final piece of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 puzzle is finding an exported function which we can call to write an arbitrary value into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 global variable. This turns out to be harder than expected. The ideal function would be one which takes a single pointer value argument and writes to that location with no ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r side effects. After a number of false starts (including trying to use gets) I settled on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 pair, SetProcessDefaultLayout and GetProcessDefaultLayout in USER32. The set function takes a single value which is a set of flags and stores it in a global location (actually in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel, but good enough). The get method will cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n write that value to an arbitrary pointer. This isn’t perfect as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 values we can set and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365refore write are limited to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 numbers 0-7, however by offsetting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 pointer in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 get calls we can write a value of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 form 0x0?0?0?0? where cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ? can be any value between 0 and 7. As cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 value just has to refer to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 handle inside a process under our control we can easily craft cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 handle to meet cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se strict requirements.

Wrapping Up

In conclusion to get arbitrary code execution inside a PP-WindowsTCB without administrator privileges process we can do cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following:

  1. Create a fake KnownDlls directory, duplicating cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 handle until it meets a pattern suitable for writing through Get/SetProcessDefaultLayout. Mark cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 handle as inheritable.
  2. Create cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 COM object hijack for CLSID {07FC2B94-5285-417E-8AC3-C2CE5240B0FA} with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ThreadingModel set to “Free”.
  3. Start Windows 10 WerFaultSecure at PP-WindowsTCB level and request a crash dump from an AppContainer process. During process creation cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fake KnownDlls must be added to ensure it’s inherited into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 new process.
  4. Wait until COM has initialized cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n use Windows 8.1 WerFaultSecure to dump cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process memory of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 target.
  5. Parse cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 crash dump to discover cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process secret, context pointer and IPID for IRundown.
  6. Connect to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 IRundown interface and use DoCallback with Get/SetProcessDefaultLayout to modify cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 LdrpKnownDllDirectoryHandle global variable to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 handle value created in 1.
  7. Call DoCallback again to call LoadLibrary with a name to load from our fake KnownDlls.

This process works on all supported versions of Windows 10 including 1809. It’s worth noting that invoking DoCallback can be used with any process where you can read cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 contents of memory and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process has initialized COM remoting. For example, if you had an arbitrary memory disclosure vulnerability in a privileged COM service you could use this attack to convert cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 arbitrary read into arbitrary execute. As I don’t tend to look for memory corruption/memory disclosure vulnerabilities perhaps this behavior is of more use to ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365rs.

That concludes my series of attacking Windows protected processes. I think it demonstrates that preventing a user from attacking processes which share resources, such as registry and files is ultimately doomed to fail. This is probably why Microsoft do not support PP/PPL as a security boundary. Isolated User Mode seems a much stronger primitive, although that does come with additional resource requirements which PP/PPL doesn’t for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 most part.  I wouldn’t be surprised if newer versions of Windows 10, by which I mean after version 1809, will try to mitigate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se attacks in some way, but you’ll almost certainly be able to find a bypass.