Friday, February 21, 2020

Our First Weeks of Securing Windows 7 and Windows Server 2008 R2

A quick status update

by Mitja Kolsek, the 0patch Team

[Update 2/22/2020: More details on the exploit code for CVE-2020-0674 were published, making exploitation by new malicious actors more likely.]

Hi 0patch users and supporters around the globe!

With February 2020 Patch Tuesday we began our three-year journey of providing critical security micropatches for Windows 7 and Windows Server 2008 R2 to our users, who could not - or decided not to - use Microsoft's Extended Security Updates.


Status of Windows 7 and Windows Server 2008 R2 micropatches



This first Patch Tuesday brought a large number of security fixes for these platforms, and we've set up a status page for public tracking of our progress on providing associated micropatches, which you can always find at this address:

Status of Windows 7 and Windows Server 2008 R2 micropatches

As you know, it is not our goal to provide micropatches for all vulnerabilities fixed by Microsoft - instead, our goal is to provide micropatches for high-risk vulnerabilities: those that are likely to get exploited (e.g., because details are published), that allow for a remote attack (e.g., through visiting a malicious web page, or opening a malicious email or document). This doesn't mean we won't micropatch publicly detailed local privilege escalation issues, but they will have a lower priority.


Improved Micropatch for CVE-2020-0674


You will remember that after January Patch Tuesday, Microsoft issued an advisory about a remotely exploitable vulnerability in Scripting Engine CVE-2020-0674 that was detected as being used in the wild. There was no official patch from Microsoft and their workaround had some unpleasant side effects, so we stepped in and created a micropatch without such side effects. Both the workaround and our micropatch did prevent functioning of legacy JScript code, so any web page still using it (and we hear from our enterprise users that JScript is still very much alive in internal corporate web applications) would not work properly.

As expected, Microsoft fixed this issue with February Patch Tuesday, but not for Windows 7 and Windows Server 2008 R2 users without Extended Security Updates. In addition, the original reporters of this issue, a Chinese security company Qihoo 360, published a technical article which provided sufficient information about the vulnerability that anyone skilled in this game could easily reproduce it. The latter changed our risk assessment - before the exploitation was limited, but now anyone motivated can build an exploit and start targeting vulnerable Windows computers.

And there are at least as many vulnerable Windows computers out there as there are Windows 7 computers without Extended Security Updates.

So we reproduced the issue and traced the root cause to JScript function sort(), specifically when called using a sorting function, and its binary code implementation in function JsArrayFunctionHeapSort.  This function has changed significantly with February updates, but so have many, many others, and we know from previous analyses of jscript.dll that many of these changes are not security related. (One is impressed with how much development effort Microsoft continues to invest in this legacy scripting engine.)

While we understood what the root cause of the issue was and knew what had to be done to fix it, we did not find a sufficiently risk-free method of doing it, at least not yet, and thus decided on a compromise: we would remove the exploitable part of sort()'s functionality, effectively causing

array.sort(sortfunction)

to become

array.sort()


It was our assessment that this change should not have a significant impact on majority of web applications using JScript. (If any 0patch users do experience a significant impact, please contact support@0patch.com!)

Our primary target for this micropatch were Windows 7 and Windows Server 2008 R2 computers, for which we also revoked our initial "workaround" micropatch. However, we subsequently learned that February Windows Updates were causing severe problems for Windows 10 v1903/v1909 users, prompting many of them to likely delay or forgo applying of these updates. Since that would leave them vulnerable to CVE-2020-0674, we ported our micropatch to Windows 10 v1903/v1909 as well (and revoked the associated "workaround" micropatch).


Online Test For 0patch Users


Once we had micropatched this web-deliverable vulnerability, we were able to construct an online test for all our 0patch users to check whether the micropatch is getting properly applied. This is particularly important for Windows 7 and Windows Server 2008 R2 users, who need to have their computers fully updated in order for our post-end-of-service micropatches to apply.





The online test page is located here:

https://0patch.com/poc/CVE-2020-0674/0patch_test.html

To use it, you have to visit it with Internet Explorer 11; Internet Explorer is the only browser using jscript.dll, and we only provided a micropatch for version 11 as this is the only still-supported version on Windows 7 and Server 2008.

Once you open the test page, you will see one of the following:






This means everything is okay; your computer is properly updated for 0patch, and 0patch has applied the micropatch for CVE-2020-0674 to your Internet Explorer, making you not-vulnerable.






This message indicates that our micropatch did not get applied. You may have not applied the January 2020 rollup update on your computer, or are using Internet Explorer version other than 11. Or, you may be on Extended Security Updates, in which case this test doesn't apply to you.

Go ahead, use this test and let us know (support@0patch.com) if our micropatch isn't getting applied.



What's Next?



Being that CVE-2020-0674 was the only remote code execution vulnerability with a published proof of concept, micropatching it was our priority. There are a couple of other issues in our status table that are already making us busy with either recreating a proof-of-concept or already analyzing the vulnerability, but there is one issue that stands out: the LNK vulnerability (CVE-2020-0729), which has "massive exploitation" written all over it. It also reportedly has a proof-of-concept successfully reproduced in the security research community, so once those details are available, we'll have to respond quickly to protect our users.

Cheers!

@mkolsek
@0patch






Monday, February 10, 2020

Letter To 0patch Users (February 10, 2020)


Subject: 0patch - What you need to know about Windows 7 and Windows Server 2008 R2 security micropatches


Dear 0patch user,

Thank you for putting your trust in 0patch to supply your computers with security micropatches. Tomorrow is the first Patch Tuesday when Windows 7 and Windows Server 2008 R2 systems that aren't registered for Microsoft's Extended Security Updates will not receive official Windows security patches, and instead depend on us to provide security micropatches for the most critical vulnerabilities.

We'd like to set your expectations and help you stay well-informed during our journey.

Whenever we become aware of a critical vulnerability affecting Windows 7 or Windows Server 2008 R2 (whether through Microsoft issuing a patch for it, or from any other source), we'll create an article for that vulnerability on our Support site (https://0patch.zendesk.com) that will provide information such as:

    - CVE ID
    - Our own risk assessment (with explanation)
    - Status of our micropatch (e.g., "in development", "waiting for test case", "issued")
    - Possible (and reported) side effects of our micropatch
    - Workarounds (for when micropatch is not available, or if you don't want to apply it)
    - Frequently asked questions
    - Links to our own and external articles related to this issue
    - Procedure for testing our micropatch (optionally)
    - Credits to people helping us with the micropatch

We will continually update these articles as new information gets available.

We will also start sending Patch Tuesday updates and alerts about issued micropatches to "0patch News" mailing list (newsletter) so we highly recommend you subscribe to it to know which vulnerabilities we have micropatched and whether we recommend applying any workarounds for issues we can't (yet) micropatch.

To subscribe to "0patch News", visit https://0patch.com/contact.html, provide your email address to the form on the right side, tick the "0patch Newsletter" box and press Subscribe.

We will make our best effort to provide users will timely, accurate, and actionable information for keeping their Windows 7 and Windows Server 2008 R2 systems as secure as possible.

Thank you again,

Mitja Kolsek
0patch co-founder

Tuesday, January 21, 2020

Micropatching a Workaround for CVE-2020-0674

A Kill Switch for Vulnerable jscript.dll

by Mitja Kolsek, the 0patch Team





Last Friday, Microsoft published an advisory about a remotely exploitable memory corruption vulnerability (CVE-2020-0674) that was reported to them by Qihoo 360 as being exploited in the wild. These attacks were reportedly limited so Microsoft decided not to rush with issuing a patch but will rather provide one as part of February's Patch Tuesday. They did, however, provide a workaround.

Because the provided workaround has multiple negative side effects, and because it is likely that Windows 7 and Windows Server 2008 R2 users without Extended Security Updates will not get the patch at all (their support ended this month), we decided to provide a micropatch that simulates the workaround without its negative side effects.

The vulnerability is in jscript.dll, which is the scripting engine for legacy JScript code; note that all "non-legacy" JScript code (whatever that might be), and all JavaScript code gets executed by the newer scripting engine implemented in jscript9.dll.

Microsoft's workaround comprises setting permissions on jscript.dll such that nobody will be able to read it. This workaround has an expected negative side effect that if you're using a web application that employs legacy JScript (and can as such only be used with Internet Explorer), this application will no longer work in your browser.

There also several other negative side effects:

Microsoft's advisory states that the provided workaround will have to be reverted when they issue a patch for jscript.dll. However, note that some additional side effects may result from changing the ownership on jscript.dll (from TrustedInstaller to the user you're implementing the workaround as).


Test Case


Finding a test case that triggers the loading of jscript.dll was not difficult - Google Project Zero has one published in an advisory from November last year. (It won't be at all surprising if the vulnerability at hand is either a clone of that one, or a bypass for its patch - but we'll know soon enough.)

So we took Google's example, simplified it to only cause the loading of jscript.dll for executing a single alert call. Note the important part is to specify JScript.Encode as language. (By the way, read the Wikipedia article on JScript.Encode for a primer on how to underestimate intelligent adversaries.)


<html>
<head>
 <meta http-equiv="X-UA-Compatible" content="IE=8"></meta>
</head>
<body>
<script language="Jscript.Encode">
 alert("jscript.dll was loaded");
</script>
</body>
</html>


The test was then simple: opening this file in IE without mitigation or patch should result in a popup saying "jscript.dll was loaded". With a patch, we would want the loading of jscript.dll to fail and consequently no popup to appear. Ideally, in a graceful manner without any ugly error messages or crashed processes.

Analysis


Sabotaging some functionality is usually a simple thing to do with a micropatch: you locate the code that implements or initializes said functionality, and make it fail. This was a case here too.

We first used Process Monitor to locate the code in Internet Explorer which loads jscript.dll. This was trivial as Process Monitor records a call stack for every operation, and it was obvious that mshtml.dll causes the loading of jscript.dll through a call to CoCreateInstance.


lea     eax,[esp+3Ch]
xor     edi,edi
push    eax
push    offset MSHTML!_GUID_bb1a2ae1_a4f9_11cf_8f20_00805f2cd064 (631bf2a8)
push    1
push    edi
lea     eax,[esp+0B4h]
push    eax
call    dword ptr [MSHTML!_imp__CoCreateInstance (641c301c)]
mov     ebx,eax
test    ebx,ebx


When this code is reached as a result of rendering a Jscript.Encode script block, the first argument (the last one pushed to the stack) points to a ClassID f414c262-6ac0-11cf-b6d1-00aa00bbbb58, which instantiates a jscript.dll object.

Great, could we just sabotage this call and be done with it? Unfortunately not; this same function is being used for instantiating other objects as well, so we need to be selective here.

We decided to make a micropatch that checks, before the call to CoCreateInstance is made, whether its first argument equals f414c262-6ac0-11cf-b6d1-00aa00bbbb58, and if so, sabotages the call by setting its last argument (pvv) to NULL, causing CoCreateInstance to return error 0x80070057 (E_INVALIDARG). This has the same effect as making jscript.dll impossible to read.

But before settling with that, we wanted to check if there were any other ways in which a malicious web page could have code executed by jscript.dll. So we scanned the Registry for all ClassIDs associated with jscript.dll that were loadable via a script tag - and found Jscript.Compact to be such an alternative. So we made another HTML test file:


<html>
<head>
 <meta http-equiv="X-UA-Compatible" content="IE=8"></meta>
</head>
<body>
<script language="Jscript.Compact">
 alert("jscript.dll was loaded");
</script>
</body>
</html>


And sure enough, this one also executed the alert with jscript.dll.We therefore had to add another ClassID check to our micropatch, also preventing cc5bbec3-db4a-4bed-828d-08d78ee3e1ed from getting instantiated.

The final micropatch then became:


MODULE_PATH "..\Affected_Modules\mshtml.dll_11.0.17763.831_32bit\mshtml.dll"
PATCH_ID 1000004
PATCH_FORMAT_VER 2
VULN_ID 5897
PLATFORM win32

patchlet_start
PATCHLET_ID 1
PATCHLET_TYPE 2

PATCHLET_OFFSET 0x3bcf36
N_ORIGINALBYTES 5

code_start

  ; At this point, ClassID is stored at address pointed to by [esp+0ACh]
  ; If we want to sabotage the call, we put 0 at [esp+0ch] (argument ppv), which
  ; will cause error 0x80070057 (E_INVALIDARG)

  ; Compare ClassID with f414c262-6ac0-11cf-b6d1-00aa00bbbb58 (Jscript.Encode)
  cmp dword [esp + 0ACh], 0xf414c262
  jne skip1
  cmp dword [esp + 0ACh + 4h], 0x11cf6ac0
  jne skip1
  cmp dword [esp + 0ACh + 8h], 0xaa00d1b6
  jne skip1
  cmp dword [esp + 0ACh + 0Ch], 0x58bbbb00
  jne skip1
 
  mov dword [esp + 0xc], 0 ; Sabotage the call to CoCreateInstance by setting ppv to 0
 
 skip1:

 ; Compare ClassID with cc5bbec3-db4a-4bed-828d-08d78ee3e1ed (Jscript.Compact)
  cmp dword [esp + 0ACh], 0xcc5bbec3
  jne skip2
  cmp dword [esp + 0ACh + 4h], 0x4beddb4a
  jne skip2
  cmp dword [esp + 0ACh + 8h], 0xd7088d82
  jne skip2
  cmp dword [esp + 0ACh + 0Ch], 0xede1e38e
  jne skip2
 
  mov dword [esp + 0xc], 0 ; Sabotage the call to CoCreateInstance by setting ppv to 0
 
 skip2:

code_end
patchlet_end


We ported this micropatch to the following platforms, both 32-bit and 64-bit:

  • Windows 7,
  • Windows 10 v1709,
  • Windows 10 v1803, 
  • Windows 10 v1809, 
  • Windows 10 v1903, [issued on 1/30/2020]
  • Windows 10 v1909, [issued on 1/30/2020]
  • Windows Server 2008 R2, 
  • Windows Server 2019 

If you're a 0patch user, you already have this micropatch downloaded to all your online computers with 0patch Agent, and - depending on your settings - already automatically applied to all processes using the Internet Explorer 11 engine for rendering content. This includes Internet Explorer (obviously), Microsoft Word, Microsoft Outlook, and a variety of other applications.

As all our micropatches, you can switch this micropatch on or off and have it instantly applied to, or removed from running applications - effectively making it a "kill switch" for jscript.dll.

If you're using other Windows versions or older Internet Explorer versions and are interested in having this micropatch ported to your systems, please contact us at sales@0patch.com.


Video


Here's our micropatch in action:






Frequently Asked Questions


Q: Why would we apply your micropatch instead of Microsoft's recommended workaround?

Our micropatch is designed to avoid negative side effects of Microsoft's workaround (see above). It can also be easily reverted (un-applied) with a switch of a button without leaving any traces, while the workaround changes the ownership on jscript.dll.


Q: Will Microsoft provide a patch for CVE-2020-0674 to Windows 7 and Windows Server 2008 R2 users without Extended Security Updates?

We don't know but these systems are now officially out of support and Microsoft has historically only issued security patches for unsupported systems in extreme cases (e.g., the Shadow Brokers leak, or BlueKeep / CVE-2019-0708).

We at 0patch have committed to provide post-end-of-service security micropatches for Windows 7 and Windows Server 2008 R2 for three additional years, which is why we're also issuing this micropatch for these platforms. (Read FAQ for more information.)


Q: What will happen if I apply your micropatch, and then apply Microsoft's patch for CVE-2020-0674 when it comes out?

When Microsoft issues a patch for this vulnerability, we'll inspect it and decide whether to replace our current micropatch (which resides in mshtml.dll and disables jscript.dll entirely) with a more targeted micropatch in jscript.dll (which will only fix that vulnerability but keep jscript.dll available). It might happen that we do so on supported Windows platforms but keep the current micropatch on Windows 7 and Windows Server 2008 R2. This also depends on user feedback (i.e., whether our micropatch causes anyone problems).

In any case, you won't have to do anything - Microsoft's patch will have precedence over our micropatch.


Q: I suspect your micropatch is causing problems on my computer. What should I do?

Make a quick test: Disable 0patch Agent and execute your affected process - if the problem is still there, it's unlikely the cause of your problem is our micropatch. However, if your problem goes away, please report that to support@0patch.com and temporarily disable micropatches 402-405 on your 0patch Agent.

Users on the Enterprise plan can enable and disable individual patches centrally through 0patch Central.


Q: Are there any applications using jscript.dll directly (not though Internet Explorer browser component) that could still be used as attack vector?

We're aware of one - Windows Media Player (WMP) uses jscript.dll directly and will still be able to do so when our micropatch is applied. WMP allows displaying a remote web site when playing certain files but the user has to confirm a security warning for that. This was the reason we decided not to micropatch WMP as well.


Q: How can I deploy this micropatch in my organization's network?

Contact sales@0patch.com for our Enterprise offering (including central management, setting patching policies, group management etc.). We'll set you up with some trial licenses and technical support for making your deployment smooth and quick.


Cheers!

@mkolsek
@0patch








Monday, January 6, 2020

0patch Central: We are Now Ready to Micropatch Your Enterprise

0patch Central, our central management solution, is now ready to accept first users 

 

by Stanka Salamun, the 0patch Team



At 0patch, we are on the mission to make your security patching virtually imperceptible:

  • We patch your most critical 0days.
  • We buy you time by protecting you with micropatches while you test official vendor updates.
  • We secure your unsupported products after they lose their vendors' support (Windows 7 and Windows Server 2008).

We do it in the most convenient way you've ever experienced: you don't need to reboot computers or restart applications, you can switch off a potentially problematic patch (and later switch it on again), our micropatches are so tiny that most could be published in a single tweet. They are delivered and applied within an hour of their publication, without any activity on user's or administrator's part. Needless to say, we don't tinker with functionality of your applications: we don't change, add or remove anything (unless it's vulnerable and we can't repair it any other way).
  
But one of the most common questions we've been receiving from our users lately was: when will your remote central management be ready for enterprises? We are excited to inform you that 0patch Central, our cloud-based enterprise management solution, is now ready to accept first users, and you're invited!

This is a big thing for us, and for all enterprise users asking for central management of their 0patch Agents. If you have a non-trivial fleet of Windows computers to protect with our micropatches, 0patch Central is your central management solution.

What can you do with 0patch Agents remotely?

  • You can make them completely silent for end users.
  • You can organize them into groups and subgroups.
  • You can move them between groups (which will change their patching policy to the destination group's).
  • You can enable or disable them.
  • You can update them to the latest version.
  • You can delete them. (But no worries, you can also bring them back.)
  • For each group you can define patches that are enabled or disabled. You can even do that for individual computers, remotely. 


And how do you set up patching policy in 0patch Central? 

0patch Central - "All Computers" group

 

Let's look at two frequent scenarios:


Scenario 1: The traditional enterprise "Test in a small group before deployment" setup

1) Open the root All Computers group, open the Settings tab, and set Default state for new patches to "Disabled" - this will result in all newly arrived patches being disabled on all computers in this group.

2) Create a subgroup called Testing, open its Settings tab, and set Default state for new patches to "Enabled" - this will result in all newly arrived patches being enabled on all computers in trhis group.

3) Select and move your testing machines from the All Computers group to the Testing group - these computers will get all newly downloaded patches immediately applied.

4) When you decide that some patch has been sufficiently tested on computers in the Testing group for network-wide deployment, open the All Computers group, Patches tab, locate the patch and set it to "Enabled"


Scenario 2: The "I don't have time for this, just micropatch my 0days immediately" setup

1) Open the root All Computers group, open the Settings tab, and set Default state for new patches to "Enabled" - this will result in all newly arrived patches being immediately enabled on all computers.




You'll find 0patch Central at address https://central.0patch.com, where you can login with your existing 0patch credentials, or register a new account. In case you don't have a 0patch account yet, just register a new account at https://central.0patch.com/auth/register. When you have your 0patch account ready, let us know at support@0patch.com which email address you used so we can issue some trial PRO licenses and turn on the "Enterprise" switch for you. This will allow you to access all Enterprise features such as organizing agents into groups and setting patching policy for each individual group.

If you apply for your Enterprise trial while we are still in "Early Access" you will get your 0patch Enterprise licenses for the price of 0patch PRO for your first yearly subscription. But do not wait too long as we are closing "Early Access" just before Q2 2020 starts.


Important! Remote management only works with our just-released 0patch Agent version (19.11.15.10650) so while you will be able to see your older agents in 0patch Central, you won't be able to do anything with them. To resolve this, please manually update all existing agents to the latest version and make sure to only use the latest agent version for all future installs. All subsequent agent updates will from then on be manageable from 0patch Central.

We tried to design 0patch Central intuitively and with minimal complexity, and hope you won't be needing much help using it. But we're not fooling ourselves. You'll surely have questions and we're anxiously waiting for you at support@0patch.com. Don't hesitate to ask or suggest anything as we want to make 0patch Central a tool that will make your patching life as easy as possible. If something is not obvious to you, it's probably not obvious to others as well, so do let us know about it.



We had to focus on enterprise features first, but next items on our to-do list will be to make life much easier for MSPs and VARs.

Welcome to 0patch Central, we hope it'll serve you well and become your effective little patching assistant!


Friday, September 20, 2019

Micropatching Keeps Windows 7 and Windows Server 2008 Secure After Their End-Of-Support

Becoming an Adoptive Parent For Abandoned Windows

by Mitja Kolsek, the 0patch Team





Hello people, it's nice to step out for a moment and see the daylight. Those of you following us have noticed our near radio silence in the past months. To stop you from worrying I'd like to just quickly update you all on what's going on inside our walls (spoiler: a lot) and what our plans are (spoiler: big).

As you know, Windows 7 and Windows Server 2008 are reaching their end-of-support on January 14 next year, which is causing a lot of headaches for people and companies who are entirely happy with the way these OSs work, or have compatibility requirements preventing them from upgrading. If they want to keep receiving security fixes, their options are: (a) to upgrade to Windows 10 and a newer server version, or (b) to buy Extended Security Updates from Microsoft (conditions apply, and 3rd party patch management solutions cannot be used for delivery).

NetMarketShare shows that last month, 5 months before end-of-support, 30% of desktop OSs were running Windows 7. With the current upgrading trend, we can safely forecast that the number of Windows 7 machines on February 11, 2020 (the first Patch Tuesday to exclude them) will be approximately somewhere between huge and vast. There are few public stats on how Windows Server 2008 is doing but judging from what our users are saying, it's not going to get extinct anytime soon.
 
You see where we're going with this. Back in January 2018, we at 0patch "security-adopted" Microsoft Office Equation Editor, a program integrated into Microsoft Word with which scientists, teachers and students had written millions of equations. They were all suddenly left without a way to edit their equations when Microsoft decided to delete Equation Editor from their computers.

What we did was create micropatches for all known Equation Editor vulnerabilities and made instructions for users to bring back Equation Editor on their computers so they could continue using it while keeping Office regularly updated with Microsoft's security patches.

But that was just a trial run for becoming an adoptive parent of a vendor-abandoned product. This time we're going bigger: we're going to security-adopt Windows 7 and Windows Server 2008 for those of you who want to keep them patched after their official security updates have dried out.

What does this mean, exactly?

It means that after the last official security update has been issued for Windows 7 and Windows Server 2008 in January 2020, we'll start doing the following:

  1. Each Patch Tuesday we'll review Microsoft's security advisories to determine which of the vulnerabilities they have fixed for supported Windows versions might apply to Windows 7 or Windows Server 2008 and present a high-enough risk to warrant micropatching.
  2. For the identified high-risk vulnerabilities we'll inspect Windows Updates for supported Windows versions (e.g., Windows 10) to confirm whether the vulnerable code that was fixed in Windows 10 is actually present on Windows 7 or Windows Server 2008. (For all intents and purposes, such vulnerabilities will be considered 0days for these OSs.)
  3. If the high-risk vulnerable code is found to be present on Windows 7 or Windows Server 2008, we'll start a process of obtaining a proof-of-concept (POC) for triggering the vulnerability. Sometimes a POC is published by security researchers soon after the official vendor fix is out (and sometimes even before); other times we can get one from our partner network or threat intelligence sources; occasionally researchers share a POC with us privately; and sometimes we have to create a POC ourselves by analyzing the official patch and working our way out towards the input data that steers the execution to the vulnerability.
  4. Once we have a POC and know how the vulnerability was fixed by the people who know the vulnerable code best (i.e., Microsoft developers), we'll port their fix, functionally speaking, as a series of micropatches to the vulnerable code in Windows 7 and Windows Server 2008, and test them against the POC. After additional side-effect testing we'll publish the micropatches and have them delivered to users' online machines within 60 minutes. (Which by the way means that many Windows 7 and Windows Server 2008 will be patched sooner than those with still-supported Windows versions where organizations will continue to prudently test Windows updates for days or weeks before having them applied to all computers.)

We expected you might have questions at this point; please see our FAQ about Windows 7 and Windows Server 2008 Post-End-of-Support Security Micropatches

Okay - but what are we so busy with now? A lot of things:
 
Firstly, in order for large organizations to be able to use 0patch efficiently, we're developing a central management service (think WSUS for 0patch, but nice and fast) which will allow admins to organize computers in groups and apply different policies to these groups. Admins will thus be able to set up "testing" groups where new micropatches will be applied immediately, and subsequently have them applied to the rest of their computers with a few clicks (and of course, without users ever noticing anything). Naturally they'll also be able to un-apply any micropatches just as easily and quickly should they choose to. There will be alerts, graphs, reports, and drill-downs, and the very next step will be an on-premises version of 0patch server which so many organizations are asking for.

Secondly, we're growing our team: things are buzzing in our 0patch bootcamp and a nice side effect of passing one's knowledge onto others is that one has to neatly organize and document it. Consequently, adding further new members to the team afterwards will be even smoother and quicker.

Lastly, we're enhancing our reversing, patch analysis, vulnerability analysis, micropatch development and micropatch porting processes with new tools and techniques. Suffice to say that we've never had as many disassemblers, debuggers, decompilers, plugins and concurrently opened reversing projects running as we have now. But the thing I'm personally most excited about is our introduction of symbolic execution in micropatch creation, verification and porting processes. We've been aiming for eventual formal verification of our micropatches since the beginning and we're finally working on that. But not only that: symbolic execution and emulation will help us avoid errors sooner during micropatch development and allow us to perform unit testing against micropatched code even before we have a POC. Goosebumps!

This concludes our news from the 0patch lab. If you're interested in getting early access to 0patch central management (in November), or have any questions about our service, please consult Frequently Asked Questions or send an email to sales@0patch.com.


Cheers!

@mkolsek
@0patch

Tuesday, June 4, 2019

Another Task Scheduler 0day, Another Task Scheduler Micropatch (The SandboxEscaper Saga)

Backward Compatibility is Hard, and so is Stacked Impersonation

by Simon Raner and Mitja Kolsek, the 0patch Team








[Update 6/12/2019: Yesterday's Windows Updates include a fix for this vulnerability, 12 days after our micropatch has been released. The issue was assigned CVE-2019-1069.]

Last August we issued a micropatch for a local privilege escalation 0day in Task Scheduler, published by SandboxEscaper. The vulnerability allowed a local attacker on a Windows machine to change permissions of any chosen file, including system executables, such that the attacker would subsequently be able to modify that file. This obviously allowed for privilege escalation, although many system files can't be changed even with suitable permissions either due to being owned by TrustedInstaller or due to being in use. Nevertheless, at least one such file can always be found.

Fast forward to last week. SandboxEscaper has dropped three Windows 0days, one of which is again a local privilege escalation in Task Scheduler. We tested it and it worked on a fully patched Windows 10 machine. According to Will Dormann of CERT/CC, the exploit "functions reliably on 32- and 64-bit Windows 10 platforms, as well as Windows Server 2016 and Windows Server 2019. While Windows 8 still contains this vulnerability, exploitation using the publicly-described technique is limited to files where the current user has write access, in our testing. As such, the impact on Windows 8 systems using the technique used by the public exploit appears to be negligible. We have not been able to demonstrate the vulnerability on Windows 7 systems."


Analysis


Analysis always starts with reproducing the POC.  It comes as a Windows executable that takes two arguments, username and password of a local low-privileged user. Let's see what it does when we run it as a low-privileged user test:


C:\Temp\Vuln-5172_bearlpe\Exploit>whoami
0p-win-10-ent-3\test


C:\Temp\Vuln-5172_bearlpe\Exploit>icacls "c:\Windows\system32\drivers\pci.sys"
c:\Windows\system32\drivers\pci.sys NT AUTHORITY\SYSTEM:(I)(F)
                                    BUILTIN\Administrators:(I)(F)
                                    BUILTIN\Users:(I)(RX)
                                    APPLICATION PACKAGE AUTHORITY\ALL APPLICATION PACKAGES:(I)(RX)
                                    APPLICATION PACKAGE AUTHORITY\ALL RESTRICTED APP PACKAGES:(I)(RX)

Successfully processed 1 files; Failed processing 0 files


C:\Temp\Vuln-5172_bearlpe\Exploit>polarbear.exe test test
SUCCESS: The parameters of scheduled task "bear" have been changed.
SUCCESS: The parameters of scheduled task "bear" have been changed.


C:\Temp\Vuln-5172_bearlpe\Exploit>icacls "c:\Windows\system32\drivers\pci.sys"
c:\Windows\system32\drivers\pci.sys NT AUTHORITY\SYSTEM:(Rc,S,X,RA)
                                    0P-WIN-10-ENT-3\test:(R)
                                    BUILTIN\Administrators:(I)(R,W,D,WDAC,WO)
                                    NT AUTHORITY\SYSTEM:(I)(R,W,D,WDAC,WO)
                                    0P-WIN-10-ENT-3\test:(I)(F)
                             
Successfully processed 1 files; Failed processing 0 files



Obviously, the POC was able to change permissions on pci.sys. Furthermore, in contrast to the last year's Task Scheduler 0day we had micropatched, this one also changed the ownership of the target file; not being owned by TrustedInstaller any more, pci.sys could be modified freely by the attacker.

Its operation is fairly simple; when launched with credentials of a low-privileged user test with password test, the POC performs these steps (as seen from its source code):

  1. Copy file bear.job to c:\windows\tasks\bear.job
  2. Execute schtasks.exe /change /TN \"bear\" /RU test /RP test
    (This instructs Task Scheduler to take bear.job created above and create a new scheduled tasks - resulting in a new file c:\windows\system32\tasks\Bear. Note that a legacy schtasks.exe from Windows XP is used, which uses legacy RPC interface for that.)
  3. Delete  c:\windows\system32\tasks\Bear.
  4. Create a hard link c:\windows\system32\tasks\Bear, pointing to system file c:\windows\system32\drivers\pci.sys.
  5. Again, execute schtasks.exe /change /TN \"bear\" /RU test /RP test
    (This time, since the task already exists, Task Scheduler sets full permissions and ownership for user test on the task file. Since the task file is actually a hard link to pci.sys, it apparently changes permissions and ownership on that file.)

Observing operations against c:\windows\system32\tasks\Bear with Process Monitor during POC execution told us more:





Apparently, there were two SetSecurityFile operations performed on the file, with the following call stacks:







Both of these SetSecurityFile operations stem from function _SchRpcSetSecurity in schedsvc.dll, and based on our prior experience with Task Manager's impersonation issues we assumed this function was responsible for calling SetSecurityInfo without proper impersonation. Next step: debugger.

We set a breakpoint at _SchRpcSetSecurity and traced its execution towards the call to SetSecurityInfo - its first call being made from function SetJobFileSecurityByName. Therein, before the call to SetSecurityInfo was made, we checked the thread's access token, expecting it to be not-impersonated.


0:030> !token
TS Session ID: 0
User: S-1-5-18 

... 
Privs:
 ...
 14 0x000000012 SeRestorePrivilege                Attributes - Enabled
 ...
Impersonation Level: Impersonation
...


But surprise! The token was impersonated. Only the user it was impersonating was not the attacker's user test, but Local System (S-1-5-18). What was going on?

Was function _SchRpcSetSecurity broken and incorrectly impersonated the caller? We found an impersonation call in it and it looked okay. Clearly we needed to understand this function better, and it's natural to start with the documentation when available. The specification of function  _SchRpcSetSecurity describes its behavior in detail, including this step that is relevant for our analysis (the path parameter being the Bear file in our case.):
 


This makes sense: if someone asks Task Scheduler to change permissions on a task file, said someone should have write permissions on that file. A typical use case for this is when the user who created a task subsequently decides to have that task executed as some other user, which requires that user to have at least read access to the task file. And this is also the use case triggered by the schtasks.exe's /change option, where /RU and /RP parameters specify the "run-as" user's credentials.

We then reverse engineered _SchRpcSetSecurity to find where this security check is implemented and find out why it doesn't work as specified.

Except we found that it does work as specified: the code attempts to open the Bear file with permissions to change its DACL and its owner - and if that succeeds, actually does that. Which would work great if only it was impersonating the low-privileged attacker instead of Local System (who obviously can do all that on the linked-to pci.sys file).

So why didn't the function impersonate the attacker? After some head-scratching, we remembered that this attack only works with the legacy schtasks.exe, and not with the new one. Could it be that the old schtasks.exe was calling some other RPC function than _SchRpcSetSecurity, which then in turn called _SchRpcSetSecurity via RPC? While still paused inside the _SchRpcSetSecurity call, we looked at other threads in the same process - and found an interesting one with this call stack:



0:037> k
ChildEBP RetAddr 
08d1dbf4 775e058a ntdll!KiFastSystemCallRet
08d1dbf8 76e35bde ntdll!NtAlpcSendWaitReceivePort+0xa
08d1dc88 76e359f4 RPCRT4!LRPC_BASE_CCALL::DoSendReceive+0xde
08d1dca4 76e156dc RPCRT4!LRPC_CCALL::SendReceive+0x54
08d1e118 6ff9fa7a RPCRT4!NdrClientCall2+0xa4c
08d1e130 6ffbd524 taskcomp!SchRpcSetSecurity+0x24
08d1e17c 6ffa8536 taskcomp!RpcSession::SetSecurity+0x25
08d1ecd0 6ffa8669 taskcomp!CompatibilityAdapter::Register+0xef4
08d1ed00 6ffb13a9 taskcomp!CompatibilityAdapter::RegisterWithRetry+0x28
08d1f1f4 76e67544 taskcomp!SASetAccountInformation+0x4a9
08d1f21c 76e1665d RPCRT4!Invoke+0x34
08d1f688 76e17399 RPCRT4!NdrStubCall2+0x86d
08d1f6a4 76e48712 RPCRT4!NdrServerCall2+0x19
08d1f6e4 76e4832b RPCRT4!DispatchToStubInCNoAvrf+0x52
08d1f758 76e47d6f RPCRT4!RPC_INTERFACE::DispatchToStubWorker+0x17b
08d1f78c 76e36b6f RPCRT4!RPC_INTERFACE::DispatchToStub+0x8f
08d1f7f4 76e37e4d RPCRT4!LRPC_SCALL::DispatchRequest+0x2ef
08d1f884 76e37915 RPCRT4!LRPC_SCALL::HandleRequest+0x37d
08d1f8d0 76e36501 RPCRT4!LRPC_ADDRESS::HandleRequest+0x325
08d1f9a8 76e324e6 RPCRT4!LRPC_ADDRESS::ProcessIO+0x211
08d1f9e8 775827f8 RPCRT4!LrpcIoComplete+0xa6
08d1fa20 775819da ntdll!TppAlpcpExecuteCallback+0x188
08d1fbe8 74d7e529 ntdll!TppWorkerThread+0x3da
08d1fbf8 775a9ed1 KERNEL32!BaseThreadInitThunk+0x19
08d1fc54 775a9ea5 ntdll!__RtlUserThreadStart+0x2b
08d1fc64 00000000 ntdll!_RtlUserThreadStart+0x1b


Hmm, a thread in taskcomp.dll, which was itself triggered via an RPC call (as suggested by RPCRT4!Invoke) called a function named SchRpcSetSecurity, which invoked another RPC call (as suggested by RPCRT4!NdrClientCall2), and was now waiting for it to return. A few debugging sessions later, we could confirm that this is indeed what is happening: the legacy schtasks.exe makes a RPC call to a legacy RPC endpoint SASetAccountInformation implemented in taskcomp.dll, which implements the old task scheduler instructions with RPC calls to the new ones implemented in schedsvc.dll, such as SchRpcRegisterTask and SchRpcSetSecurity.

Our focus thus turned to taskcomp.dll. Namely, RPC calls can be stacked: process A can RPC-call process B, and then the code processing said call in process B can further RPC-call process C. In our case, schtasks.exe (running as attacker) calls RPC endpoint taskcomp!SASetAccountInformation in Task Scheduler's process svchost.exe (running as Local System), which in turn calls RPC endpoint schedsvc!_SchRpcSetSecurity in the same svchost.exe (still running as Local System). When the latter impersonates its caller, it actually impersonates the access token of the thread in taskcomp.dll that called it, and if that thread had previously impersonated its own caller (i.e., attacker), the final impersonated token would also be attacker's. However, taskcomp.dll does not impersonate its caller; it impersonates self (Local System) to enable the SeRestorePrivilege privilege that is needed for it to set DACL and ownership on any file:




This impersonation breaks the tie with attacker's identity, and causes the subsequently executed schedsvc!_SchRpcSetSecurity to believe it was Local System, not the attacker, who requested the change of DACL and owner on pci.sys. It was time to patch.


Patching


Correcting the behavior of someone else's code in a complex environment is always tricky, and legacy support + task scheduling = complex, we believe it was actually an error to impersonate self in taskcomp.dll instead of impersonating the client. The latter would in fact allow the security check in schedsvc!_SchRpcSetSecurity to perform correctly and work as intended on a regular file as well as on a hard-linked system file (correctly failing when invoked by a low-privileged user).

We therefore decided to replace self-impersonation with client-impersonation, and to do that, we removed the call to ImpersonateSalfWithPrivilege and injected a call to RpcImpersonateClient in its place.

We wrote a micropatch for this and tested it.

The POC still worked.

It turned out that there was another RPC call to SchRpcSetSecurity in taskcomp.dll, which got called when the first one was unsuccessful:




The call stack was:

0:005> k
ChildEBP RetAddr
044ffc20 6ff9a3dd taskcomp!CompatibilityAdapter::

                  [IFileChangeNotification]::SdChange+0x9235
044ffc60 6ff9a2a4 taskcomp!JournalReader::HandleWaitTimer+0x11d
044ffef0 74d7e529 taskcomp!CompatibilityAdapter::MonitorThread+0x104
044fff00 775a9ed1 KERNEL32!BaseThreadInitThunk+0x19
044fff5c 775a9ea5 ntdll!__RtlUserThreadStart+0x2b
044fff6c 00000000 ntdll!_RtlUserThreadStart+0x1b



It looked like some monitoring thread was used for getting the job done when the original call failed, but this thread was not called via RPC, and client impersonation could not be used there. We therefore decided on a more drastic approach and simply amputated the call to SetSecurity.

After that, we got the desired behavior: The legacy schtasks.exe was behaving correctly when creating a new task from a job file, and when setting a "run-as" user for an existing task that the user was allowed to change permissions on. On the other hand, the hard link trick no longer worked because the Task Scheduler process correctly identified the caller and determined that it doesn't have sufficient permissions to change DACL or ownership on a system file. Since we didn't even touch schedsvc.dll, the new (non-legacy) Task Scheduler functionality was not affected at all.




With our micropatch in place, re-launching the POC and observing the Bear task file in Process Monitor only showed two CreateFile operations from SchRpcSetSecurity's security check described above, and both ended with an ACCESS DENIED error due to correct impersonation.


This is the source code of our micropatch for 32bit Windows 10 version 1809:



;Micropatch for taskcomp.dll version 10.0.17763.1
MODULE_PATH "..\AffectedModules\taskcomp.dll_10.0.17763.1_x86\taskcomp.dll"
PATCH_ID 374
PATCH_FORMAT_VER 2
VULN_ID 5172
PLATFORM win32

patchlet_start
 PATCHLET_ID 1
 PATCHLET_TYPE 2
 PATCHLET_OFFSET 0x000184dd
 PIT rpcrt4.dll!RpcImpersonateClient
 JUMPOVERBYTES 16 ; we skip the call to ImpersonateSelfWithPrivilege
 N_ORIGINALBYTES 1

 code_start
  mov dword [ebp-0b20h], 0 ; token (set to 0 to force the ImpersonateSelfWithPrivilege
                           ; destructor to call RpcRevertToSelf)
  push 0                   ; Impersonating the client that made the request
  call PIT_RpcImpersonateClient
 code_end

patchlet_end

patchlet_start
 PATCHLET_ID 2
 PATCHLET_TYPE 2
 PATCHLET_OFFSET 0x00015e72
 JUMPOVERBYTES 5 ; we skip the call to SetSecurity@RpcSession
 N_ORIGINALBYTES 1

 code_start
  add    esp, 0ch       ; 3 x pop
  mov eax, 00000000h   ; simulate that SetSecurity@RpcSession() function
                       ; returned 0 (as on successfull call)
 code_end

patchlet_end


And here it is in action:






As always, if you have 0patch Agent installed and registered, this micropatch is already on your computer - and applied to taskcomp.dll in your Task Scheduler service. If you don't have the 0patch Agent yet, you can register a 0patch account and install it to get this micropatch applied.

Following our guidelines on which patches to provide for free, this micropatch affects many home and education users, and is therefore included in both FREE and PRO 0patch license until Microsoft provides an official fix. After that the micropatch will only be included in the PRO license.

We are currently providing this micropatch for fully updated:
  1. Windows 10 version 1809 32bit
  2. Windows 10 version 1809 64bit
  3. Windows Server 2019
0patch PRO users are welcome to request porting this micropatch to other Windows 10 or Server versions at support@0patch.com. (Note that Windows 8, Windows 7, and their Server counterparts 2012 and 2008 don't seem to be affected.)


https://0patch.com/patches.html



One final question: Does the attacker really need a local user's password?

We seriously doubt that. While running the legacy schtasks.exe with an incorrect password via argument /RP results in an error, the documentation for IScheduledWorkItem::SetAccountInformation method (which actually gets called by legacy schtasks.exe) states: "If you set the TASK_FLAG_RUN_ONLY_IF_LOGGED_ON flag, you may also set pwszPassword to NULL for local or domain user accounts." We haven't tested this but it sounds reasonable that for "run only if logged on" tasks a password would not be needed. Since attacker's goal is not to have the task executed but to have Task Scheduler change permissions on a target file, we believe executing the attack should also be possible without knowing any password.


Cheers!

Simon Raner
@mkolsek
@0patch

Wednesday, April 17, 2019

Microsoft Edge Uses a Secret Trick And Breaks Internet Explorer's Security

Edge Decided To Use An Undocumented Security Feature.
Internet Explorer Didn't Get The Memo.

 

by Mitja Kolsek, the 0patch Team








Five days ago, security researcher John Page published details and a proof-of-concept for a vulnerability in Internet Explorer that he had previously reported to Microsoft but received a response that "...a fix for this issue will be considered in a future version of this product or service."

In this article we will explain why we think Microsoft has underestimated the severity of this vulnerability, how one Microsoft product inadvertently sabotaged another Microsoft product's security, and what you can do to protect yourself while waiting for Microsoft to fix this bug.


The Vulnerability



The vulnerability is a classic: an XML External Entity ("XXE") attack can  be mounted in Internet Explorer using an XML block inside a MHT file. As a result, a user opening such MHT file will have one or more of their local files sent to attacker's web server. Similar XXE vulnerabilities have been found in hundreds of products before, and exploited for exfiltrating local files.

The attack is nicely demonstrated in John's video, where you can see the user downloading an MHT file with Edge and then opening it with Internet Explorer - resulting in their system.ini file being sent to attacker's server.


But... What About The Mark-Of-The-Web?


After watching John's video we tried to reproduce the issue, and a Windows 7 machine was at hand. We downloaded the MHT file with Internet Explorer, then double-clicked it, and... nothing. Process Monitor showed that system.ini was in fact read, but it didn't get sent to the remote server. Then we created the same MHT file locally instead of downloading it, and the exploit worked.

This looked like a classic "mark-of-the-web" situation: when a file is obtained from the Internet, well-behaved Windows applications like web browsers and email clients add a mark to such file in form of an alternate data stream named Zone.Identifier, containing a line ZoneId=3. This allows other applications to know that the file has come from an untrusted source - and should thus be opened in a sandbox or an otherwise limited environment.

Indeed, Internet Explorer does put a mark-of-the-web on the downloaded MHT file, and when rendering that file, notices said mark and decides not to make the request to the remote server. Deleting the mark from the file effectively turns the file into a "trusted" file and the exploit works.

Okay, this is all good and well, but why does the exploit work with a downloaded file on John's video?

To answer that, we moved our analysis over to Windows 10 in order to replicate John's demo more closely. We downloaded the MHT file, this time with Edge, and opened it locally with Internet Explorer: Surprise! The exploit worked, just like in the demo!

But why? Does Edge not put the mark-of-the-web on downloaded files, or does it do it differently and somehow confuses Internet Explorer? That would be a serious flaw.

It was time for some differential analysis. We had two MHT files downloaded from the same location; one downloaded with Internet Explorer (msie-xss-0day-1.mht) and the other with Edge (msie-xss-0day-2.mht). Same content, when opened with an editor, but slightly different Zone.Identifier data streams:

msie-xss-0day-1.mht

[ZoneTransfer]
ZoneId=3
 

msie-xss-0day-2.mht

[ZoneTransfer]
ZoneId=3
ReferrerUrl=http://www.acrossecurity.com/test/
HostUrl=http://www.acrossecurity.com/test/msie-xxe-0day-2.mht


It turned out Edge does, unsurprisingly, put a mark-of-the-web on the file - but apparently stores some additional data there compared to Internet Explorer. Could this additional data somehow confuse Internet Explorer? It was easy to check; we copied the content of the Zone.Identifier stream from file #1 to file #2 and saved it.

Result: no difference; file #2 was still able to launch the exploit.


What Now?


So we had two identical files with identical data streams, and one of them executed the exploit while the other one didn't. After a bit of frustration, mixed with wild fantasies of Internet Explorer somehow remembering its downloaded files and tracking them on the computer, our Twitter buddy Eric Lawrence proposed checking the permissions on these files.

That was a silly proposal, of course, as obviously they would have identical permissions, inherited from the Downloads folder they were stored in. Obviously.

Wait, what?



Permissions on the file downloaded
with Internet Explorer
Permissions on the file downloaded
with Edge



Strange. Edge seemed to have added two entries to the downloaded file's AC, both for some SIDs that Windows can't or won't translate to a friendly name:

S-1-15-3-3624051433-2125758914-1423191267-1740899205-1073925389-
3782572162-737981194:(OI)(CI)(R)
                    S-1-15-2-3624051433-2125758914-1423191267-1740899205-1073925389-
3782572162-737981194:(OI)(CI)(R)


To see whether these ACL entries affected the exploit's execution in Internet Explorer, we decided to delete them one by one and retry the exploit. It turned out that removing the second one, SID S-1-15-2-*, resulted in exploit not working anymore. How weird: what looks like Read access permission (see the (R) above) for some unknown user account prevents the exploit from working.

Not finding anything useful about this SID on the Internet (although the AppContainer SID looks related)*, we turned to Process Monitor hoping to see some interesting differences between the execution of both files. And differences we have found, the most obvious being that Internet Explorer got a lot of ACCESS DENIED's on Edge-downloaded MHT file (the one where exploit was working), while it got none on Internet Explorer-downloaded MHT file.


Low Integrity iexplore.exe process gets ACCESS DENIED errors on opening the Zone.Identifier stream



Remember that Internet Explorer works with multiple iexplore.exe processes, some running with Medium Integrity and some with Low Integrity (i.e. in a sandbox). Low Integrity processes are not allowed to write or change files with higher integrity even if user account they're running as otherwise has permissions to do that. They are allowed to read files with higher integrity though.

All the ACCESS DENIED's were happening to Low Integrity iexplore.exe processes on read access, and that was clearly caused by the mysterious S-1-15-2-* SID we had found above because removing that ACL entry from file's permissions also removed all ACCESS DENIED's.


It became clear that we have stumbled upon an undocumented Windows 10 feature, a flag that can be set on a file to prevent Low Integrity processes from even reading its content or its attributes. We theorize that Edge is using this feature to further tighten the security of saved files against malicious code executing in its Low Integrity sandbox. Nothing wrong with that.

But why does this flag help the exploit to execute in Internet Explorer? We looked at some of the ACCESS DENIED events and noticed that two of them occurred on attempting to read MHT file's Zone.Identifier data stream. Remember the mark-of-the-web discussed above? It's stored in this data stream - and Internet Explorer was unable to read it. What if failing to read it made Internet Explorer assume that there is no mark-of-the-web on the file (which is true for all locally created files), resulting in treating it as a "trusted" file?

It turned out that's exactly what happened. In order to understand why, we need to dive into the code. The stack trace on one of the ACCESS DENIED events includes a call to a function with an extremely interesting name: GetZoneFromAlternateDataStreamEx.


The ACCESS DENIED event includes a call to GetZoneFromAlternateDataStreamEx



A quick look at the function in IDA, combined with observing its calls in WinDbg, tells us it takes two arguments: (1) path to a file, and (2) pointer to the Zone Id value. It tries to read the file's Zone.Identifier stream and parse the ZoneId value from it, storing it to the provided address if found. Its return value is the error code, typically 0 if the stream was found and read, or 80070002 ("File not found") if the stream doesn't exist.

GetZoneFromAlternateDataStreamEx resides in urlmon.dll and is only called from one place. That call, however, is not followed by any checking of the error code returned by the function. The calling code simply assumes that if GetZoneFromAlternateDataStreamEx can't read the Zone Id from the file for whatever reason, the file must be "trusted". This logic was probably correct until the new feature we had discovered above got introduced.

Namely, when the MHT file permissions include the mysterious S-1-15-2-* SID, GetZoneFromAlternateDataStreamEx gets an ACCESS DENIED on attempting to read the file's Zone.Identifier stream, stores no Zone Id, and returns the error code 80070005 ("Access denied"). The calling code, not caring about the error, understands this as the file not having a mark-of-the-web, subsequently allowing it to make a request to attacker's server.

See the irony here? An undocumented security feature used by Edge neutralized an existing, undoubtedly much more important feature (mark-of-the-web) in Internet Explorer.

This is clearly a significant security issue, especially since the attack can be further improved from what was originally demonstrated. We have found that:

  1. the malicious MHT file doesn't have to be downloaded and manually opened by the user - just opening it directly from Edge can be made to work as well;
  2. the exploit can be enhanced so that it works more silently, and extracts many local files using a single MHT file.

On the upside, only Edge users are at risk. No other leading web browsers and email clients we've tested are using the undocumented security flag on the downloaded files, which effectively blocks the exploit.


The Micropatch


While we believe Microsoft will update their original severity assessment of this issue and provide a fix for it, we wanted to give our users a micropatch to allow them to protect themselves. Namely, published 0days often start getting exploited, especially when no vendor fix is available.

Let's look at the code that calls GetZoneFromAlternateDataStreamEx and ignores the error returned by it.


The code calling GetZoneFromAlternateDataStreamEx


Fixing this seems pretty straight-forward: we need to add some error checking immediately after the call to GetZoneFromAlternateDataStreamEx to detect if the error was 80070005 ("Access denied"), and if so, set Zone Id to 3 ("untrusted"). This will effectively make Internet Explorer aware of Edge's security feature. Such is the source code of our micropatch for Windows 10 version 1803:


MODULE_PATH "..\AffectedModules\urlmon.dll_11.0.17134.648_32bit\urlmon.dll"
; Windows 10 version 1803
PATCH_ID 362
PATCH_FORMAT_VER 2
VULN_ID 5000
PLATFORM win32

patchlet_start

 PATCHLET_ID 1
 PATCHLET_TYPE 2
 PATCHLET_OFFSET 0x00034507 ; Injecting after the call to GetZoneFromAlternateDataStreamEx

 code_start

   cmp eax, 0x80070005 ; did we get ACCESS DENIED on reading the MOTW?
   jne pass            ; nope, all is OK
 
   ; we got ACCESS DENIED
   mov dword [ebp-4], 3   ; we set the ZoneID to 3 if we had ACCESS DENIED
 
  pass:
 
 code_end

patchlet_end


Here's  video if you'd like to see how the micropatch affects the exploit.





As always, if you have 0patch Agent installed and registered, this micropatch is already on your computer - and applied to urlmon.dll in Internet Explorer and other processes loading it. "Why not just Internet Explorer?" you might ask. Well, while we now know that Internet Explorer is vulnerable, there are other products using urlmon.dll, and in case some of them happen to be using its (flawed) logic we'll automatically fix them as well.
 
If you don't have the 0patch Agent yet, you can register a 0patch account and install it to get this micropatch applied.

Following our guidelines on which patches to provide for free, this micropatch affects many home and education users, and is therefore included in both FREE and PRO 0patch license until Microsoft provides an official fix. After that the micropatch will only be included in the PRO license.

We are currently providing this micropatch for fully updated:
  1. Windows 10 version 1803
  2. Windows 10 version 1809
  3. Windows 10 version 1709 [added on 4/18/2019]
0patch PRO users are welcome to request porting this micropatch to other Windows 10 versions at support@0patch.com.


* [Update 4/18/2019] James Forshaw of Google Project Zero has subsequently noted the mysterious undocumented SIDs are "capability and group SIDs for the Microsoft.MicrosoftEdge_8wekyb3d8bbwe package." We trust James so let's put it here as some day this will help someone researching a similar issue. You're welcome ;)

[Update 4/23/2019] User itman on a Wilders Security Forums thread about this issue has provided a lot of useful additional information on said SIDs in multiple posts that are well worth reading.We generally agree with itman on everything stated there (including our then "clueles[ness] to the fact that Edge in essence always operates in equivalent IE11 EPM mode,"), except on the risk introduced by modifying "code that is loaded by multiple Win system processes". While urlmon.dll is in fact being loaded by many processes, not all are using it for determining the Zone identifier (the DLL has many other exported functions). For those that are, and are faced with the same situation of being unable to read the Zone.Identifier stream due to running with Low Integrity or in a different AppContainer, we believe our added code that checks for errors has a net positive effect as it prevents such apps from overly trusting downloaded files.


Cheers!

@mkolsek
@0patch