Closed Bug 1372849 (CVE-2017-7804) Opened 7 years ago Closed 7 years ago

WindowsDllDetourPatcher Destructor Exploit Primitive

Categories

(Core :: Security, defect)

defect
Not set
normal

Tracking

()

RESOLVED FIXED
mozilla56
Tracking Status
firefox-esr52 55+ fixed
firefox54 --- wontfix
firefox55 + fixed
firefox56 + fixed

People

(Reporter: stephen, Assigned: stephen)

References

(Blocks 1 open bug)

Details

(Keywords: csectype-priv-escalation, sec-high, Whiteboard: [adv-main55+][adv-esr52.3+][post-critsmash-triage])

Attachments

(2 files, 3 obsolete files)

WindowsDllDetourPatcher Destructor Exploit Primitive

The destructor function for the WindowsDllDetourPatcher class can be re-purposed by an attacker during the exploitation of a memory corruption exploit to force attacker controlled data to be written to an attacker controlled location in memory. Furthermore the destructor function will modify the protection of the memory being written-to, to be writable, before reverting it back to the original protection. This allows an attacker to write arbitrary code to an existing code section before executing it. This issue was found as part of a security review and a working exploit using this technique was developed against FF 52.0 64-Bit on Windows 10.0.15063 (See magic_selfrando_pdatascan1.html in https://bugzilla.mozilla.org/show_bug.cgi?id=1371002).

The purpose of the ~WindowsDllDetourPatcher function is to remove existing hooks in place by overwriting the destination pointer from the "JMP pointer" (x86) or "MOV R11, pointer; JMP R11" (x64) code bytes previously written by CreateTrampoline back to the address of the trampoline, which effectively removes the hook. The mHookPage member variable is a pointer to a buffer that holds several items for every hook that has been added; including a pointer to the original location where the hook was inserted and the trampoline code itself.

An attacker with a read/write primitive can discover the location of the mozilla::internal::WindowsDllDetourPatcher::~WindowsDllDetourPatcher function and modify an existing object in heap memory in order to change a vftable entry to allow the ~WindowsDllDetourPatcher function to be called. When ~WindowsDllDetourPatcher is called, it will use member variables stored in the corrupted object and thus the attacker can control the mHookPage and mCurHooks member variables.

Note: This issue is separate from https://bugzilla.mozilla.org/show_bug.cgi?id=1344034 as the attacker can set the mHookPage pointer to point to a RW buffer of their choosing. No existing hooks will be in place (as we forge a new WindowsDllDetourPatcher instance) so this buffer never needs to be executable.

The attacker can then specify a target location to write to (for example a location in a RX .text section is a good candidate). The data written is an address within the mHookPage buffer (what would be the location of the trampoline code). As the attacker can control this address, the attacker can choose an arbitrary low byte when setting the address in order to force a byte of attacker controlled data to be written to the target address. This operation can be repeated multiple times to allow an arbitrary sequence of bytes to be written.

The above technique can be used during any memory corruption exploit where an attacker has a read/write primitive. In order to harden the ~WindowsDllDetourPatcher function from being re-purposed by an attacker, several options are available:

	1. Encode the origBytes pointers held in the mHookPage buffer using a secure technique like EncodePointer/DecodePointer (which use a secret held in the kernel to avoid an attacker leaking it). Note: This API is available on XPSP2 and up.
	
	2. Ensure the byte(s) preceding the location being written to are the expected ones. As the write replaces the dest pointer for a jmp, we can always expect the preceding byte on x86 to be 0xE9 for a "JMP ptr" instruction and on x64 it can be expected to be 0x49, 0xBB for a "MOV R11, ptr; JMP R11" sequence. If the expected bytes are not found the process should __fastfail.

	3. Enable CFG as ~WindowsDllDetourPatcher would not be an indirect call target as the class (or the destructor) is not virtual, so methods are called directly and not indirectly via a vftable. This would prevent an attacker calling the destructor via a corrupted object.

	4. Enable immutable code pages on systems that support it, e.g. on Windows 10, this is available in the form of Arbitrary Code Guard (ACG). However this is a non trivial change which will probably require out of process JIT engine, out of process hooking and so on.
	
Options 1 and 2 are the best short term solutions, with 3 the best mid term and 4 the best long term solution.
Attached patch 1372849.patch (obsolete) — Splinter Review
Attached is a patch for consideration. It implements options 1 and 2 as previously mentioned. I have verified that this breaks the exploit I developed. I chose to use 'continue;' in the destructors for loop if an unexpected byte sequence was seen rather that use __fastfail() as I couldn't see any evidence anywhere else in the code base that you use fast failing for these type of conditions.
Attached patch 1372849.patch (obsolete) — Splinter Review
The attached is a patch that applied against -central and can be imported.

Stephen, I wrote the patch in your name with a commit message - I'm flagging you for ni to confirm you're okay with your name being attached to the patch and message.
Attachment #8877578 - Attachment is obsolete: true
Flags: needinfo?(stephen)
Yes that's fine to use may name, cheers :)
Flags: needinfo?(stephen)
Thanks for the great writeup, Stephen! I support both of the approaches in the patch.

Regarding the GetProcAddress: is there any reason not to link against EncodePointer/DecodePointer directly? We haven't supported anything below XPSP2 for 4+ years.

Also I'm wondering if we need to re-word the patch description per the security guidelines to avoid calling attention to the exploit details -- although that may be difficult, since the hidden bug with this code change makes it pretty clear what problem we're patching. :/ I wonder if we should land these as "stability" fixes in a public bug, maybe say to avoid conflicting with other apps that re-hook our same APIs.
Thanks David, I didn't realise XPSP1 or below was no longer supported hence why the GetProcAddress. It makes much better sense to link directly to these API's rather than dynamically resolve them if it doesn't affect compatibility.
LGTM. Style nit re: spaces surrounding parameters to EncodePointer and DecodePointer
Attached patch 1372849.patch (obsolete) — Splinter Review
I've updated the patch to remove the indirection and fix the nit. I haven't compiled it (no easy way to do so) but it 'should work'? =)
Attachment #8877642 - Attachment is obsolete: true
Assignee: nobody → stephen
Status: UNCONFIRMED → NEW
Ever confirmed: true
Flagging for thoughts about the patch description and comment 4.
Flags: needinfo?(dveditz)
Tom: can you run the patch through a try build?
Group: firefox-core-security → dom-core-security
Flags: needinfo?(tom)
Product: Firefox → Core
I think we need to keep the in-line comments just to make sense of the code in the future (e.g. "Ensure the JMP from CreateTrampoline is where we expect it to be.") which limits how obscure we can make this. We should drop the details from the commit message, though. A simple "Bug 1372849 Improve the security of WindowsDllDetourPatcher" should be OK, doesn't give away much beyond what's already obvious.
Flags: needinfo?(dveditz)
(In reply to Daniel Veditz [:dveditz] from comment #9)
> Tom: can you run the patch through a try build?


Yes, duh of course - sorry.

https://treeherder.mozilla.org/#/jobs?repo=try&revision=5ed3dd6deea30275167fca5f07024183c605701a
Flags: needinfo?(tom)
tracking as sec-high
Adding Bug 1344034 as a 'See Also' which Stephen identified alongside this one, but was reported earlier by a Tor developer.
See Also: → CVE-2017-7782
Comment on attachment 8877731 [details] [diff] [review]
1372849.patch

tjr, do you want to fill out the sec-approval on behalf of Stephen?
Attachment #8877731 - Flags: sec-approval?
Attachment #8877731 - Flags: review+
Comment on attachment 8877731 [details] [diff] [review]
1372849.patch

Oops
Attachment #8877731 - Flags: sec-approval?
Comment on attachment 8877731 [details] [diff] [review]
1372849.patch

[Security approval request comment]
How easily could an exploit be constructed based on the patch? 

The patch itself does not fix an immediately exploitable condition (like a UAF or int overflow). But given such a vulnerability, this issue could help build an exploit. The patch makes it very obvious we are hardening this structure to make it more difficult to build exploits with it.


Do comments in the patch, the check-in comment, or tests included in the patch paint a bulls-eye on the security problem?

Yup. Even if edit the commit to "Improve the security of WindowsDllDetourPatcher" as Dan suggested.


Which older supported branches are affected by this flaw?

Lots of them. This code goes back a couple years.


Do you have backports for the affected branches? If not, how different, hard to create, and risky will they be?

Backporting to esr52 won't be difficult. Other than that, no, as 54 was indicated 'wontfix'. 


How likely is this patch to cause regressions; how much testing does it need?

Medium likely, just because we really shouldn't see any problems with adding the assembly check, but I wouldn't be too surprised if there was some crazy case we hadn't considered. Perhaps we should change this from 'continue' to an assert.



If people agree I'll update the patch
 - Use asserts instead of continues to fast-crash
 - Trim the commit message to 'Improve the security of WindowsDllDetourPatcher'


LMK!
Attachment #8877731 - Flags: sec-approval?
(In reply to Tom Ritter [:tjr] from comment #16)
> If people agree I'll update the patch
>  - Use asserts instead of continues to fast-crash

I think I'm okay with the continue. Most (all?) of our interceptors are statics that stay alive for the entire process. If there's badness happening, an assert wouldn't fire in time to be of much benefit. And it might lead to unactionable crash reports if our hooks collide with some injected AV or something.

>  - Trim the commit message to 'Improve the security of WindowsDllDetourPatcher'

Ok.
sec-approval+ for checkin on trunk the week of July 3, three weeks into the current cycle.
We'll want beta and ESR52 patches nominated and approved to go in after it lands on trunk.
Whiteboard: [checkin on 7/3]
Attachment #8877731 - Flags: sec-approval? → sec-approval+
Attached patch 1372849.patchSplinter Review
Update patch commit message
Attachment #8877731 - Attachment is obsolete: true
*Nudge*
Is this ready to land?
https://hg.mozilla.org/integration/mozilla-inbound/rev/87cf3117088c9d2f613ebd1f916c1d55b9c91458

This grafts cleanly to Beta but will need a rebased patch for ESR52. And some approval nominations too when you get a chance :)
Flags: needinfo?(tom)
Whiteboard: [checkin on 7/3]
https://hg.mozilla.org/mozilla-central/rev/87cf3117088c
Status: NEW → RESOLVED
Closed: 7 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla56
Added patch rebased for esr52
Flags: needinfo?(tom) → needinfo?(ryanvm)
Comment on attachment 8883916 [details] [diff] [review]
1372849-esr52.patch

[Approval Request Comment]
If this is not a sec:{high,crit} bug, please state case for ESR consideration: This is sec-high

User impact if declined: ESR users will be vulnerable to an exploit writing mechanism that is fixed on release.

Fix Landed on Version: 56

Risk to taking this patch (and alternatives if risky): The browser on Windows crashes. I believe this would happen reliably.

String or UUID changes made by this patch: None.

See https://wiki.mozilla.org/Release_Management/ESR_Landing_Process for more info.
Attachment #8883916 - Flags: approval-mozilla-esr52?
Flags: needinfo?(ryanvm)
Attachment #8879247 - Flags: approval-mozilla-beta?
Comment on attachment 8883916 [details] [diff] [review]
1372849-esr52.patch

Sec-high, ESR52+
Attachment #8883916 - Flags: approval-mozilla-esr52? → approval-mozilla-esr52+
Comment on attachment 8879247 [details] [diff] [review]
1372849.patch

Sec-high, Beta55+
Attachment #8879247 - Flags: approval-mozilla-beta? → approval-mozilla-beta+
Group: dom-core-security → core-security-release
Alias: CVE-2017-7804
Whiteboard: [adv-main55+][adv-esr52.3+]
Flags: qe-verify-
Whiteboard: [adv-main55+][adv-esr52.3+] → [adv-main55+][adv-esr52.3+][post-critsmash-triage]
Group: core-security-release
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: