14:00 CET on the 1st November 2013 Entry written by Hossein Lotfi, Security specialist, Secunia research..
We have taken a look at one of the zero-day vulnerabilities that Microsoft fixed this summer and we wanted to give you a brief overview of the vulnerability, including some additional details that have not been published by other parties yet.
In June 2013, Microsoft released MS13-051  to fix a vulnerability in Microsoft Office 2003 Service Pack 3 and Microsoft Office for Mac 2011. The vulnerability was reported by researchers from Google. Based on Microsoft’s TechNet blog, it has been used for targeted attacks mostly in Indonesia and Malaysia . Secunia covered this vulnerability in SA53747 . Although the average vulnerability window of a zero-day exploit is about 10 months , then it is suggested that this vulnerability has been exploited since 2009 , and even discovered initially back in 2008.
Reproduction: ------------------ 1) Install Microsoft Office 2003. Install Service Pack 3 for this version of office. (Note: This analysis is done without applying any further patches with MSO.dll version 11.0.8172.0).
2) Create a new document.
3) Go to "%CommonProgramFiles%\microsoft shared\GRPHFLT" (e.g. "C:\Program Files\Common Files\microsoft shared\GRPHFLT").
4) Drag "MS.PNG" file (a 2KB file) into the document and save the document as a "*.doc" file.
5) Open the saved document in a hex editor.
6) Change the value at offset 0x1B36 from 0x00000017 to 0xFFFFFFFF.
Microsoft Office will crash when processing this crafted document.
PNG File Format: ----------------------- PNG (Portable Network Graphics) is an extensible file format for the lossless, portable, well-compressed storage of raster images. A PNG file consists of a PNG signature followed by a series of chunks. Each chunk consists of four parts :
Length A 4-byte unsigned integer giving the number of bytes in the chunk's data field.
Chunk Type A 4-byte chunk type code. Type codes are restricted to consist of uppercase and lowercase ASCII letters.
Chunk Data The data bytes appropriate to the chunk type, if any.
CRC A 4-byte CRC (Cyclic Redundancy Check).
Among other chunks, a PNG file may contain iTXt, tEXt, or zTXt chunks to provide textual information. Each of the text chunks contains as its first field, a keyword that indicates the type of information represented by the text string. The following keywords are predefined and should be used where appropriate :
Title Short (one line) title or caption for image Author Name of image's creator Description Description of image (possibly long) Copyright Copyright notice Creation Time Time of original image creation Software Software used to create the image Disclaimer Legal disclaimer Warning Warning of nature of content Source Device used to create the image Comment Miscellaneous comment
----------------------- An integer overflow error when parsing "tEXt" chunks of a PNG stream within a document file can be exploited to cause a stack-based buffer overflow. Successful exploitation allows execution of arbitrary code.
During the processing of a document containing a PNG stream, execution reaches sub_30E63709 where first a call to sub_30E63270 is made to verify the supplied PNG stream.
If sub_30E63270 detects certain errors during verification of the PNG stream, it returns zero and the image will not be processed. Otherwise, true is returned and execution reaches loc_30E638B3 to process any encountered "tEXt" chunk with the "Title" and "Description" keywords. It first parses "tEXt" chunks with the "Title" keyword via a call to sub_30E630FC.
Note: The same process will be done later for the "Description" keyword.
.text:30E638B3 loc_30E638B3: .text:30E638B3 push 74455874h ; "tEXt" .text:30E638B8 push 800h ; parsing_buffer_space .text:30E638BD lea eax, [ebp+74h+buf] ; parsing_buffer .text:30E638C3 push eax .text:30E638C4 push offset aTitle_2 ; "Title" .text:30E638C9 lea ecx, [ebp+74h+proessing_object] .text:30E638CF mov [ebp+74h+buf], 0 .text:30E638D6 call sub_30E630FC ; process tEXt chunk with given keyword .text:30E638DB test al, al .text:30E638DD jz short loc_30E63944 .text:30E638DF lea edi, [ebp+74h+buf] .text:30E638E5 lea ecx, [edi+1] .text:30E638E8 .text:30E638E8 loc_30E638E8: .text:30E638E8 mov al, [edi] .text:30E638EA inc edi .text:30E638EB test al, al .text:30E638ED jnz short loc_30E638E8 .text:30E638EF sub edi, ecx .text:30E638F1 cmp edi, 200h .text:30E638F7 jge short loc_30E6393C .text:30E638F9 test edi, edi .text:30E638FB jg insert_line_terminator ; insert 0D0A .text:30E63901 .text:30E63901 loc_30E63901: .text:30E63901 push 74455874h ; "tEXt" .text:30E63906 mov eax, 800h .text:30E6390B sub eax, edi ; calculating remained space in parsing_buffer .text:30E6390D push eax ; parsing_buffer_space .text:30E6390E lea ebx, [ebp+edi+74h+buf] ; parsing_buffer .text:30E63915 push ebx .text:30E63916 push offset aDescription ; "Description" .text:30E6391B lea ecx, [ebp+74h+proessing_object] .text:30E63921 call sub_30E630FC ; process tEXt chunk with given keyword .text:30E63926 test al, al .text:30E63928 jz short loc_30E63933
The goal of sub_30E63126 is to extract text of all "tExt" chunks with the certain keyword (in this case "Title"). To achieve this goal, it enters a loop. Firstly, it starts by calculating the passed keyword length and checking if there is enough data available in the PNG stream.
If enough data is available, it extracts the chunk size and checks if enough data is available in the stream for the extracted chunk length. Note that this check can be bypassed due to an integer overflow error.
.text:30E63157 mov esi, [ebp+current_offset] .text:30E6315A cmp esi, ebx .text:30E6315C ja loc_30F05B1F .text:30F05B1F push edi .text:30F05B20 mov eax, [ebp+pProcessing_object] .text:30F05B23 mov edi, [eax+24h] ; load PNG stream .text:30F05B26 lea ecx, [edi+esi] ; current offset .text:30F05B29 mov [ebp+PNG_stream], edi .text:30F05B2C call get_dword ; extracting chunk size .text:30F05B31 mov ecx, [ebp+pProcessing_object] .text:30F05B34 mov [ebp+cur_chunk_size], eax .text:30F05B37 lea eax, [eax+esi+0Ch] ; *** integer overflow *** .text:30F05B3B cmp eax, [ecx+28h] ; enough data available? .text:30F05B3E ja short loc_30F05B95
Then, the chunk type is extracted and a check is done to see if it is a "tEXt" chunk.
.text:30F05B40 add esi, 4 ; advance the offset .text:30F05B43 lea ecx, [edi+esi] .text:30F05B46 call get_dword ; get chunk .text:30F05B4B add esi, 4 ; advance the offset .text:30F05B4E cmp eax, 'IEND' ; end of the PNG datastream? .text:30F05B53 mov [ebp+current_offset], esi .text:30F05B56 jz short loc_30F05B95 .text:30F05B58 cmp eax, [ebp+arg_C] ; tEXt chunk? .text:30F05B5B jnz short continue_with_next
Then, the execution reaches loc_30F05B6D to check the keyword of the encountered "tEXt" chunk.
If the keyword matches, a check is done to ensure that there is enough space in a 2048-byte stack-based buffer to process that amount of data specified by chunk length. Note that this check can be bypassed due to the integer overflow error. Then the chunk data will be extracted to this buffer.
.text:30FEFF04 loc_30FEFF04: .text:30FEFF04 mov ecx, [ebp+cur_chunk_size] .text:30FEFF07 sub ecx, eax ; lean_chunk_size = cur_chunk_size - keyword_length .text:30FEFF09 lea edx, [ecx+ebx] ; space_needed = lean_chunk_size + space_occupied *** integer overflow *** .text:30FEFF0C lea edi, [edx+2] ; 2 more for appending 0D0A *** integer overflow *** .text:30FEFF0F cmp edi, [ebp+buffer_size] ; parsing_buffer_space: 0x800 (2048) byte here .text:30FEFF12 ja short continue_with_the_next_chunk ; not enough space to process this chunk .text:30FEFF14 add esi, eax .text:30FEFF16 mov eax, [ebp+pProcessing_object] .text:30FEFF19 add esi, [eax+24h] ; loading the chunk data offset .text:30FEFF1C mov eax, [ebp+arg_4] .text:30FEFF1F lea edi, [eax+ebx] ; loading offset of parsing_buffer .text:30FEFF22 mov ebx, ecx .text:30FEFF24 shr ecx, 2 .text:30FEFF27 rep movsd ; *** stack-based buffer overflow here *** .text:30FEFF29 mov ecx, ebx .text:30FEFF2B and ecx, 3 .text:30FEFF2E mov ebx, edx .text:30FEFF30 rep movsb .text:30FEFF32 mov esi, [ebp+current_offset] .text:30FEFF35 mov word ptr [ebx+eax], 0A0Dh ; appaned a NewLine .text:30FEFF3B inc ebx .text:30FEFF3C inc ebx .text:30FEFF3D jmp continue_with_next_chunk
The loop continues checking for other "tEXt" chunks with the given keyword. By providing e.g. two "tEXT" chunks with e.g. "Title" or "Description" keyword where the size of the second one is an overly large value like 0xFFFFFFFF, it will be possible to pass the check of the available space in the buffer due to the integer overflow error and cause a stack-based buffer overflow.
Even though a working exploit already exists for this vulnerability, we would like to point out, that exploiting this vulnerability should be considered easy as the overflowed buffer resides on stack. Due to the copy size being a very large value, ultimately an access violation will be triggered that will be handled by an exception handler. As it is possible to overwrite the exception handlers with controlled data, receiving control and executing arbitrary code would be easily doable. The only remaining challenge would be to bypass ASLR on a more recent version of Microsoft Windows, which is not considered to be a hurdle due to the existence of non-ASLR modules within the process address space.
Fix: ------ The vulnerability is patched in the fixes released with MS13-51 by checking for integer overflow errors when performing the calculations.