Search
Apple QuickTime Player H.264 issues
- Details
- Category: Advisories
- Published on Thursday, 01 September 2011 20:26
- Written by rmallof
Some months ago, analyzing module in charge to parse H.264 compressed data in QuickTime Player, were found exactly two vulnerabilities in the way it do it.
First we need document this codec. The basic from http://en.wikipedia.org/wiki/H.264/MPEG-4_AVC :
“H.264/MPEG-4 Part 10 or AVC (Advanced Video Coding) is a standard for video compression, and is currently one of the most commonly used formats for the recording, compression, and distribution of high definition video.”
Looking for more info, could be found that the coded video data is organized into NAL Units, which contains besides that a header with information about data (like type of the structure contained), and the size of each variable:

This pseudo-code structure and the other that we need can be found at ITU-T H.264 with terms, algorithms to encode / decode data, and so on; speaking regarding algorithms and according to documentation, we should find three parsers:
- to Exponential-Golomb coding;
- to CAVLC for transform coefficients levels;
- to CABAC for slice data;
Exponential-Golomb is responsible of decoding the syntax elements of the corresponding structures, and necessary for us on this case.
The process to decode unsigned integers begins looking for the MSB in stream setted to 1 and counting the leading bits equals to zero. Some like this:
zeroBits = -1;
for(b = 0; !b; zeroBits++) {
b = read_bits(1);
}
Then, zeroBits acts like exponent in base two and like the number of bits to read this time:
codeNum = (2**zeroBits) - 1 + read_bits(zeroBits);
Like you can see, this algorithm allows us generate values from a base ((2 ** zeroBits) - 1) and then add it to an offset (read_bits(zeroBits)), our selected value.
Since we have the exponent value equals to number of bits to read, when we need to read a large offset the base value will grow too, losing precision to generate all values. This issue will bring us problems in the exploitation process, as we shall see later.
Here is code example about implementation of last algorithm from QuickTimeH264.qtx:
|
.text:681D4A39 loc_681D4A39: .text:681D4A39 bsr eax, [esp+84h+SliceHeader] .text:681D4A3E mov ecx, 3Fh .text:681D4A43 cmovz eax, ecx .text:681D4A46 xor eax, 1Fh .text:681D4A49 mov [esp+84h+var_48], eax .text:681D4A4D mov edx, [esp+84h+var_48] .text:681D4A51 mov eax, [esp+84h+SliceHeader] .text:681D4A55 lea ecx, [edx+1] .text:681D4A58 shl eax, cl .text:681D4A5A mov ecx, 20h .text:681D4A5F sub ecx, edx .text:681D4A61 mov ebx, 1 .text:681D4A66 shr eax, cl .text:681D4A68 mov ecx, edx .text:681D4A6A neg ecx .text:681D4A6C sbb ecx, ecx .text:681D4A6E and eax, ecx .text:681D4A70 mov ecx, edx .text:681D4A72 shl ebx, cl .text:681D4A74 lea edx, [ebp+edx*2+1] .text:681D4A78 mov [esp+84h+SliceHeader], eax .text:681D4A7C lea eax, [ebx+eax-1] .text:681D4A80 mov ebx, edx .text:681D4A82 shr edx, 3 .text:681D4A85 add esi, edx |
Decoding unsigned integers with Exponential - Golomb
0k, as I said, this is the process to decode unsigned integers for structures, so what about this structures? His names are Sequence Parameter Set (SPS), Picture Parameter Set (PPS), and Slice Header, and here are their definitions:
- Sequence parameter set: A syntax structure containing syntax elements that apply to zero or more entire coded video sequences as determined by the content of a seq_parameter_set_id syntax element found in the picture parameter set referred to by the pic_parameter_set_id syntax element found in each slice header:

- Picture parameter set: A syntax structure containing syntax elements that apply to zero or more entire codedpictures as determined by the pic_parameter_set_id syntax element found in each slice header:

- Slice header: A part of a coded slice containing the data elements pertaining to the first or all macroblocks represented in the slice (this is an integer number of macroblocks or macroblock pairs ordered consecutively in the raster scan within a particular slice group):

Knowing QuickTime movie container format (“.mov” extension) are organized by Atoms, we could situate the H.264 bit stream containing last three structs on MDAT atom .
Thus QuickTime starts looking for Nal Units on stream with nal_unit_type indicating SPS or PPS structures on 6810F040 and checks if any. If yes, first decodes SPS on QuickTimeH264.qtx!68192FB0 and then PPS on QuickTimeH264.qtx!68190100; the algorithm need decode last two structs to parse Slice Header.
After at QuickTimeH264.qtx!68194810, while decoding Slice Header, application checks either Slice_Header.Num_Ref_IDX_Active_Override_Flag is setted or not, a flag indicating if our Slice Header has been created with Num_Ref_IDX_l0_Active_Minus1 and Num_Ref_IDX_l1_Active_Minus1 fields.
What says specification about this values?:
num_ref_idx_l0_active_minus1 specifies the maximum reference index for reference picture list 0 that shall be used to decode each slice of the picture in which list 0 is used when num_ref_idx_active_override_flag is equal to 0 for the slice. […]The value of num_ref_idx_l0_active_minus1 shall be in the range of 0 to 31, inclusive.
A new structure is present, Slice_Header.ref_pic_list_reordering, and last fields are indicating size of data contained on here:

Looking for members on spec, we can see:
'ref_pic_list_reordering_flag_l0 equal to 1 specifies that the syntax element
reordering_of_pic_nums_idc is present for specifying reference picture list 0. ref_pic_list_reordering_flag_l0 equal to 0 specifies that this syntax element is not present.
When ref_pic_list_reordering_flag_l0 is equal to 1, the number of times that reordering_of_pic_nums_idc is not equal to 3 following ref_pic_list_reordering_flag_l0 shall not exceed
num_ref_idx_l0_active_minus1 + 1.
When RefPicList0[ num_ref_idx_l0_active_minus1 ] in the initial reference picture list produced as specified in subclause 8.2.4.2 is equal to "no reference picture", ref_pic_list_reordering_flag_l0 shall be equal to 1 and reordering_of_pic_nums_idc shall not be equal to 3 until RefPicList0[num_ref_idx_l0_active_minus1 ] in the reordered list produced as specified in subclause 8.2.4.3 is not equal to "no reference picture".'
And:
'reordering_of_pic_nums_idc together with abs_diff_pic_num_minus1 or long_term_pic_num specifies which of the reference pictures are re-mapped. The values of reordering_of_pic_nums_idc are specified below. The value of the first reordering_of_pic_nums_idc that follows immediately after ref_pic_list_reordering_flag_l0 or ref_pic_list_reordering_flag_l1 shall not be equal to 3.
reordering_of_pic_nums_idc Reordering specified
0 abs_diff_pic_num_minus1 is present and corresponds to a difference to subtract from a picture number prediction value
1 abs_diff_pic_num_minus1 is present and corresponds to a difference to add to a picture number prediction value
2 long_term_pic_num is present and specifies the long-term picture number for a reference picture
3 End loop for reordering of the initial reference picture list”
This number is result of decoding our crafted data, and as you can see, his value indicates type of reference pictures, but value 3 indicates end of stream being decoded.
In other words, it break loop.
Also, if we look PPS structure we will see it has fields with same name, num_ref_idx_l0_active_minusX, cause this will be used as values to Slice Header fields if Slice_Header.Num_Ref_IDX_Active_Override_Flag == 0:
|
.text:681950BB check_reordering_flag: ; CODE XREF: parseSliceHeader+88Cj .text:681950BB ; parseSliceHeader+891j .text:681950BB ; parseSliceHeader+896j .text:681950BB ; parseSliceHeader+89Bj .text:681950BB ; parseSliceHeader+8A0j .text:681950BB shr eax, 1Fh ; Bit - stream .text:681950BE mov [edi+Slice_Header.Num_Ref_IDX_Active_Override_Flag], al .text:681950C1 mov eax, [esp+84h+var_68] .text:681950C5 add eax, 1 .text:681950C8 mov edx, eax .text:681950CA and edx, 7 .text:681950CD shr eax, 3 .text:681950D0 mov ebp, edx .text:681950D2 add esi, eax .text:681950D4 mov [esp+84h+var_68], ebp .text:681950D8 mov [esp+84h+counter], esi .text:681950DC mov ecx, [esp+84h+counter] .text:681950E0 mov edx, ecx .text:681950E2 and edx, 0FFFFFFFCh .text:681950E5 neg ecx .text:681950E7 mov ebx, [edx] .text:681950E9 lea ecx, [edx+ecx+4] .text:681950ED mov edx, [edx+4] .text:681950F0 bswap ebx .text:681950F2 shl ecx, 3 .text:681950F5 bswap edx .text:681950F7 shrd edx, ebx, cl .text:681950FA cmp ecx, 20h ; ' ' .text:681950FD cmovz edx, ebx .text:68195100 mov [esp+84h+SliceHeader], edx .text:68195104 mov eax, [esp+84h+SliceHeader] .text:68195108 mov ecx, ebp .text:6819510A shl eax, cl .text:6819510C cmp [edi+Slice_Header.Num_Ref_IDX_Active_Override_Flag], 0 .text:68195110 mov [esp+84h+SliceHeader], eax .text:68195114 jz default ... .text:681951F3 default: ; CODE XREF: parseSliceHeader+904j .text:681951F3 mov ecx, [esp+84h+PPS] .text:681951F7 mov edx, [ecx+PPS.Num_Ref_IDX_l0_Active_Minus1] .text:681951FA mov [edi+Slice_Header.Num_Ref_IDX_l0_Active_Minus1], edx .text:681951FD mov ecx, [ecx+PPS.Num_Ref_IDX_l1_active_minus1] .text:68195200 mov [edi+Slice_Header.Num_Ref_IDX_l1_active_minus1], ecx |
But if flag is setted, Slice_Header.Num_Ref_IDX_l0_Active_Minus1 and/or Slice_Header.Num_Ref_IDX_l1_Active_Minus1 are decoded again from input stream on fields within the same name on Slice_Header:
|
.text:68195114 jz default .text:6819511A bsr eax, [esp+84+SliceHeader] ; decode our value .text:6819511F mov ecx, 3Fh ; '?' .text:68195124 cmovz eax, ecx .text:68195127 xor eax, 1Fh .text:6819512A mov [esp+84h+var_34], eax .text:6819512E mov edx, [esp+84h+var_34] .text:68195132 mov eax, [esp+84h+SliceHeader] .text:68195136 lea ecx, [edx+1] .text:68195139 shl eax, cl .text:6819513B mov ecx, 20h .text:68195140 sub ecx, edx .text:68195142 mov ebx, 1 .text:68195147 shr eax, cl .text:68195149 mov ecx, edx .text:6819514B neg ecx .text:6819514D sbb ecx, ecx .text:6819514F and eax, ecx .text:68195151 mov ecx, edx .text:68195153 shl ebx, cl .text:68195155 mov [esp+84h+SliceHeader], eax .text:68195159 mov ecx, ebp .text:6819515B lea eax, [ebx+eax-1] ; get size .text:6819515F mov [edi+Slice_Header.Num_Ref_IDX_l0_Active_Minus1], eax ; p0wned! |
Num_Ref_IDX_lX_Active_Minus1 values has been checked on QuickTimeH264.qtx!68190100 (>= 0 && <= 31), but this time simply not.
Then this value is used to decode ref_pic_list_reordering, if any, to stack-based buffer present on QT Slice Header struct:
|
00000000 SliceHeader struct ... 00000150 ref_pic_list_reordering_buffer_l0 db 132 dup(?) 000001d4 ref_pic_list_reordering_buffer_l1 db 132 dup(?) ...
|
Like you can see on ref_pic_list_reordering definition we need set some fields more to the decoding :
- ref_pic_list_reordering_flag_l0/1
- reordering_of_pic_nums_idc
Remembering to set reordering_of_pic_nums_idc != 3 to not break loop and without checks against Num_Ref_IDX_lX_Active_Minus1, we can craft a stream (..F8025b80..) to overflow Slice_Header.ref_pic_list_reordering_buffer_l0 or Slice_Header.ref_pic_list_reordering_buffer_l1 in this loop (QuickTimeH264!681952A0):

Exactly:
|
.text:68195289 mov [esp+84h+counter], 0 .text:68195291 lea ebp, [edi+Slice_Header.ref_pic_list_reordering_buffer_l0] .text:68195297 jmp short get_reordering_of_pic_nums_idc ... .text:681952A0 get_reordering_of_pic_nums_idc: .text:6819531D bsr eax, [esp+84h+SliceHeader] ...
.text:68195360 mov [ebp+0], eax ; stack overflow! .text:68195363 jmp short check_limit .text:681953B4 check_limit: ; CODE XREF: parseSliceHeader+B53j .text:681953B4 mov ecx, [esp+84h+var_68] .text:681953B8 lea eax, [ecx+edx*2+1] ... .text:681953D2 mov ecx, [esp+84h+counter] .text:681953D6 cmp ecx, [edi+Slice_Header.Num_Ref_IDX_l0_Active_Minus1] .text:681953D9 mov [esp+84h+SliceHeader], eax .text:681953DD ja out .text:681953E3 add [esp+84h+counter], 1 .text:681953E8 add ebp, 4 .text:681953EB jmp get_reordering_of_pic_nums_idc
|
+ Exploitation:
We already know Exponential-Golomb coding and it losses precission when we set a high base value, as shown in the following chart (x = offset, y = base):

limiting our data generation; but looking for a nice address we could hit one decodable: QuickTimePlayerLauncher.exe!0x00441FFF jmp esp, or encoded: 0x00000221.
Overwritting RET address with data resulting of decode 0x221, we can redirect flow while ESP register are pointing to our decoded data, but to make the job easier we will insert in stream a trampoline to our uncoded ShellCode executing minimum coded opcodes.
For this, we going to follow next steps:
1) Adding, ORing and Shifting values we will get relative distance value of pointer (saved in the stack) pointing to our mapped file from our position.
2) Substract last value to ESP.
3) POPing from stack a pointer to our buffer to EDI.
4) Add value from 1st step to EDI 4 times, just to point to our ShellCode.
5) CALL EDI.
Here are two images terminating this process:

Zooming:

A file sample is avaible cliking here.
Advisories: ZDI-11-255 & ZDI-11-257.
SSD-1012211 - IBM Lotus Domino 8.5.2 Nnotes.dll!NSFComputeEvaluateExt Stack-Based Buffer Overflow
- Details
- Category: Advisories
- Published on Monday, 07 March 2011 01:12
- Written by rmallof
Hi,
some months ago, we contacted with SecuriTeam Secure Disclosure to tramit IBM vulnerability, and finally, today customer published advisory regarding IBM Lotus Domino 8.5.2 issue: here.
As his name suggest, WebAdmin.nsf module is administration tool to configure nHTTP.exe server. On this control panel, after login, server allows us configurate multiple options, ie open ports on server.
For this functionality, user sends next POST request to server:
__Click=0
&tHPRAgentName=wqsToolConfig$UserL2 <- 0wnd
&tHPRXml1=<?xml version='1.0' encoding='UTF-8' ?><tool id='portConfig'><port
name='LAN3' newname='LAN3' driver='NETBIOS' new='0' modified='1' deleted='0'
renamed='0' enabled='0' encrypted='0' compressed='0' manual='0' unit='3' />
</tool>
thpragentname=op
tHPRAgentName POST variable is processed on Ninotes.dll!InotesHTTPProcessRequest → Nnotes.dll!NSFComputeEvaluateExt → Nnotes.dll!strncpy, where without checks, our buffer is copied to fixed-size buffer of 444 bytes.

This issue allows to attackers overwrite SEH pointer stored on stack and redirect execution flow, executing arbitrary code on remote IBM LD installations, but wait!
To exploit this bug, we must send alphanumeric payload and looking for valid address writable as alphanumeric characters: nnotes.dll has perfect address to POP-POP-RET on 0x60404672 (on Windows XP SP3 Spanish).
Therefore, this POST request is only attainable when user is authenticated on webadmin.nsf, since we need set "Authorization: Basic" Header to:
"Authorization: Basic "+Base64((usr:pwd))+"\r\n"
Ok, then we can achieve this information injecting code through Cross-Site Scripting residing on administration tool :) :
http://localhost/webadmin.nsf/fmpgPanelHeader
?ReadForm
&PanelIcon="><script>alert("XSS");</script><img src="
Once we have all information, we could exploit this post-auth vulnerability. Here is the PoC.
0-day
- Details
- Category: Articles
- Published on Sunday, 06 March 2011 20:04
- Written by rmallof
Hi,
this website will contain advisories regarding software security issues uncovereds by Roi (@rmallof) and Sherab (@shaddycls).
Details about vulnerabilities will be posted when this ones has been fixed and patched.
Regards.
(0-Day) ZDI-11-112 - HP Data Protector Media Operations DBServer.exe Integer Overflow
- Details
- Category: Advisories
- Published on Monday, 07 March 2011 00:02
- Written by rmallof
Hi there,
today ZDI has published our first advisory regarding Hewlett-Packard Data Protector Media Operations Server version 6.11, which provides automated backup and recovery of physical and virtual servers from disk through net.
From Zero Day Initiative advisory :
"This vulnerability allows remote attackers to execute arbitrary code on vulnerable installations of HP Data Protector. Authentication is not required to exploit this vulnerability.
The specific flaw exists within the DBServer.exe process which listens by default on TCP port 19813. While parsing a request, the process trusts a user-supplied 32-bit length value and uses it within a memory operation. By specifying large enough values in a packet sent to the service, a remote attacker can execute arbitrary code under the context of the SYSTEM user."
Before server calculates total allocation size, classical integer overflow can be triggered when attackers send crafted packet, sure.
First, process allocate heap block with this, then this value is used too like size argument in memcpy() wrapper, where it execute insufficient checks, writting out of bounds of assigned block:

This bug is caused by non-existent security checks against this Size value before memory operations, and as said ZDI this allows executing arbitrary code remotely on HP Data Protector Media Operations Server installations like SYSTEM user.
(0 day) Hewlett-Packard Data Protector Media Operations DBServer.exe Remote Code Execution Vulnerability Advisory here.
Bye!


