Flexera Software - The leading provider of software licensing, entitlement management, installation, and application readiness

On November 2, 2015, the Secunia blog will be moving

In September 2015, Secunia was acquired by Flexera Software.

The blog posts and news on secunia.com will therefore be moved to a brand new Software Vulnerability Management section on FlexeraSoftware.com

From November 2 you can visit us there, for an uninterrupted stream of news about the Software Sulnerability Management solutions and Secunia Research.

Get this blog as an RSS Feed

In memory of a zero-day - MS13-051

14:00 CET, 1st November 2013 By Hossein Lotfi, Security specialist, Secunia research..

Hello all!

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 [1] 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 [2]. Secunia covered this vulnerability in SA53747 [3]. Although the average vulnerability window of a zero-day exploit is about 10 months [4], then it is suggested that this vulnerability has been exploited since 2009 [5], and even discovered initially back in 2008.

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 [6]:

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.

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 [7]:


   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

Technical Details:

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.

.text:30E63709    push    ebp
.text:30E6370A    lea     ebp, [esp-74h]
.text:30E6370E    sub     esp, 9F0h
.text:30E63714    mov     eax, ds:dword_3165E000
.text:30E63719    push    ebx
.text:30E6371A    push    esi
.text:30E6371B    push    [ebp+74h+arg_0]
.text:30E6371E    mov     [ebp+74h+var_4], eax
.text:30E63721    mov     esi, ecx
.text:30E63723    call    sub_30E63DBC
.text:30E63728    push    eax
.text:30E63729    lea     ecx, [ebp+74h+var_1E4]
.text:30E6372F    call    sub_30D8EBB3
.text:30E63734    lea     ecx, [ebp+74h+proessing_object]
.text:30E6373A    call    sub_30E63270    ; verify PNG stream.
.text:30E6373F    test    al, al          ; valid PNG stream?
.text:30E63741    jz      return_0

sub_30E63270 performs various checks by calling other functions including sub_30E633A4. Chunks with a very large length will pass the checks due to integer overflow errors.


.text:30E633BF    loop_start:
.text:30E633BF    mov     eax, [esi+24h]
.text:30E633C2    add     eax, edi
.text:30E633C4    mov     ecx, eax
.text:30E633C6    mov     [ebp+var_4], eax
.text:30E633C9    call    get_dword          ; chunk size
.text:30E633CE    mov     ecx, [ebp+var_4]
.text:30E633D1    add     ecx, 4
.text:30E633D4    mov     ebx, eax        
.text:30E633D6    call    get_dword          ; Chunk Type
.text:30E633DB    mov     [ebp+var_4], eax
.text:30E633DE    mov     eax, [esi+28h]
.text:30E633E1    lea     ecx, [ebx+edi+0Ch] ; *** integer overflow ***
.text:30E633E5    cmp     ecx, eax
.text:30E633E7    ja      loc_310BD821
.text:310BD82E    lea     ecx, [ebx+edi+8]   ; *** integer overflow ***
.text:310BD832    cmp     ecx, eax
.text:310BD834    jbe     short loc_310BD83D

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    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    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

sub_30E630FC in turn calls sub_30E63126.

.text:30E630FC    push    ebp
.text:30E630FD    mov     ebp, esp
.text:30E630FF    mov     eax, 74455874h       ; "tEXt" chunk
.text:30E63104    cmp     [ebp+arg_C], eax
.text:30E63107    jnz     loc_31028434
.text:30E6310D    push    dword ptr [ecx+18h]
.text:30E63110    push    dword ptr [ecx+14h]
.text:30E63113    push    eax
.text:30E63114    loc_30E63114:                          
.text:30E63114    push    [ebp+arg_8]          ; parsing_buffer_space
.text:30E63117    push    [ebp+arg_4]          ; parsing_buffer
.text:30E6311A    push    [ebp+arg_0]          ; "Title" keyword
.text:30E6311D    call    sub_30E63126

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.
.text:30E63126    push    ebp
.text:30E63127    mov     ebp, esp
.text:30E63129    sub     esp, 14h
.text:30E6312C    mov     eax, [ebp+arg_0]
.text:30E6312F    push    ebx
.text:30E63130    xor     ebx, ebx
.text:30E63132    cmp     eax, ebx                        ; any keyword passed?
.text:30E63134    push    esi
.text:30E63135    mov     [ebp+pProcessing_object], ecx
.text:30E63138    jz      loc_31028446
.text:30E6313E    lea     edx, [eax+1]
.text:30E63141    get_tEXt_keyword_length:               
.text:30E63141    mov     cl, [eax]
.text:30E63143    inc     eax
.text:30E63144    test    cl, cl
.text:30E63146    jnz     short get_tEXt_keyword_length
.text:30E63148    sub     eax, edx
.text:30E6314A    inc     eax
.text:30E6314B    mov     [ebp+tEXt_keyword_length], eax
.text:30E6314E    loc_30E6314E:                          
.text:30E6314E    cmp     [ebp+buffer_size], ebx          ; not enough data?
.text:30E63151    mov     [ebp+result], 1
.text:30E63155    jbe     short return_result

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.

.text:30F05B6D    mov     eax, [ebp+PNG_stream]
.text:30F05B70    mov     edi, [ebp+arg_0] ; "Title"
.text:30F05B73    add     esi, eax         ; loading current offset
.text:30F05B75    xor     eax, eax
.text:30F05B77    repe cmpsb
.text:30F05B79    mov     esi, [ebp+current_offset]
.text:30F05B7C    jz      loc_30FEFEF9

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.

The vulnerability is patched in the fixes released with MS13-51 by checking for integer overflow errors when performing the calculations.

.text:30ECE722    mov     esi, edx
.text:30ECE724    sub     esi, [ebp+arg_10]
.text:30ECE727    lea     eax, [ebp+var_18]
.text:30ECE72A    push    eax
.text:30ECE72B    mov     edx, esi
.text:30ECE72D    mov     ecx, ebx
.text:30ECE72F    mov     [ebp+var_28], esi
.text:30ECE732    call    safely_add_edx_ecx
.text:30ECE737    test    eax, eax        ; integer overflow?
.text:30ECE739    jl      return_0
.text:30ECE73B    mov     ecx, [ebp+var_18]
.text:30ECE73E    lea     eax, [ebp+var_18]
.text:30ECE741    push    eax
.text:30ECE742    push    2
.text:30ECE744    pop     edx
.text:30ECE745    call    safely_add_edx_ecx
.text:30ECE74A    test    eax, eax        ; integer overflow?
.text:30ECE74C    jl      return_0
.text:30ECE74E    mov     eax, [ebp+arg_8]
.text:30ECE751    cmp     [ebp+var_18], eax
.text:30ECE754    ja      short loc_30ECE787
.text:30ECE756    mov     eax, [ebp+var_8]
.text:30ECE759    mov     ecx, esi
.text:30ECE75B    mov     esi, [eax+24h]
.text:30ECE75E    add     esi, [ebp+arg_10]
.text:30ECE761    mov     eax, [ebp+arg_4]
.text:30ECE764    add     esi, [ebp+var_C]
.text:30ECE767    mov     edx, ecx
.text:30ECE769    shr     ecx, 2
.text:30ECE76C    lea     edi, [eax+ebx]
.text:30ECE76F    rep movsd
.text:30ECE771    mov     ecx, edx
.text:30ECE773    and     ecx, 3
.text:30ECE776    add     ebx, edx
.text:30ECE778    rep movsb
.text:30ECE77A    mov     word ptr [ebx+eax], 0A0Dh
.text:30ECE780    inc     ebx
.text:30ECE781    inc     ebx
.text:30ECE782    jmp     loc_30E7FEFF

Stay secure!
Hossein Lotfi,
Security specialist,
Secunia research.

1. http://technet.microsoft.com/en-us/security/bulletin/ms13-051
2. http://blogs.technet.com/b/srd/archive/2013/06/11/ms13-051-get-out-of-my-office.aspx
3. http://secunia.com/advisories/53747/
4. http://users.ece.cmu.edu/~tdumitra/public_documents/bilge12_zero_day.pdf
5. http://eromang.zataz.com/tag/ms13-051/
6. http://tools.ietf.org/html/rfc2083#page-11
7. http://tools.ietf.org/html/rfc2083#page-24

Discuss this blog entry
A new thread in our forum is created. Activate the thread by commenting/discussing below.

Subject: In memory of a zero-day - MS13-051

No posts yet
You must be logged in to post a comment.