Posted by James Forshaw, Taker of Names
Sometimes when I'm doing security research I'll come across a bug which surprises me. I discovered just such a bug in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Windows version of Chrome which exposed a little-known security detail in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 OS. The bug, CVE-2014-3196 was fixed in M38, so it seemed a good time for a blog post. The actual reported issue is here. While cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bug didn’t allow for a full sandbox escape it did provide cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 initial part of a chain; something that’s still important to fix.
The security of an OS kernel is of extreme importance to modern user-mode sandboxes such as is used in Chrome. Some OS kernels have built-in facilities for reducing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 attack surface of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 OS in general, for example seccomp on Linux or cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 sandbox facilities in OS X. While not always perfect cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y are valuable facilities for Chrome. Windows 8 introduced some steps towards improving sandboxing, such as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 AppContainer model and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ability to disable Win32k system calls. Chrome has experimental support for disabling Win32k (through cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 --enable_win32k_renderer_lockdown flag), but for many ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r features it has to make do with what’s available.
On Windows, Chrome relies on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 built-in NT permissions model to secure resources from code executing within a sandboxed process. The Windows NT operating system was built with security in mind (no laughing at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 back) including a robust and flexible permission model for securing resources. There are two parts to securing resources, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Access Token which acts as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 identity of a process and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Discretionary Access Control List (DACL) that defines cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 list of users and groups which can access a resource and what permissions cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y would be granted. The set of permissions allowed is quite granular (and dependant on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 object type), but typically cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re are separate permissions for read, write and execute operations.
When a user mode process requests access to a securable kernel object cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel's security manager verifies cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process Access Token has access to that resource with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 required sets of permissions as defined in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DACL. If all permissions are allowed cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n a Handle is generated, an opaque reference to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 object, and returned to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process which can use it in subsequent system calls. Many resources also have cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ability to have an assigned name. Think of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 name like a file path which represents how to find and open a new handle to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 object. You can browse named objects using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 WinObj tool from Sysinternals.
One such securable resource is shared memory sections, sometimes called memory-mapped files. On Windows this is created through cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 CreateFileMapping API function. If you look at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 API you'll notice that it has a final parameter which specifies cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 name of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 object. Shared memory sections are used when Chrome needs to share large amounts of data between sandboxed processes and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 privileged broker process. The kernel defines a few permissions a program can request when accessing a section object; cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 most important for our purposes are FILE_MAP_WRITE which gives cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 program cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ability to map cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 memory writable and FILE_MAP_READ which gives cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 program read-only access. If a program is only granted FILE_MAP_READ cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel will ensure it cannot be mapped writable.
One useful feature of shared memory is that a process can create cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 memory and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n share a read-only copy with ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r processes. This allows a higher privileges process to provide a real-time copy of data which only it can update. A typical way to share sections read-only on Windows is to name cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m when cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y're created writeable in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 original process. Then by applying an appropriate DACL a sandboxed process calling cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 OpenFileMapping function can only be granted cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 FILE_MAP_READ permission. In Chrome’s case, sections are not shared by providing a name. Instead it uses a different method which we can see by looking at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 source code. In cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 base/memory directory you'll find Chrome's implementation of shared memory for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 different platforms. In cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 header you'll find an important function:
bool ShareReadOnlyToProcess(ProcessHandle process,
SharedMemoryHandle* new_handle) {
return ShareToProcessCommon(process, new_handle, false,
SharedMemoryHandle* new_handle) {
return ShareToProcessCommon(process, new_handle, false,
SHARE_READONLY);
}
}
The ShareReadOnlyToProcess function delegates to an OS specific function. For Windows this looked like:
bool SharedMemory::ShareToProcessCommon(ProcessHandle process,
SharedMemoryHandle *new_handle,
bool close_self,
ShareMode share_mode) {
*new_handle = 0;
DWORD access = FILE_MAP_READ;
DWORD options = 0;
HANDLE mapped_file = mapped_file_;
HANDLE result;
if (share_mode == SHARE_CURRENT_MODE && !read_only_)
access |= FILE_MAP_WRITE;
// *SNIP* ...
if (!DuplicateHandle(GetCurrentProcess(), mapped_file, process,
&result, access, FALSE, options))
return false;
*new_handle = result;
return true;
}
SharedMemoryHandle *new_handle,
bool close_self,
ShareMode share_mode) {
*new_handle = 0;
DWORD access = FILE_MAP_READ;
DWORD options = 0;
HANDLE mapped_file = mapped_file_;
HANDLE result;
if (share_mode == SHARE_CURRENT_MODE && !read_only_)
access |= FILE_MAP_WRITE;
// *SNIP* ...
if (!DuplicateHandle(GetCurrentProcess(), mapped_file, process,
&result, access, FALSE, options))
return false;
*new_handle = result;
return true;
}
It might be more obvious if I show it in diagrammatic form. The section object is shared between cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 different processes but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 handles have different permissions.
This behaviour is documented, sort-of. For example have a look at this MSDN page. Did you see cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 documented behaviour? It amounts to a throw away comment, with no effort to go into detail. The page doesn’t tell you which unnamed objects have no security, just that some unnamed objects DO have security (such as processes). So let's find out what determines this behaviour. If you dump cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 OBJECT_TYPE_INITIALIZER structure from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 public kernel symbols you'll see cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 offender.
0:000> dt nt!_OBJECT_TYPE_INITIALIZER
ntdll!_OBJECT_TYPE_INITIALIZER
+0x000 Length : Uint2B
+0x002 ObjectTypeFlags : UChar
+0x002 CaseInsensitive : Pos 0, 1 Bit
+0x002 UnnamedObjectsOnly : Pos 1, 1 Bit
+0x002 UseDefaultObject : Pos 2, 1 Bit
+0x002 SecurityRequired : Pos 3, 1 Bit <---- Important Flag
+0x002 MaintainHandleCount : Pos 4, 1 Bit
+0x002 MaintainTypeList : Pos 5, 1 Bit
+0x002 SupportsObjectCallbacks : Pos 6, 1 Bit
+0x002 CacheAligned : Pos 7, 1 Bit
+0x004 ObjectTypeCode : Uint4B
+0x008 InvalidAttributes : Uint4B
* SNIP....
ntdll!_OBJECT_TYPE_INITIALIZER
+0x000 Length : Uint2B
+0x002 ObjectTypeFlags : UChar
+0x002 CaseInsensitive : Pos 0, 1 Bit
+0x002 UnnamedObjectsOnly : Pos 1, 1 Bit
+0x002 UseDefaultObject : Pos 2, 1 Bit
+0x002 SecurityRequired : Pos 3, 1 Bit <---- Important Flag
+0x002 MaintainHandleCount : Pos 4, 1 Bit
+0x002 MaintainTypeList : Pos 5, 1 Bit
+0x002 SupportsObjectCallbacks : Pos 6, 1 Bit
+0x002 CacheAligned : Pos 7, 1 Bit
+0x004 ObjectTypeCode : Uint4B
+0x008 InvalidAttributes : Uint4B
* SNIP....
The important part of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 type is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SecurityRequired flag. If you dump cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 section object type nt!MmSectionObjectType and compare it to something like cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process type nt!PsProcessType you'll see cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 difference. I guess cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 question you might be asking is what ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r types have this same behaviour; well a quick script later on Windows 8.1 and you’ll get cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following types which have cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SecurityRequired flag set to 0, note of course that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Section type is among cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 list:
Adapter
ALPC Port
Callback
Controller
Device
Driver
Event
File
FilterCommunicationPort
IoCompletion
IoCompletionReserve
IRTimer
KeyedEvent
Mutant
PcwObject
PowerRequest
Profile
Section
Semaphore
SymbolicLink
Timer
TpWorkerFactory
Type
UserApcReserve
WaitCompletionPacket
ALPC Port
Callback
Controller
Device
Driver
Event
File
FilterCommunicationPort
IoCompletion
IoCompletionReserve
IRTimer
KeyedEvent
Mutant
PcwObject
PowerRequest
Profile
Section
Semaphore
SymbolicLink
Timer
TpWorkerFactory
Type
UserApcReserve
WaitCompletionPacket
There are some interesting types in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 list, but remember cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se types only have no security if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y have no name, which would make it trickier to exploit. Also some like “Type” are unlikely to ever be accessible in a user mode process, but it’s still worthwhile pointing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m out.
Okay so how might we exploit this in practice? Turns out cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re was actually only one user of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ShareReadOnlyToProcess method at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 time. It was part of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code which shared extension scripts between renderer processes (see user_script_loader.cc). For reasons of efficiency cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se scripts were shared read-only to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 renderers and relied on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 OS enforcing this read-only property of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 sections to prevent cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 renderers modifying cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 contents. On Linux/OSX this works but due to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 issue I’ve just described it didn't work so well on Windows. The contents of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 section looked like cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 image below, it contained a pickled version of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 script and extension information.
From a compromised renderer you can call DuplicateHandle to elevate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 privileges of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 section handle to re-gain write access, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n modify cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 shared memory to execute arbitrary Javascript in any rendered page, including more-privileged chrome:// pages. While this is not directly a sandbox breakout it could be used as part of a chain as demonstrated in previous attacks against cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Chrome sandbox. Of course a bug like this might be even more important when site-isolation is enabled as a default in Chrome.