The blog continues at suszter.com/ReversingOnWindows

November 19, 2012

An Attempt to Make a Read Access Violation Exploitable

This is the analysis of an attempt to make a read access violation exploitable. The bug is found in the 64-bit version of Internet Explorer 9 (9.0.8112.16421).

The crash happens when trying to open the SVG file with the below content. Note, that CDATA (stands for charachter data) doesn't have any element content leading to crash.
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <![CDATA[]]>
</svg>
These are the registers and the faulting instruction when the read access violation occurs.
0:005> r
rax=0000000000000000 rbx=00000000042bc2b0 rcx=00000000ffffffff
rdx=0000000000000000 rsi=0000000000000002 rdi=00000000042bbdc0
rip=000000005bd9aff5 rsp=00000000042bc4d0 rbp=00000000002844b0
 r8=0000000000000000  r9=0000000000000084 r10=000000005c7c1b00
r11=000000000eb1d7a0 r12=00000000042bc570 r13=0000000000000000
r14=00000000002844b0 r15=0000000000000001
iopl=0         nv up ei pl zr na po nc
cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010244
MSHTML!CHtmSpaceParseCtx::AddNonspaces+0x134:
00000000`5bd9aff5 410fb70c4c      movzx   ecx,word ptr [r12+rcx*2] ds:00000002`042bc56e=????
This is the call stack. It's not used to support any of claims but it's pasted for information only.
0:005> k
Child-SP          RetAddr           Call Site
00000000`042bc4d0 00000000`5bc7c249 MSHTML!CHtmSpaceParseCtx::AddNonspaces+0x134
00000000`042bc530 00000000`5bc7c153 MSHTML!CHtmCrlfParseCtx::AddTextIE9+0x146
00000000`042bc7c0 00000000`5bd2bd17 MSHTML!CHtmCrlfParseCtx::AddText+0x24
00000000`042bc800 00000000`5bd7daa5 MSHTML!CHtmParse::ParseText+0x349
00000000`042bc9c0 00000000`5bd2d36e MSHTML!CHtmParse::ParseToken+0x2d2
00000000`042bca00 00000000`5bd20980 MSHTML!CHtmPost::ProcessTokens+0x49b
00000000`042bcd00 00000000`5bd20f7b MSHTML!CHtmPost::Exec+0x274
00000000`042bcf10 00000000`5bd20e81 MSHTML!CHtmPost::Run+0x5a
00000000`042bcf50 00000000`5bd206eb MSHTML!PostManExecute+0x1ae
00000000`042bcfa0 00000000`5bd1f4e0 MSHTML!CDwnChan::OnMethodCall+0x1b
00000000`042bcfd0 00000000`5bdeb468 MSHTML!GlobalWndOnMethodCall+0x18b
00000000`042bd060 00000000`771d9bd1 MSHTML!GlobalWndProc+0x36c
00000000`042bd0e0 00000000`771d98da USER32!UserCallWinProcCheckWow+0x1ad
00000000`042bd1a0 000007fe`ebfdaf5e USER32!DispatchMessageWorker+0x3b5
00000000`042bd220 000007fe`ebf87754 IEFRAME!CTabWindow::_TabWindowThreadProc+0x9c1
00000000`042bf680 00000000`76d153b3 IEFRAME!LCIETab_ThreadProc+0x39f
00000000`042bf820 000007fe`ebf68dcb iertutil!CIsoScope::RegisterThread+0x10f
00000000`042bf850 00000000`76bf652d IEFRAME!Detour_DefWindowProcA+0x97
00000000`042bf890 00000000`772ec521 kernel32!BaseThreadInitThunk+0xd
00000000`042bf8c0 00000000`00000000 ntdll!RtlUserThreadStart+0x1d
After restarting Internet Explorer and the debugger (leading different memory layout), I set a breakpoint at the address of the faulting instruction.
0:005> g
Breakpoint 0 hit
MSHTML!CHtmSpaceParseCtx::AddNonspaces+0x134:
00000000`69f0aff5 410fb70c4c      movzx   ecx,word ptr [r12+rcx*2] ds:00000002`0421cb2e=????
r12 is the base address of a structure. The instruction reads a word value from the structure using a delta value that is RCX*2. In our case, RCX is 0`ffffffff which cannot be a valid delta value as the size of the memory region of the structure is only 4000 bytes as seen below. Therefore by executing the instruction it reads out of the bounds of the structure, that is likely an invalid memory address.
0:005> !vprot r12
BaseAddress:       000000000421c000
AllocationBase:    0000000004020000
AllocationProtect: 00000004  PAGE_READWRITE
RegionSize:        0000000000004000
State:             00001000  MEM_COMMIT
Protect:           00000004  PAGE_READWRITE
Type:              00020000  MEM_PRIVATE
By allocating memory at the address of the invalid read we can execute the instruction without causing exception.
MSHTML!CHtmSpaceParseCtx::AddNonspaces+0x134:
00000000`69f0aff5 410fb70c4c      movzx   ecx,word ptr [r12+rcx*2] ds:00000002`0421cb2e=????
0:005> .dvalloc /b 2`0421c000 1000
Allocated d000 bytes starting at 00000002`04210000
As seen below, movzx now tries to access to a valid memory region recently allocated by .dvalloc, filled with zeroes. If we let the program execute now it doesn't crash. Even if we refresh the SVG file it doesn't cause a read access violation because now the memory movzx tries to access is a valid address in the virtual address space.
0:005> r
rax=0000000000000000 rbx=0000000000000000 rcx=00000000ffffffff
rdx=0000000000000000 rsi=0000000000000000 rdi=000000000033bd50
rip=0000000069f0aff5 rsp=000000000421ca90 rbp=000000000df58d90
 r8=0000000000000000  r9=000000000e03fee0 r10=000000000dfe4401
r11=0000000000000001 r12=000000000421cb30 r13=0000000000000000
r14=000000000df58d90 r15=0000000000000001
iopl=0         nv up ei pl zr na po nc
cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
MSHTML!CHtmSpaceParseCtx::AddNonspaces+0x134:
00000000`69f0aff5 410fb70c4c      movzx   ecx,word ptr [r12+rcx*2] ds:00000002`0421cb2e=0000
When the instruction is executed it reads the tainted word value to ECX. As seen below, the word value is copied to a second structure. At this point the tainted data is copied to a second structure.
0:005> p
MSHTML!CHtmSpaceParseCtx::AddNonspaces+0x13c:
00000000`69f0affd 66894f7c        mov     word ptr [rdi+7Ch],cx ds:00000000`0033bdcc=0020
Using the PoC, later on the execution the program doesn't read the tainted data from the second structure that is verified by processor breakpoint.

The tainted word value was zero as .dvalloc filled the memory with zeroes. Since we know the address of the word value we can try all the 65536 possibilities and watch what happens when processing the different word values. To achieve this I wrote a wrapper HTML which calls the SVG file periodically. Also, I set up the below commands which does the job automatically, so in every iteration we provide different tainted input in range of 0 to 65535.
0:005> bc 0
0:005> r $t0 = 0;
0:005> bp 69f0aff5 "j @ecx=ffffffff 'ew 2`0421cb2e @$t0; r $t0 = @$t0 + 1; .if (@$t0 <= 0xffff) { gc }'; gc"
0:005> g
When the command completed I concluded that we tried all the word values but neither of them seem to trigger unusual code paths using the PoC.

Further analyzing the data flow there is a possible place when the tainted data could be used to make decision on the execution flow, and it's the following.
MSHTML!CHtmSpaceParseCtx::AddNonspaces+0x87:
00000000`69f4823e 0fb74f7c        movzx   ecx,word ptr [rdi+7Ch]
00000000`69f48242 6685c9          test    cx,cx
00000000`69f48245 0f8511b8d2ff    jne     MSHTML!CHtmSpaceParseCtx::AddNonspaces+0x90 (00000000`69c73a5c)
If this code can be reached when [rdi+7c] is the tainted data that might have consequence due to the complexity of the code paths in this function. I however was unable to reach this code path in my experience.

The address of invalid read is predictable by the attacker as it's always 2 x 0`ffffffff plus something which can be filled with attacker controlled data. But this doesn't seem to be relevant as Microsoft just confirmed that they had finished their investigation into this crash and as they say "[we] can confirm that this crash is caused by a read AV which is not exploitable." I believe them and I no longer investigate this but will focus on other crashes, but thought to share this.

November 12, 2012

An Example for Hidden NULL Pointer Bug

When performing security testing of the native application I often attach Windbg to the target process. The obvious benefit of this methodology is that when an exception occurs it's possible to immediately analyze and save the state information of the program. There is one more important benefit, and that is you can get additional information of the running application if you set certain options beforehand. For example, sxn ud command sets up the debugger to send notification when a module is unloaded. I find very useful to analyze Windbg log during security testing, rather than just relying to find exception or memory corruption.

Some time ago, during testing Internet Explorer 9, I noticed that Windbg screen had been flooded with the following messages.
Invalid parameter passed to C runtime function.
Invalid parameter passed to C runtime function.
Invalid parameter passed to C runtime function.
Invalid parameter passed to C runtime function.
The application continued running without displaying more of these messages and there was no sign the integrity of the application corrupted. My first thought was it's the result of one of Windbg commands I set up earlier just before executing the test. The second thought was that it is unlikely because it seems to be a CRT error message, that most likely comes from the runtime DLL. I knew there is a way to send message to the debugger from an executable and that is to call OutputDebugString function.

I set up a breakpoint for OutputDebugString, and rerun the test. Here is the call stack when the breakpoint hit.
0:005> k
Child-SP          RetAddr           Call Site
00000000`04448388 000007fe`fdfd2478 KERNELBASE!OutputDebugStringA
00000000`04448390 000007fe`fdfd249b msvcrt!invoke_watson+0x98
00000000`044488d0 000007fe`fdfb0439 msvcrt!invalid_parameter+0x13
00000000`04448910 00000000`6027290f msvcrt!wcsnicmp+0x40
00000000`04448950 00000000`6000b522 MSHTML!CMultimediaLog::ExtractVideoData+0x8f
00000000`04448a30 00000000`600077ba MSHTML!CDoc::ExecHelper+0x4308
00000000`044498b0 000007fe`f1a22805 MSHTML!CDoc::Exec+0x2a
00000000`04449900 000007fe`f1a222f1 IEFRAME!CDocObjectHost::_PopulateOnlineHistoryData+0x141
00000000`04449990 000007fe`f1a21ecb IEFRAME!CDocObjectHost::_UpdateHistoryAndIntSiteDB+0x229
00000000`0444cb10 000007fe`f1a22001 IEFRAME!CDocObjectHost::_OnReadyState+0x21b
00000000`0444cda0 000007fe`f1a220bc IEFRAME!CDocObjectHost::_OnChangedReadyState+0xd1
00000000`0444ce70 00000000`5ff33c27 IEFRAME!CDocObjectHost::OnChanged+0x1c
00000000`0444cea0 00000000`5ff31380 MSHTML!CBase::FirePropertyNotify+0x3a3
00000000`0444cf30 00000000`5ff7f874 MSHTML!CMarkup::SetReadyState+0x41a
00000000`0444cfb0 00000000`5ff323b1 MSHTML!CMarkup::OnLoadStatusDone+0x3eb
00000000`0444d070 00000000`5ff7ef3f MSHTML!CMarkup::OnLoadStatus+0xb2
00000000`0444d0a0 00000000`5ff2f4e0 MSHTML!CProgSink::DoUpdate+0x5f5
00000000`0444d530 00000000`5fffb468 MSHTML!GlobalWndOnMethodCall+0x18b
00000000`0444d5c0 00000000`76de9bd1 MSHTML!GlobalWndProc+0x36c
00000000`0444d640 00000000`76de98da USER32!UserCallWinProcCheckWow+0x1ad
00000000`0444d700 000007fe`f198af5e USER32!DispatchMessageWorker+0x3b5
00000000`0444d780 000007fe`f1937754 IEFRAME!CTabWindow::_TabWindowThreadProc+0x9c1
00000000`0444fbe0 00000000`771553b3 IEFRAME!LCIETab_ThreadProc+0x39f
00000000`0444fd80 000007fe`f1918dcb iertutil!CIsoScope::RegisterThread+0x10f
00000000`0444fdb0 00000000`76ee652d IEFRAME!Detour_DefWindowProcA+0x97
00000000`0444fdf0 00000000`774dc521 kernel32!BaseThreadInitThunk+0xd
00000000`0444fe20 00000000`00000000 ntdll!RtlUserThreadStart+0x1d
Looking at the parameter of OutputDebugString I saw the followings.
0:005> db @rcx
000007fe`fe014110  49 6e 76 61 6c 69 64 20-70 61 72 61 6d 65 74 65  Invalid paramete
000007fe`fe014120  72 20 70 61 73 73 65 64-20 74 6f 20 43 20 72 75  r passed to C ru
000007fe`fe014130  6e 74 69 6d 65 20 66 75-6e 63 74 69 6f 6e 2e 0a  ntime function..
000007fe`fe014140  00 00 00 00 3a 20 00 00-0a 00 0a 00 00 00 00 00  ....: ..........
000007fe`fe014150  2e 00 2e 00 2e 00 00 00-00 00 00 00 00 00 00 00  ................
000007fe`fe014160  4d 00 69 00 63 00 72 00-6f 00 73 00 6f 00 66 00  M.i.c.r.o.s.o.f.
000007fe`fe014170  74 00 20 00 56 00 69 00-73 00 75 00 61 00 6c 00  t. .V.i.s.u.a.l.
000007fe`fe014180  20 00 43 00 2b 00 2b 00-20 00 52 00 75 00 6e 00   .C.+.+. .R.u.n.
This confirms this function sends the message to the debugger. We also see that OutputDebugString is called from wcsnicmp that is called from CMultimediaLog::ExtractVideoData.

I set up a breakpoint just before we call wcsnicmp.
0:005> ub MSHTML!CMultimediaLog::ExtractVideoData+0x8f
MSHTML!CMultimediaLog::ExtractVideoData+0x69:
00000000`602728e9 7409            je      MSHTML!CMultimediaLog::ExtractVideoData+0x74 (00000000`602728f4)
00000000`602728eb 488b01          mov     rax,qword ptr [rcx]
00000000`602728ee ff9020050000    call    qword ptr [rax+520h]
00000000`602728f4 4c8b6c2428      mov     r13,qword ptr [rsp+28h]
00000000`602728f9 488d15480f6900  lea     rdx,[MSHTML!`string' (00000000`60903848)]
00000000`60272900 41b807000000    mov     r8d,7
00000000`60272906 498bcd          mov     rcx,r13
00000000`60272909 ff1591ca5e00    call    qword ptr [MSHTML!_imp__wcsnicmp (00000000`6085f3a0)]
The place of the breakpoint is the highlighted line above.

Here we are when the breakpoint is hit.
Breakpoint 2 hit
MSHTML!CMultimediaLog::ExtractVideoData+0x89:
00000000`60272909 ff1591ca5e00    call    qword ptr [MSHTML!_imp__wcsnicmp (00000000`6085f3a0)] ds:00000000`6085f3a0={msvcrt!wcsnicmp (000007fe`fdf93330)}
Note that wcsnicmp takes three parameters: string1, string2, and count. These describes null-terminated strings and number of characters to compare.

I checked the parameters of wcsnicmp and saw the followings.
0:005> r rcx;r rdx;r r8
rcx=0000000000000000
rdx=0000000060903848
r8=0000000000000007
string2 and count both look healthy however string1 is NULL but the API documentation expects a string.

To make sure everything is ok with string2 let's check.
0:005> du @rdx
00000000`60903848  "http://"
It's fine, so the only problem with parameter string1 and the problem is that a NULL pointer is passed rather than a pointer to the string.

Microsoft long time ago added security enhancements in the CRT library. One of them involves to call invalid parameter handler which, for example, checks for NULL pointer parameters, and we terminate gracefully rather than with invalid memory access exception.

As you can see the return value is the highest positive value that can be represented in signed 32-bit. If the application is not prepared to handle this edge value it could cause problem later on the execution. Fortunately, that was not the case with Internet Explorer.
0:005> g 6027290f
MSHTML!CMultimediaLog::ExtractVideoData+0x8f:
00000000`6027290f baffff0000      mov     edx,0FFFFh
0:005> r eax
eax=7fffffff
The NULL check suppresses the crash but the application likely having problems managing the lifetime of objects.

Developers are advised to avoid the use of wcsnicmp() function as it's deprecated. Please check references what to use instead.

References

Security Features in the CRT
  This blog is written and maintained by Attila Suszter. Read in Feed Reader.