Slate
Blackcurrant
Watermelon
Strawberry
Orange
Banana
Apple
Emerald
Chocolate
Marble
Slate
Blackcurrant
Watermelon
Strawberry
Orange
Banana
Apple
Emerald
Chocolate
Marble
-
Content Count
16,668 -
Joined
-
Last visited
Never -
Feedback
N/A
Everything posted by Rss Bot
-
Read more about Get the virtual assistant that will actually help you get things done at CreativeBloq.com Your phone is capable of doing so much, but it's about time that it can help you actually get more done. With EasilyDo, you'll be able to check off items on your to-do list faster than ever.View the full article
-
Read more about Go from beginner to expert with the Ultimate Animation Bundle at CreativeBloq.com Whether you're looking at a career in design as your next step or you're already in the field and want to refresh your skills, the Ultimate Design and Animation Bundle is here for you.View the full article
-
By Hossein Lotfi, Security Specialist On the 8th December 2015, Microsoft released Security Bulletin MS15-130 [1] to fix a vulnerability in Unicode Scripts Processor component found by Secunia Research [2]. The Common Vulnerabilities and Exposures (CVE) project has assigned the CVE-2015-6130 identifier for the vulnerability. The vector for a successful exploitation is a specially crafted "True Type Font" (TTF) file, which typically can be embedded in e.g. Microsoft Office documents or even in emails and web-based content depending on the font type. The result is the execution of arbitrary code once successfully exploited and thus is rated as "Highly Critical" by Secunia Research. Introduction: Uniscribe is the Microsoft Windows set of services for rendering Unicode-encoded text, especially complex text layout. They are implemented in USP10.DLL. USP is an initialism for Unicode Scripts Processor [3]. Reproduction: Open %systemroot%\Fonts\ariblk.ttf in a hex editor and change content of offset 0x4ED2 from 0x0014 to... View the full article
-
On the 8th December 2015, Microsoft released Security Bulletin MS15-130 [1] to fix a vulnerability in Unicode Scripts Processor component found by Secunia Research [2]. The Common Vulnerabilities and Exposures (CVE) project has assigned the CVE-2015-6130 identifier for the vulnerability. The vector for a successful exploitation is a specially crafted “True Type Font” (TTF) file, which typically can be embedded in e.g. Microsoft Office documents or even in emails and web-based content depending on the font type. The result is the execution of arbitrary code once successfully exploited and thus is rated as “Highly Critical” by Secunia Research. Introduction: Uniscribe is the Microsoft Windows set of services for rendering Unicode-encoded text, especially complex text layout. They are implemented in USP10.DLL. USP is an initialism for Unicode Scripts Processor [3]. Reproduction: Open %systemroot%Fontsariblk.ttf in a hex editor and change content of offset 0x4ED2 from 0x0014 to 0x011B. Technical Details: Note: The following analysis is done on Windows 7 SP1 with usp10.dll version 1.626.7601.18454. During processing scripts in a font file, the code flow reaches the “LoadFont()” function within usp10.dll. Shortly after, this function calls the “GetFontDesc()” function to load mapping of character codes within the font. .text:7603D2E0 mov edi, edi .text:7603D2E2 push ebp .text:7603D2E3 mov ebp, esp .text:7603D2E5 sub esp, 25Ch .text:7603D2EB mov eax, ___security_cookie .text:7603D2F0 xor eax, ebp .text:7603D2F2 mov [ebp+var_8], eax .text:7603D2F5 mov eax, [ebp+arg_0] .text:7603D2F8 push esi ; struct FACE_CACHE * .text:7603D2F9 push edi ; HDC .text:7603D2FA xor edi, edi .text:7603D2FC push 220h ; Size .text:7603D301 lea ecx, [ebp+Dst] .text:7603D307 push edi ; Val .text:7603D308 push ecx ; Dst .text:7603D309 mov [ebp+hdc], eax .text:7603D30F mov [ebp+var_250], edi .text:7603D315 call _memset .text:7603D31A xor eax, eax .text:7603D31C mov dword ptr [ebp+var_28], eax .text:7603D31F mov [ebp+var_24], eax .text:7603D322 mov [ebp+var_20], eax .text:7603D325 mov [ebp+var_1C], eax .text:7603D328 mov [ebp+var_18], eax .text:7603D32B mov [ebp+var_14], eax .text:7603D32E mov [ebp+var_10], eax .text:7603D331 mov [ebp+var_C], eax .text:7603D334 mov al, [ebx+95h] .text:7603D33A mov edx, 0F807h .text:7603D33F and [ebx+0A0h], dx .text:7603D346 and al, 0Ch .text:7603D348 add esp, 0Ch .text:7603D34B cmp al, 8 .text:7603D34D jnz short loc_7603D366 .text:7603D34F cmp byte ptr [ebx+97h], 0 .text:7603D356 jnz short loc_7603D366 .text:7603D358 lea esi, [ebx+98h] .text:7603D35E mov dword ptr [esi], 0FFFFFFFDh .text:7603D364 jmp short loc_7603D385 .text:7603D366 ; --------------------------------------------------------------------------- .text:7603D366 .text:7603D366 loc_7603D366: ; CODE XREF: LoadFont(HDC__ *,FACE_CACHE *)+6D_j .text:7603D366 ; LoadFont(HDC__ *,FACE_CACHE *)+76_j .text:7603D366 mov eax, [ebp+hdc] .text:7603D36C lea ecx, [ebp+var_250] .text:7603D372 push ecx ; int * .text:7603D373 lea esi, [ebx+98h] .text:7603D379 push esi ; HDC .text:7603D37A call GetFontDesc(HDC__ *,int *,FONTCMAPDESC * *) The “GetFontDesc()” function first checks for certain values within the “OS/2” table and then loads data from the cmap table. .text:7603AF70 ; __int32 __stdcall GetFontDesc(HDC, int *, struct FONTCMAPDESC **) .text:7603AF70 ?GetFontDesc@@YGJPAUHDC__@@PAHPAPAUFONTCMAPDESC@@@Z proc near .text:7603AF70 ; CODE XREF: LoadFont(HDC__ *,FACE_CACHE *)+9A_p .text:7603AF70 .text:7603AF70 var_20= dword ptr -20h .text:7603AF70 var_1C= dword ptr -1Ch .text:7603AF70 var_18= dword ptr -18h .text:7603AF70 pvBuffer= byte ptr -14h .text:7603AF70 var_12= byte ptr -12h .text:7603AF70 var_10= dword ptr -10h .text:7603AF70 var_C= dword ptr -0Ch .text:7603AF70 var_8= dword ptr -8 .text:7603AF70 var_4= dword ptr -4 .text:7603AF70 arg_0= dword ptr 8 .text:7603AF70 arg_4= dword ptr 0Ch .text:7603AF70 .text:7603AF70 mov edi, edi .text:7603AF72 push ebp .text:7603AF73 mov ebp, esp .text:7603AF75 sub esp, 20h .text:7603AF78 push ebx .text:7603AF79 mov ebx, ds:__imp__GetFontData@20 ; GetFontData(x,x,x,x,x) .text:7603AF7F push esi ; int .text:7603AF80 push edi ; unsigned __int16 * .text:7603AF81 mov edi, [ebp+arg_4] .text:7603AF84 push 4 ; cjBuffer .text:7603AF86 mov esi, eax .text:7603AF88 lea eax, [ebp+pvBuffer] .text:7603AF8B push eax ; pvBuffer .text:7603AF8C push 3Eh ; dwOffset .text:7603AF8E push '2/SO' ; dwTable .text:7603AF93 push esi ; hdc .text:7603AF94 mov dword ptr [edi], 0 .text:7603AF9A call ebx ; GetFontData(x,x,x,x,x) ; GetFontData(x,x,x,x,x) .text:7603AF9C cmp eax, 4 .text:7603AF9F jz short loc_7603AFB5 .text:7603AFA1 mov ecx, [ebp+arg_0] .text:7603AFA4 pop edi .text:7603AFA5 pop esi .text:7603AFA6 mov dword ptr [ecx], 0FFFFFFFEh .text:7603AFAC xor eax, eax .text:7603AFAE pop ebx .text:7603AFAF mov esp, ebp .text:7603AFB1 pop ebp .text:7603AFB2 retn 8 .text:7603AFB5 ; --------------------------------------------------------------------------- .text:7603AFB5 .text:7603AFB5 loc_7603AFB5: ; CODE XREF: GetFontDesc(HDC__ *,int *,FONTCMAPDESC * *)+2F_j .text:7603AFB5 mov al, [ebp+var_12] ; usFirstCharIndex .text:7603AFB8 cmp al, 0F0h .text:7603AFBA jnb short loc_7603AFC0 .text:7603AFBC test al, al .text:7603AFBE jnz short loc_7603AFD1 .text:7603AFC0 .text:7603AFC0 loc_7603AFC0: ; CODE XREF: GetFontDesc(HDC__ *,int *,FONTCMAPDESC * *)+4A_j .text:7603AFC0 mov al, [ebp+pvBuffer] ; fsSelection .text:7603AFC3 test al, al .text:7603AFC5 jz short loc_7603AFD1 .text:7603AFC7 movzx edx, al .text:7603AFCA mov eax, [ebp+arg_0] .text:7603AFCD mov [eax], edx .text:7603AFCF jmp short loc_7603AFDA .text:7603AFD1 ; --------------------------------------------------------------------------- .text:7603AFD1 .text:7603AFD1 loc_7603AFD1: ; CODE XREF: GetFontDesc(HDC__ *,int *,FONTCMAPDESC * *)+4E_j .text:7603AFD1 ; GetFontDesc(HDC__ *,int *,FONTCMAPDESC * *)+55_j .text:7603AFD1 mov ecx, [ebp+arg_0] .text:7603AFD4 mov dword ptr [ecx], 0FFFFFFFFh .text:7603AFDA .text:7603AFDA loc_7603AFDA: ; CODE XREF: GetFontDesc(HDC__ *,int *,FONTCMAPDESC * *)+5F_j .text:7603AFDA push 0 ; cjBuffer .text:7603AFDC push 0 ; pvBuffer .text:7603AFDE push 0 ; dwOffset .text:7603AFE0 push 'pamc' ; dwTable .text:7603AFE5 push esi ; hdc .text:7603AFE6 call ebx ; GetFontData(x,x,x,x,x) ; GetFontData(x,x,x,x,x) .text:7603AFE8 mov ebx, eax .text:7603AFEA mov [ebp+var_4], ebx .text:7603AFED cmp ebx, 0FFFFFFFFh .text:7603AFF0 jz loc_7603B188 .text:7603AFF6 cmp ebx, 4 .text:7603AFF9 jl loc_7603B188 .text:7603AFFF push edi ; int .text:7603B000 lea edx, [ebx+34h] .text:7603B003 push edx ; dwBytes .text:7603B004 call _UspAllocCache@8 ; UspAllocCache(x,x) .text:7603B009 test eax, eax .text:7603B00B jl short loc_7603B061 .text:7603B00D mov eax, [edi] .text:7603B00F lea ecx, [eax+34h] .text:7603B012 mov [eax+4], ecx .text:7603B015 push ebx ; cjBuffer .text:7603B016 mov [eax+8], ebx .text:7603B019 mov edx, [eax+4] .text:7603B01C push edx ; pvBuffer .text:7603B01D push 0 ; dwOffset .text:7603B01F push 'pamc' ; dwTable .text:7603B024 push esi ; hdc .text:7603B025 call ds:__imp__GetFontData@20 ; GetFontData(x,x,x,x,x) Based on the loaded information, a check is done to make sure enough data is available and that there is at least one EncodingRecord table. .text:7603B035 mov ecx, [eax+4] .text:7603B038 mov dx, [ecx+2] ; numTables .text:7603B03C add ecx, 2 .text:7603B03F rol dx, 8 ; change endianness .text:7603B043 mov [ecx], dx .text:7603B046 mov esi, [eax+4] .text:7603B049 movzx ecx, word ptr [esi+2] .text:7603B04D lea edx, ds:4[ecx*8] .text:7603B054 cmp ebx, edx ; check if enough data is available .text:7603B056 mov [ebp+var_20], ecx .text:7603B059 jge short proceed1 .text:7603B05B push eax .text:7603B05C call _UspFreeMem@4 ; UspFreeMem(x) .text:7603B061 .text:7603B061 return_error: ; CODE XREF: GetFontDesc(HDC__ *,int *,FONTCMAPDESC * *)+9B_j .text:7603B061 mov eax, [ebp+arg_0] .text:7603B064 pop edi .text:7603B065 pop esi .text:7603B066 mov dword ptr [eax], 0FFFFFFFDh .text:7603B06C xor eax, eax .text:7603B06E pop ebx .text:7603B06F mov esp, ebp .text:7603B071 pop ebp .text:7603B072 retn 8 .text:7603B075 ; --------------------------------------------------------------------------- .text:7603B075 .text:7603B075 proceed1: ; CODE XREF: GetFontDesc(HDC__ *,int *,FONTCMAPDESC * *)+E9_j .text:7603B075 xor edx, edx .text:7603B077 add esi, 4 .text:7603B07A cmp ecx, edx ; check if numTables is zero .text:7603B07C mov [eax+2Ch], edx .text:7603B07F mov [ebp+var_C], edx .text:7603B082 mov [ebp+var_10], edx .text:7603B085 mov [eax+30h], edx .text:7603B088 mov [ebp+var_8], edx .text:7603B08B jle clean_and_return Afterwards, a loop is entered to process available EncodingRecords. If platform ID is 3 and encoding ID is either 0 (Symbol) or 1 (Unicode BMP (UCS-2)) [4], then the offset and format of a table are saved in respective local variables. .text:7603B094 loop: ; CODE XREF: GetFontDesc(HDC__ *,int *,FONTCMAPDESC * *)+200_j .text:7603B094 mov cx, [esi] ; platformID .text:7603B097 mov dx, [esi+2] ; encodingID .text:7603B09B rol cx, 8 .text:7603B09F mov [esi], cx .text:7603B0A2 rol dx, 8 .text:7603B0A6 lea edi, [esi+4] ; offset .text:7603B0A9 mov ecx, 1 .text:7603B0AE mov eax, edi .text:7603B0B0 mov [esi+2], dx .text:7603B0B4 call ?FlipDWords@@YGXPAKH@Z ; FlipDWords(ulong *,int) .text:7603B0B9 mov edi, [edi] ; offset (little endian) .text:7603B0BB movzx ecx, word ptr [esi] ; platformID .text:7603B0BE test edi, edi ; is_offset_zero? .text:7603B0C0 jz continue_loop2 .text:7603B0C6 lea eax, [ebx-4] .text:7603B0C9 cmp eax, edi ; enough_data_available? .text:7603B0CB jbe continue_loop2 .text:7603B0D1 mov edx, [ebp+arg_4] .text:7603B0D4 mov edx, [edx] .text:7603B0D6 mov eax, [edx+4] .text:7603B0D9 mov bx, [eax+edi] ; format .text:7603B0DD add eax, edi .text:7603B0DF rol bx, 8 .text:7603B0E3 movzx ebx, bx .text:7603B0E6 test cx, cx .text:7603B0E9 jnz short loc_7603B115 .text:7603B0EB movzx ecx, word ptr [esi+2] .text:7603B0EF cmp cx, 5 .text:7603B0F3 jnz short continue_loop1 .text:7603B0F5 cmp bx, 0Eh .text:7603B0F9 jnz short continue_loop1 .text:7603B0FB cmp dword ptr [edx+2Ch], 0 .text:7603B0FF jnz short continue_loop1 .text:7603B101 mov ebx, [ebp+var_4] .text:7603B104 mov ecx, ebx .text:7603B106 sub ecx, edi .text:7603B108 cmp ecx, 0Ah .text:7603B10B jl short continue_loop2 .text:7603B10D mov [edx+2Ch], eax .text:7603B110 mov [edx+30h], ecx .text:7603B113 jmp short continue_loop2 .text:7603B115 ; --------------------------------------------------------------------------- .text:7603B115 .text:7603B115 loc_7603B115: ; CODE XREF: GetFontDesc(HDC__ *,int *,FONTCMAPDESC * *)+179_j .text:7603B115 mov edx, 3 .text:7603B11A cmp cx, dx .text:7603B11D jnz short continue_loop1 .text:7603B11F movzx ecx, word ptr [esi+2] .text:7603B123 test cx, cx .text:7603B126 jnz short loc_7603B137 ; Unicode BMP encodings? .text:7603B128 mov ecx, 1 .text:7603B12D cmp [ebp+var_8], ecx .text:7603B130 jge short continue_loop1 .text:7603B132 mov [ebp+var_8], ecx .text:7603B135 jmp short loc_7603B15A .text:7603B137 ; --------------------------------------------------------------------------- .text:7603B137 .text:7603B137 loc_7603B137: ; CODE XREF: GetFontDesc(HDC__ *,int *,FONTCMAPDESC * *)+1B6_j .text:7603B137 cmp cx, 1 ; Unicode BMP encodings? .text:7603B13B jnz short loc_7603B14C .text:7603B13D mov ecx, 2 .text:7603B142 cmp [ebp+var_8], ecx .text:7603B145 jge short continue_loop1 .text:7603B147 mov [ebp+var_8], ecx .text:7603B14A jmp short loc_7603B15A .text:7603B14C ; --------------------------------------------------------------------------- .text:7603B14C .text:7603B14C loc_7603B14C: ; CODE XREF: GetFontDesc(HDC__ *,int *,FONTCMAPDESC * *)+1CB_j .text:7603B14C cmp cx, 0Ah .text:7603B150 jnz short continue_loop1 .text:7603B152 cmp [ebp+var_8], edx .text:7603B155 jge short continue_loop1 .text:7603B157 mov [ebp+var_8], edx .text:7603B15A .text:7603B15A loc_7603B15A: ; CODE XREF: GetFontDesc(HDC__ *,int *,FONTCMAPDESC * *)+1C5_j .text:7603B15A ; GetFontDesc(HDC__ *,int *,FONTCMAPDESC * *)+1DA_j .text:7603B15A mov [ebp+table_pointer], eax .text:7603B15D movzx eax, bx .text:7603B160 mov [ebp+format4_offset], edi .text:7603B163 mov [ebp+format], eax .text:7603B166 .text:7603B166 continue_loop1: ; CODE XREF: GetFontDesc(HDC__ *,int *,FONTCMAPDESC * *)+183_j .text:7603B166 ; GetFontDesc(HDC__ *,int *,FONTCMAPDESC * *)+189_j ... .text:7603B166 mov ebx, [ebp+var_4] .text:7603B169 .text:7603B169 continue_loop2: ; CODE XREF: GetFontDesc(HDC__ *,int *,FONTCMAPDESC * *)+150_j .text:7603B169 ; GetFontDesc(HDC__ *,int *,FONTCMAPDESC * *)+15B_j ... .text:7603B169 add esi, 8 .text:7603B16C sub [ebp+var_18], 1 .text:7603B170 jnz loop Immediately after finishing the loop, a check is done to see if a local variable for a possible encountered offset of EncodingRecord is set and then another check is done to see if saved format is a format 4 (segment mapping to delta values). .text:7603B176 mov ecx, [ebp+format4_offset] .text:7603B179 test ecx, ecx .text:7603B17B jnz short loc_7603B19C ; is Segment_mapping_to_delta_values? .text:7603B17D mov edi, [ebp+arg_4] .text:7603B180 .text:7603B180 clean_and_return: ; CODE XREF: GetFontDesc(HDC__ *,int *,FONTCMAPDESC * *)+11B_j .text:7603B180 mov ecx, [edi] .text:7603B182 .text:7603B182 loc_7603B182: ; CODE XREF: GetFontDesc(HDC__ *,int *,FONTCMAPDESC * *)+314_j .text:7603B182 push ecx .text:7603B183 call _UspFreeMem@4 ; UspFreeMem(x) .text:7603B188 .text:7603B188 loc_7603B188: ; CODE XREF: GetFontDesc(HDC__ *,int *,FONTCMAPDESC * *)+80_j .text:7603B188 ; GetFontDesc(HDC__ *,int *,FONTCMAPDESC * *)+89_j .text:7603B188 mov edx, [ebp+arg_0] .text:7603B18B pop edi .text:7603B18C pop esi .text:7603B18D mov dword ptr [edx], 0FFFFFFFDh .text:7603B193 xor eax, eax .text:7603B195 pop ebx .text:7603B196 mov esp, ebp .text:7603B198 pop ebp .text:7603B199 retn 8 .text:7603B19C ; --------------------------------------------------------------------------- .text:7603B19C .text:7603B19C loc_7603B19C: ; CODE XREF: GetFontDesc(HDC__ *,int *,FONTCMAPDESC * *)+20B_j .text:7603B19C movzx eax, word ptr [ebp+format] ; is Segment_mapping_to_delta_values? .text:7603B1A0 cmp eax, 4 .text:7603B1A3 jz format4 .text:7603B1A9 cmp eax, 0Ch .text:7603B1AC jnz short loc_7603B210 After that, a loop is entered to check if there is an EncodingRecord offset larger than saved format 4 offset. If it is also smaller than cmap table data size, it is considered valid and will be saved. .text:7603B242 next_record: ; CODE XREF: GetFontDesc(HDC__ *,int *,FONTCMAPDESC * *)+2E5_j .text:7603B242 mov ecx, [eax] ; loading EncodingRecord offset .text:7603B244 cmp ecx, [ebp+offset] .text:7603B247 jbe short loc_7603B24F .text:7603B249 cmp edx, ecx ; smaller than cmap table data size? .text:7603B24B jbe short loc_7603B24F .text:7603B24D mov edx, ecx ; saving in EDX .text:7603B24F .text:7603B24F loc_7603B24F: ; CODE XREF: GetFontDesc(HDC__ *,int *,FONTCMAPDESC * *)+2D7_j .text:7603B24F ; GetFontDesc(HDC__ *,int *,FONTCMAPDESC * *)+2DB_j .text:7603B24F add eax, 8 .text:7603B252 sub esi, 1 .text:7603B255 jnz short next_record Then, a subroutine is entered to change endianness of format 4 subtable. In order to calculate the length of operation, the saved offset from the last loop is subtracted from the original format 4 offset and to skip format and length fields (two short values), a subtraction by 4 is performed. Note that there is no check here for an integer underflow. .text:7603B257 mov edi, [ebp+format4_offset] .text:7603B25A mov esi, [ebp+table_pointer] .text:7603B25D sub edx, edi .text:7603B25F sub edx, 4 ; *** Integer Underflow *** .text:7603B262 shr edx, 1 ; would not be a signed value any more. .text:7603B264 lea ecx, [esi+4] ; skip ushort_format and ushort_length .text:7603B267 call FlipWords(ushort *,int) Within the “FlipWords()” function, the underflowed value is used to change endianness of the content of subtable, resulting in a heap-based buffer overflow. .text:7603AF00 ; void __cdecl FlipWords(unsigned __int16 *, int) .text:7603AF00 ?FlipWords@@YGXPAGH@Z proc near ; CODE XREF: GetFontDesc(HDC__ *,int *,FONTCMAPDESC * *)+2F7_p .text:7603AF00 xor eax, eax .text:7603AF02 test edx, edx ; huge size due to underflow .text:7603AF04 jle short locret_7603AF22 .text:7603AF06 push esi .text:7603AF07 jmp short loc_7603AF10 .text:7603AF07 ; --------------------------------------------------------------------------- .text:7603AF09 align 10h .text:7603AF10 .text:7603AF10 loc_7603AF10: ; CODE XREF: FlipWords(ushort *,int)+7_j .text:7603AF10 ; FlipWords(ushort *,int)+1F_j .text:7603AF10 mov si, [ecx+eax*2] .text:7603AF14 rol si, 8 .text:7603AF18 mov [ecx+eax*2], si ; Heap-based buffer overflow .text:7603AF1C inc eax .text:7603AF1D cmp eax, edx .text:7603AF1F jl short loc_7603AF10 .text:7603AF21 pop esi .text:7603AF22 .text:7603AF22 locret_7603AF22: ; CODE XREF: FlipWords(ushort *,int)+4_j .text:7603AF22 retn References https://technet.microsoft.com/en-us/library/security/ms15-130.aspx https://secunia.com/community/advisories/66666 https://en.wikipedia.org/wiki/Uniscribe https://www.microsoft.com/typography/otspec/cmap.htm View the full article
-
By Hossein Lotfi, Security Specialist Introduction The Microsoft Security Bulletin MS15-035(1) resolved a vulnerability in Windows GDI, which can be exploited to execute arbitrary code via EMF files. This vulnerability was discovered by Secunia Research and has been assigned Secunia Advisory SA60006 (2)(3). The vulnerability is rated Highly Critical by Secunia Research. Windows Graphics Device Interface (GDI) The Graphics Device Interface (GDI) is a Microsoft Windows application programming interface and core operating system component responsible for representing graphical objects and transmitting them to output devices such as monitors and printers.(4) The processing of EMF files utilizes Windows GDI. EMF File Format An EMF metafile is a series of variable-length records, called EMF records, which contain graphics drawing commands, object definitions, and properties. The metafile begins with a header record, which includes the metafile version, its size, the resolution of the device on which the picture was created, and the dimensions... View the full article
-
Introduction The Microsoft Security Bulletin MS15-035(1) resolved a vulnerability in Windows GDI, which can be exploited to execute arbitrary code via EMF files. This vulnerability was discovered by Secunia Research and has been assigned Secunia Advisory SA60006 (2)(3). The vulnerability is rated Highly Critical by Secunia Research. Windows Graphics Device Interface (GDI) The Graphics Device Interface (GDI) is a Microsoft Windows application programming interface and core operating system component responsible for representing graphical objects and transmitting them to output devices such as monitors and printers.(4) The processing of EMF files utilizes Windows GDI. EMF File Format An EMF metafile is a series of variable-length records, called EMF records, which contain graphics drawing commands, object definitions, and properties. The metafile begins with a header record, which includes the metafile version, its size, the resolution of the device on which the picture was created, and the dimensions of the picture. An EMF metafile is “played back” when its records are converted to a format understood by a specific graphics device (5). The EMR_SETDIBITSTODEVICE record (record type 80) is one of the records available in EMF files. This record specifies a block transfer of pixels from specified scan lines of a source bitmap to a destination rectangle,(6) and contains various fields for that purpose. Technical Details The following analysis is based on Windows 7 Professional using gdi32.dll version 6.1.7601.18577 and GdiPlus.dll version 6.1.7601.18455. When processing EMF records, the processing flow reaches the “EmfEnumState::ProcessRecord()” function within gdiplus.dll to process each records. .text:25D40BCE lea eax, [edi-1] ; switch 122 cases ; edi= record type .text:25D40BD1 cmp eax, 79h .text:25D40BD4 ja short loc_25D40C20 ; jumptable 25D40BDD default case .text:25D40BD6 movzx eax, ds:byte_25D40DD7[eax] .text:25D40BDD jmp ds:off_25D40D5B[eax*4] ; switch jump For an EMR_SETDIBITSTODEVICE record a jump to loc_25D40C9D is made, where a call to the “EmfEnumState::SetDIBitsToDevice()” function is following. .text:25D40C9D mov ecx, esi ; jumptable 25D40BDD case 80 .text:25D40C9F call EmfEnumState::SetDIBitsToDevice(void) .text:25D40CA4 jmp short loc_25D40C7B After additional processing the “EmfEnumState::PlayRecord()” function is reached, where the “PlayEnhMetaFileRecord()” function within gdi32.dll is called. A pointer to the record is passed as 3rd parameter in this case. .text:25D3FA0D push dword ptr [esi+14h] ; cht .text:25D3FA10 push eax ; pointer to the record .text:25D3FA11 push dword ptr [esi+50h] ; pht .text:25D3FA14 push dword ptr [esi+8] ; hdc .text:25D3FA17 call PlayEnhMetaFileRecord(x,x,x,x) The “PlayEnhMetaFileRecord()” function is responsible for playing an enhanced-metafile record by executing the graphics device interface (GDI) functions identified by the record.(7) Depending on the record type, a different function will be called with respect to the record by utilizing the record type as an index into a call table. An EMR_SETDIBITSTODEVICE record (record type 80) will lead to a call to the “MRSETDIBITSTODEVICE::bPlay()” function based on this. .text:77B75DEA push [ebp+cht] .text:77B75DED mov ecx, esi ; passing pointer to the record as this pointer. .text:77B75DEF push [ebp+pht] .text:77B75DF2 push [ebp+hdc] .text:77B75DF5 call dword ptr ds:(loc_77B75E0B+1)[eax*4] ; eax= 0x50 (EMR_SETDIBITSTODEVICE) The “MRSETDIBITSTODEVICE::bPlay()” function starts by checking the provided record and returns an error if checks are not passed. .text:77BA3516 ; =============== S U B R O U T I N E ======================================= .text:77BA3516 .text:77BA3516 ; Attributes: bp-based frame .text:77BA3516 .text:77BA3516 ; int __thiscall MRSETDIBITSTODEVICE::bPlay(MRSETDIBITSTODEVICE *this, HDC hdc, struct tagHANDLETABLE *, unsigned int) .text:77BA3516 ?bPlay@MRSETDIBITSTODEVICE@@QAEHPAXPAUtagHANDLETABLE@@I@Z proc near .text:77BA3516 ; DATA XREF: .text:77B75F4Co .text:77BA3516 .text:77BA3516 pt = tagPOINT ptr -0Ch .text:77BA3516 var_4 = dword ptr -4 .text:77BA3516 hdc = dword ptr 8 .text:77BA3516 arg_4 = dword ptr 0Ch .text:77BA3516 .text:77BA3516 mov edi, edi .text:77BA3518 push ebp .text:77BA3519 mov ebp, esp .text:77BA351B sub esp, 0Ch .text:77BA351E mov eax, [ebp+arg_4] .text:77BA3521 push ebx .text:77BA3522 push esi .text:77BA3523 push edi .text:77BA3524 push 460000h .text:77BA3529 push dword ptr [eax] .text:77BA352B mov esi, ecx ; pointer to the record .text:77BA352D xor edi, edi … .text:77BA3544 push [ebp+arg_4] ; struct tagHANDLETABLE * .text:77BA3547 mov ecx, esi ; this .text:77BA3549 call MRSETDIBITSTODEVICE::bCheckRecord(tagHANDLETABLE *) .text:77BA354E test eax, eax .text:77BA3550 jz short return_0 .text:77BA3552 lea eax, [esi+EMRSETDIBITSTODEVICE.rclBounds] .text:77BA3555 push eax ; struct ERECTL * .text:77BA3556 mov ecx, ebx ; this .text:77BA3558 call MF::bClipped(ERECTL &) .text:77BA355D test eax, eax .text:77BA355F jz short loc_77BA3569 … .text:77BA3569 mov eax, [esi+EMRSETDIBITSTODEVICE.xDest] .text:77BA356C mov [ebp+pt.x], eax .text:77BA356F mov eax, [esi+EMRSETDIBITSTODEVICE.yDest] .text:77BA3572 mov [ebp+pt.y], eax .text:77BA3575 push 1 ; c .text:77BA3577 lea eax, [ebp+pt] .text:77BA357A push eax ; lppt .text:77BA357B push dword ptr [ebx+2A4h] ; hdc .text:77BA3581 call LPtoDP(x,x,x) .text:77BA3586 test eax, eax .text:77BA3588 jz short return_0 … .text:77BA359D push [esi+EMRSETDIBITSTODEVICE.cbBmiSrc] ; unsigned __int32 .text:77BA35A0 mov ecx, esi ; this .text:77BA35A2 push [esi+EMRSETDIBITSTODEVICE.offBmiSrc] ; unsigned __int32 .text:77BA35A5 push [ebp+arg_4] ; struct tagHANDLETABLE * .text:77BA35A8 call MR::bValidOffExt(tagHANDLETABLE *,ulong,ulong) .text:77BA35AD test eax, eax .text:77BA35AF jz short return_0 If all checks are passed, then a new buffer is allocated based on the cbBmiSrc field of the record. This field specifies size of the source BITMAPINFO structure. Note that this field is user controlled and it is possible to create a crafted record with cbBmiSrc equal to e.g. 4. .text:77BA35B1 push [esi+EMRSETDIBITSTODEVICE.cbBmiSrc] ; uBytes , controlled .text:77BA35B4 push 0 ; uFlags .text:77BA35B6 call ds:__imp__LocalAlloc@8 ; LocalAlloc(x,x) .text:77BA35BC mov ebx, eax .text:77BA35BE test ebx, ebx .text:77BA35C0 jz loc_77BA364B Further on, data is written into this allocated buffer and, by specifying a small value for the controlled cbBmiSrc field, it will be possible to allocate a small buffer, which in turn leads to corruption of memory. .text:77BA35C6 push [esi+EMRSETDIBITSTODEVICE.cbBmiSrc] ; Size .text:77BA35C9 mov eax, [esi+EMRSETDIBITSTODEVICE.offBmiSrc] .text:77BA35CC add eax, esi .text:77BA35CE push eax ; Src .text:77BA35CF push ebx ; Dst .text:77BA35D0 call _memcpy .text:77BA35D5 mov eax, [esi+EMRSETDIBITSTODEVICE.cScans] .text:77BA35D8 add esp, 0Ch .text:77BA35DB cmp [ebx+8], edi .text:77BA35DE jg short loc_77BA35E2 .text:77BA35E0 neg eax .text:77BA35E2 .text:77BA35E2 loc_77BA35E2: ; CODE XREF: MRSETDIBITSTODEVICE::bPlay(void *,tagHANDLETABLE *,uint)+C8j .text:77BA35E2 mov [ebx+8], eax ; *** corruption here *** .text:77BA35E5 mov eax, [esi+EMRSETDIBITSTODEVICE.cbBitsSrc] .text:77BA35E8 mov [ebx+14h], eax ; *** corruption here *** .text:77BA35EB cmp [esi+EMRSETDIBITSTODEVICE.cbBitsSrc], edi .text:77BA35EE jz short loc_77BA3604 … Exploitation Vectors As the processing of any encountered EMF file utilizes Windows GDI, there are several possible exploitation vectors available. For example, simply sending a malicious EMF file as an email attachment can be used to trigger this vulnerability. Additionally, it is also possible to embed a malicious EMF file in a webpage or in a file format suitable for an office suite application to exploit this issue. References https://technet.microsoft.com/en-us/library/security/ms15-035.aspx https://secunia.com/community/advisories/60006 https://secunia.com/secunia_research/2015-1 http://en.wikipedia.org/wiki/Graphics_Device_Interface https://msdn.microsoft.com/en-us/library/cc230515.aspx https://msdn.microsoft.com/en-us/library/cc230685.aspx https://msdn.microsoft.com/en-us/library/windows/desktop/dd162801(v=vs.85).aspx View the full article
-
By Dmitry Janushkevich, Security Specialist Yesterday, Oracle issued a patch for Outside In, which fixes a vulnerability discovered by Secunia Research. (1,2) The vulnerability is rated Moderately Critical by Secunia Research. Product Background(3) Oracle Outside In Technology provides software developers with a comprehensive solution to access, transform, and control the contents of over 500 unstructured file formats. From the latest Microsoft office suites, to specialty formats and legacy files, Outside In Technology provides software developers with the tools to transform unstructured files into controllable information. Issue Summary The fixed vulnerability, assigned CVE-2015-0493, is caused due to a sign extension error when handling PSD files within the ibpsd2.dll component. The vulnerability can be exploited to cause a heap-based buffer overflow and crash an application using the SDK or, potentially, execute arbitrary code within the context of such an application. The vulnerability has been confirmed in the ibpsd2.dll component version 8.5.1.0. Prior... View the full article
-
Yesterday, Oracle issued a patch for Outside In, which fixes a vulnerability discovered by Secunia Research. (1,2) The vulnerability is rated Moderately Critical by Secunia Research. Product Background(3) Oracle Outside In Technology provides software developers with a comprehensive solution to access, transform, and control the contents of over 500 unstructured file formats. From the latest Microsoft office suites, to specialty formats and legacy files, Outside In Technology provides software developers with the tools to transform unstructured files into controllable information. Issue Summary The fixed vulnerability, assigned CVE-2015-0493, is caused due to a sign extension error when handling PSD files within the ibpsd2.dll component. The vulnerability can be exploited to cause a heap-based buffer overflow and crash an application using the SDK or, potentially, execute arbitrary code within the context of such an application. The vulnerability has been confirmed in the ibpsd2.dll component version 8.5.1.0. Prior versions may also be affected. Please note that all further details (e.g. offsets or code snippets) are given with respect to this component version. File Format Introduction From a very high level perspective, a PSD (Photoshop File Format) file is comprised of five major parts called sections: File Header section, specifying basic image properties e.g. width and height. Color Mode Data section, carrying data specific to certain color modes. Image Resources section, storing non-pixel data. This data is not used by the affected code. Layer and Mask Information section, providing information about layers and masks. This data is not used by the affected code. Image Data section, containing the (possibly compressed) merged image with each color channel stored separately (not interleaved). It is the last section that will interest us the most. Further details on the file format can be found here (4). Technical Details The function sub_1C001000 is responsible for parsing the file contents. After some start-up code, the function reads the file header section and validates its contents: .text:1C00115C push 1 .text:1C00115E lea ecx, [ebp+PsdSignature] .text:1C001161 push ecx .text:1C001162 push offset a4c1s6c1s2l2s ; "4C1S6C1S2L2S" .text:1C001167 mov edx, [ebp+fp] .text:1C00116A push edx .text:1C00116B call imsReadStruct .text:1C001170 add esp, 10h .text:1C001173 cmp eax, 1 .text:1C001176 jz short loc_1C001194 .text:1C001178 mov [ebp+var_4], 0Eh .text:1C00117F mov eax, [ebp+var_4] .text:1C001182 push eax .text:1C001183 mov ecx, [ebp+arg_0] .text:1C001186 push ecx .text:1C001187 call sub_1C002B80 .text:1C00118C add esp, 8 .text:1C00118F jmp loc_1C001CF8 .text:1C001194 ; ------------------------------------------------------------------------ .text:1C001194 .text:1C001194 loc_1C001194: ; CODE XREF: sub_1C001000+176j .text:1C001194 push 4 ; Size .text:1C001196 push offset a8bps ; "8BPS" .text:1C00119B lea edx, [ebp+PsdSignature] .text:1C00119E push edx ; Buf1 .text:1C00119F call memcmp .text:1C0011A4 add esp, 0Ch .text:1C0011A7 test eax, eax .text:1C0011A9 jz short loc_1C0011BC .text:1C0011AB mov [ebp+var_4], 0FFFFFFE9h .text:1C0011B2 jmp loc_1C001D40 .text:1C0011B7 ; ------------------------------------------------------------------------ .text:1C0011B7 jmp loc_1C001CF8 .text:1C0011BC ; ------------------------------------------------------------------------ .text:1C0011BC .text:1C0011BC loc_1C0011BC: ; CODE XREF: sub_1C001000+1A9j .text:1C0011BC movzx eax, [ebp+PsdVersion] .text:1C0011C0 cmp eax, 1 .text:1C0011C3 jnz short loc_1C0011E7 .text:1C0011C5 movzx ecx, [ebp+PsdColorMode] .text:1C0011C9 cmp ecx, 9 .text:1C0011CC jz short loc_1C0011E7 .text:1C0011CE movzx edx, [ebp+PsdColorMode] .text:1C0011D2 cmp edx, 7 .text:1C0011D5 jz short loc_1C0011E7 .text:1C0011D7 movzx eax, [ebp+PsdChannelCount] .text:1C0011DB test eax, eax .text:1C0011DD jz short loc_1C0011E7 .text:1C0011DF movzx ecx, [ebp+PsdBitDepth] .text:1C0011E3 test ecx, ecx .text:1C0011E5 jnz short loc_1C0011F8 .text:1C0011E7 .text:1C0011E7 loc_1C0011E7: ; CODE XREF: sub_1C001000+1C3j .text:1C0011E7 ; sub_1C001000+1CCj ... .text:1C0011E7 mov [ebp+var_4], 0FFFFFFE8h .text:1C0011EE jmp loc_1C001D40 After initializing certain internal structures, the function reads the lengths of the following sections and handles their contents. The only actual handling is performed for the Color Mode Data section — contents of other sections is simply skipped, e.g.: .text:1C00165D push 1 .text:1C00165F lea eax, [ebp+SectionLength] .text:1C001662 push eax .text:1C001663 mov ecx, [ebp+fp] .text:1C001666 push ecx .text:1C001667 call imsReadLong ; Read the length of the Image Resources Section .text:1C00166C add esp, 0Ch .text:1C00166F cmp eax, 1 .text:1C001672 jz short loc_1C00168D .text:1C001674 mov [ebp+var_4], 0Eh .text:1C00167B mov edx, [ebp+var_4] .text:1C00167E push edx .text:1C00167F mov eax, [ebp+arg_0] .text:1C001682 push eax .text:1C001683 call sub_1C002B80 .text:1C001688 add esp, 8 .text:1C00168B jmp short loc_1C00169F .text:1C00168D ; ------------------------------------------------------------------------ .text:1C00168D .text:1C00168D loc_1C00168D: ; CODE XREF: sub_1C001000+672j .text:1C00168D push 1 .text:1C00168F mov ecx, [ebp+SectionLength] .text:1C001692 push ecx .text:1C001693 mov edx, [ebp+fp] .text:1C001696 push edx .text:1C001697 call imsSeek .text:1C00169C add esp, 0Ch The routine follows on to handle the Image Data section. First, it reads the compression method marker and prepares some internal structures. Then, the function performs the following quite interesting computations First, the channel count is clamped to 3. .text:1C0018FC movzx ecx, [ebp+PsdChannelCount] .text:1C001900 cmp ecx, 3 .text:1C001903 jge short loc_1C001911 .text:1C001905 movzx edx, [ebp+PsdChannelCount] .text:1C001909 mov [ebp+ChannelCount], edx .text:1C00190F jmp short loc_1C00191B .text:1C001911 ; ------------------------------------------------------------------------ .text:1C001911 .text:1C001911 loc_1C001911: ; CODE XREF: sub_1C001000+903j .text:1C001911 mov [ebp+ChannelCount], 3 .text:1C00191B .text:1C00191B loc_1C00191B: ; CODE XREF: sub_1C001000+90Fj .text:1C00191B mov ax, word ptr [ebp+ChannelCount] .text:1C001922 mov [ebp+ChannelCount$1], ax The bit depth is also manipulated a bit: .text:1C001929 movzx ecx, [ebp+PsdBitDepth] .text:1C00192D cmp ecx, 16 .text:1C001930 jnz short loc_1C00193E .text:1C001932 mov [ebp+BitDepth], 24 .text:1C00193C jmp short loc_1C001948 .text:1C00193E ; ------------------------------------------------------------------------ .text:1C00193E .text:1C00193E loc_1C00193E: ; CODE XREF: sub_1C001000+930j .text:1C00193E movsx edx, [ebp+PsdBitDepth] .text:1C001942 mov [ebp+BitDepth], edx .text:1C001948 .text:1C001948 loc_1C001948: ; CODE XREF: sub_1C001000+93Cj .text:1C001948 mov ax, word ptr [ebp+BitDepth] .text:1C00194F mov [ebp+BitDepth$1], ax And then the following, calculating the amount of bytes per one image line: .text:1C001956 movsx ecx, [ebp+BitDepth$1] ; <<< SIGN EXTENSION .text:1C00195D imul ecx, [ebp+PsdImageWidth] .text:1C001961 movzx edx, [ebp+ChannelCount$1] .text:1C001968 imul ecx, edx .text:1C00196B mov [ebp+BytesPerLine], ecx .text:1C001971 mov eax, [ebp+BytesPerLine] .text:1C001977 add eax, 7 .text:1C00197A shr eax, 3 .text:1C00197D mov [ebp+BytesPerLine], eax .text:1C001983 mov ecx, [ebp+BytesPerLine] .text:1C001989 add ecx, 3 .text:1C00198C shr ecx, 2 .text:1C00198F shl ecx, 2 .text:1C001992 mov [ebp+BytesPerLine], ecx which is roughly equivalent to: BytesPerLine = ((int16_t)BitDepth) * PsdImageWidth * ChannelCount; BytesPerLine = (BytesPerLine + 7) >> 3; /* Round up to bytes */ BytesPerLine = ((BytesPerLine + 3) >> 2) << 2; /* Round up to DWORD count */ Note the BitDepth value is sign-extended from 16-bit to 32-bit. The function then proceeds to allocate memory: .text:1C0019C8 mov eax, [ebp+ImageHeight] .text:1C0019CE mov [ebp+ImageHeight$1], eax .text:1C0019D4 mov ecx, [ebp+BytesPerLine] .text:1C0019DA imul ecx, [ebp+ImageHeight$1] .text:1C0019E1 mov [ebp+var_B0], ecx .text:1C0019E7 mov edx, [ebp+var_B0] .text:1C0019ED add edx, [ebp+BytesPerLine] .text:1C0019F3 push edx ; dwBytes .text:1C0019F4 push 42h ; uFlags .text:1C0019F6 call ds:GlobalAlloc .text:1C0019FC mov [ebp+ImageBufferHandle], eax .text:1C001A02 cmp [ebp+ImageBufferHandle], 0 .text:1C001A09 jz loc_1C001CD5 .text:1C001A0F mov eax, [ebp+ImageBufferHandle] .text:1C001A15 push eax ; hMem .text:1C001A16 call ds:GlobalLock .text:1C001A1C mov [ebp+ImageBufferPtr], eax After some further manipulations, we reach a call to the sub_1C001D70 function, which is responsible for image decompression: .text:1C001B59 lea ecx, [ebp+var_C4] .text:1C001B5F push ecx .text:1C001B60 mov dx, [ebp+PsdImageCompressionMethod] .text:1C001B67 push edx .text:1C001B68 mov eax, [ebp+ImageHeight$1] .text:1C001B6E push eax .text:1C001B6F lea ecx, [ebp+PsdSignature] .text:1C001B72 push ecx .text:1C001B73 mov edx, [ebp+ImageBufferPtr] .text:1C001B79 push edx .text:1C001B7A mov eax, [ebp+fp] .text:1C001B7D push eax .text:1C001B7E call sub_1C001D70 The function repeats the buffer size calculations, with one minor difference: .text:1C001DCB mov ecx, [ebp+PsdFileHeaderPtr] .text:1C001DCE movzx edx, [ecx+PsdFileHeader.BitDepth] .text:1C001DD2 mov eax, [ebp+PsdFileHeaderPtr] .text:1C001DD5 imul edx, [eax+PsdFileHeader.Width] .text:1C001DD9 add edx, 7 .text:1C001DDC shr edx, 3 .text:1C001DDF mov [ebp+BytesPerChannelLine], edx ... .text:1C001E2D mov ecx, [ebp+BytesPerChannelLine] .text:1C001E30 push ecx ; dwBytes .text:1C001E31 call sub_1C003490 .text:1C001E36 add esp, 4 .text:1C001E39 mov [ebp+ChannelLineBufferPtr], eax The BitDepth value is not sign-extended when calculating the size required for the line buffer allocated via a call to sub_1C003490. Note that, via a specially crafted image, it may be possible to exploit this discrepancy and force the program to allocate two buffers of different size (with the full image buffer being smaller). The function then enters a loop, processing each color channel and another, inner loop that handles scan line decompression. This is where an overflow actually occurs. .text:1C001E93 ; Read and decompress a line .text:1C001E93 mov cx, [ebp+PsdImageCompressionMethod] .text:1C001E97 push ecx .text:1C001E98 mov edx, [ebp+BytesPerChannelLine] .text:1C001E9B push edx .text:1C001E9C mov eax, [ebp+ChannelLineBufferPtr] .text:1C001E9F push eax .text:1C001EA0 mov ecx, [ebp+fp] .text:1C001EA3 push ecx .text:1C001EA4 call sub_1C002070 .text:1C001EA9 add esp, 10h .text:1C001EAC .text:1C001EAC ; Calculate the offset into the image buffer .text:1C001EAC mov [ebp+var_10], eax .text:1C001EAF mov edx, [ebp+ChannelLineBufferPtr] .text:1C001EB2 mov [ebp+var_2C], edx .text:1C001EB5 mov eax, [ebp+CurrentLine] .text:1C001EB8 imul eax, [ebp+BytesPerLine] .text:1C001EBC add eax, [ebp+CurrentChannel] .text:1C001EBF add eax, [ebp+ImageBufferPtr] .text:1C001EC2 mov [ebp+ImageBufferLinePtr], eax .text:1C001EC5 .text:1C001EC5 ; Loop and copy the channel data into the image buffer .text:1C001EC5 mov [ebp+var_28], 0 .text:1C001ECC jmp short loc_1C001ED7 .text:1C001ECE ; ------------------------------------------------------------------------ .text:1C001ECE .text:1C001ECE loc_1C001ECE: ; CODE XREF: sub_1C001D70+18Cj .text:1C001ECE mov ecx, [ebp+var_28] .text:1C001ED1 add ecx, 1 .text:1C001ED4 mov [ebp+var_28], ecx .text:1C001ED7 .text:1C001ED7 loc_1C001ED7: ; CODE XREF: sub_1C001D70+15Cj .text:1C001ED7 mov edx, [ebp+var_28] .text:1C001EDA cmp edx, [ebp+BytesPerChannelLine] .text:1C001EDD jge short loc_1C001EFE .text:1C001EDF mov eax, [ebp+ImageBufferLinePtr] .text:1C001EE2 mov ecx, [ebp+var_2C] .text:1C001EE5 mov dl, [ecx] .text:1C001EE7 mov [eax], dl .text:1C001EE9 mov eax, [ebp+var_2C] .text:1C001EEC add eax, 1 .text:1C001EEF mov [ebp+var_2C], eax .text:1C001EF2 movzx ecx, [ebp+ChannelCount$1] .text:1C001EF6 add ecx, [ebp+ImageBufferLinePtr] .text:1C001EF9 mov [ebp+ImageBufferLinePtr], ecx .text:1C001EFC jmp short loc_1C001ECE The overflown buffer is located on the heap, which in the context of this product may make exploitation more difficult, but arbitrary code execution cannot be ruled out. References http://secunia.com/advisories/59995/ http://secunia.com/secunia_research/2015-2/ http://www.oracle.com/us/technologies/embedded/025613.htm http://www.adobe.com/devnet-apps/photoshop/fileformatashtml/ View the full article
-
By Poul Wann, Security Specialist There has recently been a lot of attention given to the security issue commonly referred to as POODLE (Padding Oracle On Downgraded Legacy Encryption) against the SSL v3 protocol. This security issue, due to its nature as a weakness within a protocol, affects many applications and devices. SSL v3 was introduced by Netscape in 1995 and has been replaced in 1999 by TLS v1.0 which itself has seen continuous updates and refinements, most recently in 2008 with TLS v1.2. Each revision has introduced security hardening and better algorithms. While there has been ample time to migrate away from SSL v3, it is still widely supported. The POODLE security issue allows decryption of captured SSL v3 traffic by means of issuing multiple attacker-controlled requests and analyzing server responses via a Man-in-the-Middle attack. While the flaw in SSL v3 is serious, a proper attack requires tricking a... View the full article
-
There has recently been a lot of attention given to the security issue commonly referred to as POODLE (Padding Oracle On Downgraded Legacy Encryption) against the SSL v3 protocol. This security issue, due to its nature as a weakness within a protocol, affects many applications and devices. SSL v3 was introduced by Netscape in 1995 and has been replaced in 1999 by TLS v1.0 which itself has seen continuous updates and refinements, most recently in 2008 with TLS v1.2. Each revision has introduced security hardening and better algorithms. While there has been ample time to migrate away from SSL v3, it is still widely supported. The POODLE security issue allows decryption of captured SSL v3 traffic by means of issuing multiple attacker-controlled requests and analyzing server responses via a Man-in-the-Middle attack. While the flaw in SSL v3 is serious, a proper attack requires tricking a user with a vulnerable browser to visit a malicious website containing an actual exploitation script performing crafted requests. The attack demonstrated by the authors is able to compromise confidentiality of a chosen SSL v3 session only, and does not allow for any further direct compromise. Given the limited gain and high requirements for the attack to succeed, Secunia will only issue advisories for software and devices where there is a realistic vector for POODLE and where affected products cannot easily be configured to disallow SSLv3 traffic. We encourage all users to disable SSL v3 support in all products where possible and e.g. utilize TLS v1.2 instead. For more information, please see: https://www.openssl.org/~bodo/ssl-poodle.pdf http://secunia.com/advisories/60056/ View the full article
-
Update, October 3: vulnerabilities in Bash: The discovery of the Shellshock vulnerability has opened up Bash like a can of worms, with the ensuing discovery of several other vulnerabilities and rumors of more. With the vulnerabilities come a host of official and unofficial patches with varying degrees of efficiency across a number of affected product vendors, including Linux distributions, Apple and IBM. It is, in a word, chaotic. We recommend that System Administrators stay alert and keep up continuous patching, mitigating, verifying; patching, mitigating, verifying; patching, mitigating, verifying … you get the idea. Secunia continues to publish assessed Advisories on the vulnerabilities in Bash. Keep track: CVE-2014-6271 CVE-2014-7169 CVE-2014-6277 CVE-2014-6278 CVE-2014-7186 CVE-2014-7187 Update, September 30: The "Shellshock" vulnerability in Bash Since the first vulnerability in Bash was disclosed and the first patch was released, a number of unofficial patches have been released, and several additional vulnerabilities have been discovered in... View the full article
-
Update, October 3: vulnerabilities in Bash: The discovery of the Shellshock vulnerability has opened up Bash like a can of worms, with the ensuing discovery of several other vulnerabilities and rumors of more. With the vulnerabilities come a host of official and unofficial patches with varying degrees of efficiency across a number of affected product vendors, including Linux distributions, Apple and IBM. It is, in a word, chaotic. We recommend that System Administrators stay alert and keep up continuous patching, mitigating, verifying; patching, mitigating, verifying; patching, mitigating, verifying … you get the idea. Secunia continues to publish assessed Advisories on the vulnerabilities in Bash. Keep track: CVE-2014-6271 CVE-2014-7169 CVE-2014-6277 CVE-2014-6278 CVE-2014-7186 CVE-2014-7187 Update, September 30: The “Shellshock” vulnerability in Bash Since the first vulnerability in Bash was disclosed and the first patch was released, a number of unofficial patches have been released, and several additional vulnerabilities have been discovered in Bash. Only two vulnerabilities in Bash have official patches at this stage: CVE-2014-6271 and CVE-2014-7169 Update, Sept 26: The “Shellshock” vulnerability in Bash To date, Secunia has published 9 Secunia Advisories for products affected by Shellshock. On September 25 patches were released by a number of vendors, including Debian and Red Hat. Unfortunately, they appeared to be incomplete, and therefore ineffective. Red Hat and Debian have therefore pushed new patches earlier today. GNU Bash is expected to release official new patches today, Friday 26, to replace the original one that proved ineffective. Secunia will continuously update our advisories as new information becomes available. If you are a member of the Secunia Community, you can keep track of Bash related Secunia Advisories here: http://secunia.com/_CVE-2014-6271_ and here: http://secunia.com/_CVE-2014-7169_ The “Shellshock” vulnerability in Bash 16:20 CET on the 25th September 2014 Secunia has currently written 1 Secunia Advisory for the GNU Bash Shell Function Definitions OS Commands Injection Vulnerability (CVE-2014-6271), popularly referred to as the “Shellshock bug”: http://secunia.com/advisories/61541. The vulnerability has received the Secunia rating “Highly Critical” and the current solution status is unpatched, as the previously released patches are reported to be ineffective. There will be additional advisories issued for products bundled with Bash as their status becomes verified. The impact of the vulnerability in Bash is that it can be exploited to effectively take over your systems. Reportedly, Bash is currently being exploited in limited attacks in the wild. What is Shellshock? The vulnerability is caused due to an error when parsing shell function definitions passed via environment variables and can be exploited to e.g. execute arbitrary shell commands via a specially crafted environment variable value passed to a CGI script via certain HTTP headers. There are multiple attack vectors for Bash, because a lot of organizations will be using Bash in different parts of their systems, and presumably many old devices on networks will be vulnerable. What next? GNU, the Open Source project that has developed Bash, is a large and widely used project and should have the resources available to deal with the issue. They have in fact already released a patch – unfortunately it has proved ineffective, and there is therefore no official patch available at this stage. We are, however, expecting GNU Bash to release another patch today due to the criticality of this vulnerability. But the fact that the first patch wasn’t adequate, could indicate that they lack proper security quality assurance of their patches. Worse than Heartbleed? Compared to Heartbleed, the vulnerability in OpenSSL from earlier this year, the vulnerability in Bash is worse: Heartbleed “only” enabled hackers to extract information. The vulnerability in Bash enables hackers to execute commands to take over your servers and systems. We have only seen the tip of the iceberg so far, and only the most obvious attack vectors. Secunia will continuously follow this, and update our advisories as new information becomes available. View the full article
-
By Hossein Lotfi, Security specialist 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. Reproduction: ------------------ 1) Install Microsoft Office 2003. Install Service Pack 3 for this... View the full article
-
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. 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 sharedGRPHFLT” (e.g. “C:Program FilesCommon Filesmicrosoft sharedGRPHFLT“). 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]: 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 [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 .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 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 .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 .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 .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. Exploitation: —————– 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. .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 References: —————- 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 View the full article
-
The Secunia Country Reports for Q3 2013 have just aired and once again Microsoft XML Core Services (MSXML) 4.x tops the list of “Most Exposed” software among users of the Secunia PSI. Microsoft XML Core Services has topped the list since December 2012. There are currently 2 vulnerabilities in Microsoft XML Core Services. The vulnerabilities affect a large percentage of computer users, as can be seen from the Secunia Country Reports, which describe the state of security on private computers. The reports have the Microsoft program topping the list in 12 different countries. The data from the US Country Report serves as an example of how widespread the program - and how large the number of users that have not yet patched it - is: In the US, 79% of PC users who use Secunia PSI had Microsoft XML Core Services installed in Q3 2013. 50 % of these users... View the full article