|
Brought to you by:
Suppliers of:
|
|
|
| |
| There is a flaw in QuickTime FLIC parser, the flaw is located within the "COLOR_64 chunk" Quicktime parser. Since proper checking is not performed, a large amount of heap can be overwritten with controlled values. This flaw could lead to a remote code execution,if an attacker tricks the victim to visit a malicious webpage with a specially crafted .fli animation embedded. |
| |
Credit:
The information has been provided by Reversemode.
The original article can be found at: http://www.reversemode.com/index.php?option=com_remository&Itemid=2&func=fileinfo&id=25
|
| |
Vulnerable Systems:
* Apple Quicktime version 7.1 and prior
Immune Systems:
* Apple Quicktime version 7.1.3
FLC/FLI format overview:
FLIC files are structured in a hierarchy of chunks. A chunk contains a fixed part and a variable part. Every chunk starts with a 6-byte header, that contains the size (four bytes) and the type (two bytes) for the chunk
FRAME CHUNK HEADER
typedef struct {
DWORD size; /* Size of the chunk, including subchunks */
WORD type; /* Chunk type: 0xF1FA */
WORD chunks; /* Number of subchunks */
WORD delay; /* Delay in milliseconds */
short reserved; /* Always zero */
ushort width; /* Frame width override (if non-zero) */
ushort height; /* Frame height override (if non-zero) */
} FRAME_TYPE;
Chunk type: 0xB COLOR_64 64-level colour palette
The data in the COLOR_64 chunk is organized in packets. The first word next to the chunk header is the number of packets of the chunk. Each packet is structured in a 1-byte skip count, a 1-byte copy count and a series of 3-byte RGB values (the "copy count" gives us the number of RGB triplets). If the copy count is zero, there are 256 RGB triplets in the packet.
For example:
FF,40,r,g,b skip 0xFF entries (one entry= 4bytes), change 0x40 entries
Let's see QuickTime parses the chunk:
.text:679FE4DA mov eax, [ebx]
.text:679FE4DC mov cx, [eax+6] ;number of subchunks
.text:679FE4E0 mov edx, [ebp+6Ch]
.text:679FE4E3 mov esi, [edx]
.text:679FE4E5 add eax, 6
.text:679FE4E8 add esp, 4
.text:679FE4EB add eax, 2 ;pointing to 1-byte skip field
.text:679FE4EE test cx, cx
.text:679FE4F1 jbe loc_679FE5A6
.text:679FE4F7 movzx ecx, cx
.text:679FE4FA mov [esp+24h+var_10], ecx ; save number of subchunks
.text:679FE4FE mov edi, edi
.text:679FE500
.text:679FE500 loc_679FE500: ; CODE XREF: sub_679FE420+180#j
.text:679FE500 movzx cx, byte ptr [eax] ; 1-byte skip field.
.text:679FE504 inc eax
.text:679FE505 test cx, cx
.text:679FE508 jbe short loc_679FE510
.text:679FE50A movzx edx, cx
.text:679FE50D lea esi, [esi+edx*4] ; skip the bytes +align
.text:679FE510 ; esi pointing to heap chunk
.text:679FE510 loc_679FE510: ; CODE XREF: sub_679FE420+E8#j
.text:679FE510 movzx cx, byte ptr [eax] ; 1-byte count field.
.text:679FE514 inc eax
.text:679FE515 test cx, cx
.text:679FE518 jnz short loc_679FE521
.text:679FE51A mov ecx, 100h ; if bytecount=0 bytecount=0100h
; so the entire palette changes.
.text:679FE51F jmp short loc_679FE523
.text:679FE521 ;
.text:679FE521
.text:679FE521 loc_679FE521: ; CODE XREF: sub_679FE420+F8#j
.text:679FE521 jbe short loc_679FE59C
.text:679FE523
.text:679FE523 loc_679FE523: ; CODE XREF: sub_679FE420+FF#j
.text:679FE523 movzx ecx, cx
.text:679FE526 mov [esp+24h+arg_8], ecx ; counter= bytecount;
.text:679FE52A lea ebx, [ebx+0]
.text:679FE530
.text:679FE530 loc_679FE530: ; CODE XREF: sub_679FE420+176#j
.text:679FE530 mov cl, [eax] ; byte R (R,G,B)
.text:679FE532 mov dl, [eax+1] ; byte G (R,G,B)
.text:679FE535 mov bl, byte ptr [esp+24h+arg_0]
.text:679FE539 inc eax
.text:679FE53A inc eax ;ptr++
.text:679FE53B mov byte ptr [esp+24h+arg_C], dl
.text:679FE53F mov dl, [eax] ; byte B(R,G,B)
.text:679FE541 inc eax
.text:679FE542 test bl, bl
.text:679FE544 mov byte ptr [esp+24h+arg_4], dl
.text:679FE548 jz short loc_679FE574 ;RGB adjustment begin
.text:679FE54A mov dl, cl
.text:679FE54C shr dl, 4
.text:679FE54F shl cl, 2
.text:679FE552 or cl, dl
.text:679FE554 mov dl, byte ptr [esp+24h+arg_C]
.text:679FE558 mov bl, dl
.text:679FE55A shr bl, 4
.text:679FE560 or bl, dl
.text:679FE562 mov dl, byte ptr [esp+24h+arg_4]
.text:679FE566 mov byte ptr [esp+24h+arg_C], bl
.text:679FE56A mov bl, dl
.text:679FE56C shr bl, 4
.text:679FE56F shl dl, 2
.text:679FE572 or dl, bl
.text:679FE574
.text:679FE574 loc_679FE574: ; CODE XREF: sub_679FE420+128#j
.text:679FE574 xor ebx, ebx
.text:679FE576 mov bh, cl
.text:679FE578 movzx ecx, dl
.text:679FE57B add esi, 4
.text:679FE57E mov bl, byte ptr [esp+24h+arg_C]
.text:679FE582 shl ebx, 8
.text:679FE585 or ebx, ecx ;RGB adjustment end
.text:679FE587 mov ecx, [esp+24h+arg_8]
.text:679FE58B mov [esi-4], ebx ; OVERFLOW
.text:679FE58E inc word ptr [edi]
.text:679FE591 dec ecx ; Copycount --
.text:679FE592 mov [esp+24h+arg_8], ecx
.text:679FE596 jnz short loc_679FE530
.text:679FE598 mov ebx, [esp+24h+var_C]
.text:679FE59C
.text:679FE59C loc_679FE59C: ; CODE XREF:
sub_679FE420:loc_679FE521#j
.text:679FE59C dec [esp+24h+var_10]
So, the flaw is that QuickTime allocates 0x100*sizeof(DWORD) in order to copy just one palette. However, the parameters are directly copied from FLC/FLI/CEL file without validate them. Thus, we can overwrite a large amount of heap memory using controlled DWORD values. The total amount of heap memory we could overwrite, is the result of the following formula:
Max = MaxNumberofSubChunks * ( sizeof(DWORD) * sizeof(PALETTE) )
Max = FFFFh * (4* 100h);
Max = 0x3FFFC00; a lot...
In addition, we could overwrite just certain blocks on the heap, thus controlling the memory corrupted. How? Using the byte Skip field ,remember:
.text:679FE50D lea esi, [esi+edx*4] ; skip the bytes +align
The amount of bytes overwritten each time also could be controlled using CopyCount Field
The asm code previously explained would appear in C as follows:
[...]
ptr_heap=(LPVOID)malloc(0x100*sizeof(DWORD)); // chungootronics from the outer space
[...]
for (i = 0; i < subchunks; i++) {
if(buf[stream++] != 0) ptr_heap += buf[stream]; // colors to skip (distance )
CopyCount = buf[stream++]; // entries to change
if (CopyCount == 0) Copycount = 0x100; //(entire palette)
for (j = 0; j < CopyCount; j++)
{
...HEAP OVERFLOW
};
}
|
|
|
|
|