Poking a Hole in the Patch–Escaping from IE Sandbox with a Poorly Patched Vulnerability


James Forshaw reported a vulnerability to Microsoft regarding Windows Audio Service in November 2014. In our analysis, we discovered that the patch Microsoft release later did not completely solve the problem. With a combination of techniques, we successfully bypassed the patch and can exploit the vulnerability on patched system.

0x00 The Problem

There was a privilege escalation vulnerability in Windows Audio Service, reported by James Forshaw in November 2014.

Windows Audio Service, which manage audio sessions of all the processes running in the system, store audio session configurations under registry key HKCU\Software\Microsoft\Internet Explorer\LowRegistry\Audio\PolicyConfig.

For this configuration to be modifiable even by low privileged processes, it recursively set the sub key ACLs to give write access to Low IL processes.

If an attacker sets a symbolic link under this key, and points the symbolic link to a higher-privileged location, Windows Audio Service would make that location controllable by Low IL.

0x01 The Patch

Microsoft released a security bulletin MS14-071, followed by a patch KB3005607, in order to fix this vulnerability.
This patch added two functions, SafeRegCreateKeyEx and DetectRegistryLink.

The following is reconstructed DetectRegistryLink function:

int DetectRegistryLink(const HKEY key_handle, const wchar_t sub_key_path[], HKEY * out_handle)
{
    int detect_result = 0;
    HKEY sub_key_handle;
    LSTATUS status = RegOpenKeyExW(key_handle,
                                   sub_key_path,
                                   REG_OPTION_OPEN_LINK,
                                   KEY_ALL_ACCESS,
                                   &sub_key_handle);

    if (status != ERROR_SUCCESS) {
        if (status == ERROR_FILE_NOT_FOUND) {
            detect_result = 3;
        } else if (status == ERROR_ACCESS_DENIED) {
            detect_result = 4;
        } else {
            detect_result = 5;
        }
    } else {
        DWORD key_type;
        BYTE data[MAX_PATH * 2];
        DWORD data_size = sizeof(data);

        status = RegQueryValueExW(sub_key_handle, 
                                  kSymbolicLinkValueName, 
                                  nullptr,
                                  &key_type, 
                                  data, 
                                  &data_size);

        if (((status == ERROR_SUCCESS) || (status == ERROR_MORE_DATA)) && (key_type == REG_LINK)) {
            detect_result = 1;
        } 
        if ((status == ERROR_FILE_NOT_FOUND) && (detect_result != 1)) {
            HKEY temp_key_handle;
            status = RegOpenKeyExW(key_handle,
                                   sub_key_path,
                                   0,
                                   KEY_READ,
                                   &temp_key_handle);

            RegCloseKey(temp_key_handle);
            detect_result = (status == ERROR_SUCCESS) + 1;
        }

        *out_handle = sub_key_handle;
    }

    return detect_result;
}

DetectRegistryLink has strict check on symbolic links. It first opens the key with flag REG_OPTION_OPEN_LINK, which prevents the redirection, then check for many different cases, including redirection to non-existing keys. After performing all the checks, the key handle is passed out of the function for reuse.

The upper level function SafeRegCreateKeyEx use DetectRegistryLink to check the key for symbolic links before creating new sub key, use NtDeleteKey to delete the symbolic link (with the previously opened handle) if found any, and finally use RegCreateKeyEx to create a new, “safe to use” sub key.

HKEY sub_key_handle;
int detect_result = DetectRegistryLink(key_handle, kSubKeyPath, &sub_key_handle);

if (detect_result == 1) {
    status = NtDeleteKey(sub_key_handle);
    RegCloseKey(sub_key_handle);
    sub_key_handle = nullptr;

    if (!NT_SUCCESS(status)) {
        return ERROR_ACCESS_DENIED;
    }
}

if (detect_result > 3) {
    if (sub_key_handle) {
        RegCloseKey(sub_key_handle);
    }

    return ERROR_ACCESS_DENIED;
}

DWORD create_disposition = 0;

if (sub_key_handle) {
    create_disposition = REG_OPENED_EXISTING_KEY;
} else {
    status = RegCreateKeyExW(key_handle,
                             kSubKeyPath,
                             0,
                             nullptr,
                             0,
                             KEY_ALL_ACCESS,
                             nullptr,
                             &sub_key_handle,
                             &create_disposition);

    if (status != ERROR_SUCCESS) {
        return status;
    }

    if (create_disposition != REG_CREATED_NEW_KEY) {
        RegCloseKey(sub_key_handle);
        return ERROR_ACCESS_DENIED;
    }
}

0x02 The Flaw

There is a serious flaw hidden inside this seemingly strict logic.

After NtDeleteKey deletes the symbolic link, the operating system no longer allow any additional operation to be performed on that key. The already opened handles remain valid, but any operation other than closing the key fails with STATUS_KEY_DELETED.

After the key handle is closed, the remaining operation must create a new key with a new handle. In this situation, the object with the same name is not guaranteed to be the same object.

With a precise timing attack, we could create a symbolic link just before the RegCreateKeyEx operation, bypassing the symbolic link check.

0x03 The Exploit

We take IE 11 sandbox as an example to demonstrate how to escalate privilege with this vulnerability.

To exploit this vulnerability, we first need to make Windows Audio Service perform the delete operation.

We can purposely place a symbolic link under the HKCU\Software\Microsoft\Internet Explorer\LowRegistry\Audio\PolicyConfig registry key, and trigger Windows Audio Service to save its configuration.

It is vital to control the timing of the second symbolic link placement. Of course we could create millions of threads trying to win the race, but the operating system already provides us with a handy mechanism.

NtNotifyChangeKey can watch a specific registry key, and signal an event upon certain operation is performed on that key.

By setting a notification on our first symbolic link, we can receive a notification right after it is deleted by Windows Audio Service, and have a chance to create a second symbolic link just before Windows Audio Service calls RegCreateKeyEx.

We can then point the symbolic link to a non-existing GUID under HKCU\Software\Microsoft\Internet Explorer\Low Rights\ElevationPolicy to satisfy the REG_CREATED_NEW_KEY requirement. The target key will be created by Windows Audio Service.

Finally, Windows Audio Service will use upper level key (PolicyConfig)’s ACL to overwrite target key’s ACL, making it controllable by Low IL processes.

At this point the exploitation is successful. We can now write arbitrary AppPath and set Policy to 0x3 to escape from the sandbox.

0x04 The Trick

The registry operation performed by the Windows Audio Service is done after RpcImpersonateClient. Although the race can be successful inside IE sandbox, the registry operation will be performed with the originating process’ token, which do not have sufficient privilege.

James Forshaw did not solve this problem in his original PoC, the registry operation has to be performed by manually starting SndVol.exe.

To solve it we have to find a Medium or higher IL process that uses audio session — basically anything that emits sound — and can be repeatedly triggered to allow multiple retries.

IE Elevation Policy is preloaded with some system applications that can be started inside sandbox with Medium IL, including Notepad.exe. After the Medium IL process is started, the returned handle only have the right to terminate the process. But we can still pass command line parameters.

When Notepad is opening a non-existing file, it displays a dialog asking if the user would like to create that file. The dialog follows a default system sound. This is sufficient to trigger a registry write by Windows Audio Service.

With multiple retries we can ensure successful exploitation.

0x05 The Mitigation

Microsoft completely disabled the creation of registry symbolic link at Low IL in a patch released in August 2015. When setting registry symbolic link, the kernel uses RtlIsSandboxedToken to check the current process’ token, and return STATUS_ACCESS_DENIED on any Low IL or AppContainer token. This rendered any registry symbolic link based exploits unusable at Low IL, and effectively eliminates the possibility of exploiting this vulnerability inside the IE sandbox.

References

  1. Issue 99: IE11 AudioSrv RegistryKey EPM Privilege Escalation – James Forshaw
    https://code.google.com/p/google-security-research/issues/detail?id=99
  2. Vulnerability in Windows Audio Service Could Allow Elevation of Privilege (3005607)
    https://technet.microsoft.com/library/security/MS14-071
  3. Windows 10 Symbolic Link Mitigations – James Forshaw
    https://googleprojectzero.blogspot.com/2015/08/windows-10hh-symbolic-link-mitigations.html