Closed
Bug 554189
Opened 15 years ago
Closed 15 years ago
WOFF Font Format dirEntry Remote Code Execution Vulnerability (ZDI-CAN-741)
Categories
(Core :: Layout: Text and Fonts, defect)
Core
Layout: Text and Fonts
Tracking
()
RESOLVED
DUPLICATE
of bug 552216
People
(Reporter: dveditz, Unassigned)
Details
(Whiteboard: [sg:dupe 552216])
Reported from ZDI to the security alias.
ZDI-CAN-741: Mozilla Firefox WOFF Font Format dirEntry Remote Code Execution Vulnerability
-- ABSTRACT ------------------------------------------------------------
TippingPoint has identified a vulnerability affecting the following
products:
Mozilla Firefox 3.6.x
-- VULNERABILITY DETAILS -----------------------------------------------
This vulnerability allows remote attackers to execute arbitrary code on
vulnerable installations of Mozilla Firefox. User interaction is
required to exploit this vulnerability in that the target must visit a
malicious page or open a malicious file.
The specific flaw exists within the way the browser loads a WOFF-based
font. Upon calculating the length of some data read from the file, the
application will miscalculate a size used for an allocation, and then
copy an incorrect amount of data into that buffer. Due to the difference
between the size of the allocation and the size of the copy, a buffer
overflow will occur which can lead to code execution under the context
of the application.
The issue can be located within the implementation of the woff file
format which is located undergfx/thebes/src/woff.c
When reading a WOFF font, the size for the buffer is calculated in the
following code.
gfx/thebes/src/gfxUserFontSet.cpp:189
case GFX_USERFONT_WOFF: {
PRUint32 status = eWOFF_ok;
PRUint32 bufferSize = woffGetDecodedSize(aData, *aLength,
&status); // XXX
if (WOFF_FAILURE(status)) {
break;
}
PRUint8* decodedData =
static_cast<PRUint8*>(NS_Alloc(bufferSize));
if (!decodedData) {
break;
}
woffDecodeToBuffer(aData, *aLength,
decodedData, bufferSize,
aLength, &status);
// replace original data with the decoded version
NS_Free((void*)aData);
aData = decodedData;
if (WOFF_FAILURE(status)) {
// something went wrong, discard the data and return NULL
break;
}
// success, return the decoded data
return aData;
}
The application will sanitycheck the data and then calculate the
length.
gfx/thebes/src/woff.c:690
status = sanityCheck(woffData, woffLen); // XXX
if (WOFF_FAILURE(status)) {
FAIL(status);
}
totalLen = READ32BE(((const woffHeader *)
(woffData))->totalSfntSize);
/* totalLen must be correctly rounded up to 4-byte alignment,
otherwise
sanityCheck would have failed */
failure:
if (pStatus) {
*pStatus = status;
}
return totalLen;
}
In the implementation of sanityCheck, the application tests for integer
overflow. However, the orig variable can be made to be different from
the result that is returned. Due to this difference, population of the
allocated buffer will lead to a buffer overflow.
gfx/thebes/src/woff.c:623
static uint32_t
sanityCheck(const uint8_t * woffData, uint32_t woffLen)
{
const woffHeader * header;
uint16_t numTables, i;
const woffDirEntry * dirEntry;
uint32_t tableTotal = 0;
if (!woffData || !woffLen) {
return eWOFF_bad_parameter;
}
if (woffLen < sizeof(woffHeader)) {
return eWOFF_invalid;
}
header = (const woffHeader *) (woffData);
if (READ32BE(header->signature) != WOFF_SIGNATURE) {
return eWOFF_bad_signature;
}
if (READ32BE(header->length) != woffLen || header->reserved != 0) {
return eWOFF_invalid;
}
numTables = READ16BE(header->numTables);
if (woffLen < sizeof(woffHeader) + numTables * sizeof(woffDirEntry))
{
return eWOFF_invalid;
}
dirEntry = (const woffDirEntry *) (woffData + sizeof(woffHeader));
for (i = 0; i < numTables; ++i) {
uint32_t offs = READ32BE(dirEntry->offset);
uint32_t orig = READ32BE(dirEntry->origLen); // XXX
uint32_t comp = READ32BE(dirEntry->compLen);
if (comp > orig || comp > woffLen || offs > woffLen - comp) {
return eWOFF_invalid;
}
orig = (orig + 3) & ~3; // XXX
if (tableTotal > 0xffffffffU - orig) {
return eWOFF_invalid;
}
tableTotal += orig;
++dirEntry;
}
if (tableTotal > 0xffffffffU - sizeof(sfntHeader) -
numTables * sizeof(sfntDirEntry) ||
READ32BE(header->totalSfntSize) != // XXX
tableTotal + sizeof(sfntHeader) + numTables *
sizeof(sfntDirEntry)) {
return eWOFF_invalid;
}
return eWOFF_ok;
}
Version(s) tested: Mozilla Firefox 3.5.8
Platform(s) tested: Windows XP SP3
-- CREDIT --------------------------------------------------------------
This vulnerability was discovered by:
* regenrecht
Reporter | ||
Comment 1•15 years ago
|
||
Looks like this was written up based on our patch.
Status: NEW → RESOLVED
Closed: 15 years ago
Resolution: --- → DUPLICATE
Whiteboard: [sg:dupe 552216]
Updated•15 years ago
|
Hardware: x86 → All
Comment 2•15 years ago
|
||
the commment
> Version(s) tested: Mozilla Firefox 3.5.8
looks like a typo
Reporter | ||
Comment 3•15 years ago
|
||
Comment 4•15 years ago
|
||
(In reply to comment #3)
> Created an attachment (id=434175) [details]
> zdi's PoC
Just FTR, verified that this PoC is harmless with a current build (i.e. with the overflow patch in place), although it crashes 3.6 (unpatched).
Reporter | ||
Updated•15 years ago
|
Group: core-security
You need to log in
before you can comment on or make changes to this bug.
Description
•