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)

defect
Not set
normal

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
Looks like this was written up based on our patch.
Status: NEW → RESOLVED
Closed: 15 years ago
Resolution: --- → DUPLICATE
Whiteboard: [sg:dupe 552216]
Hardware: x86 → All
the commment > Version(s) tested: Mozilla Firefox 3.5.8 looks like a typo
Attached file zdi's PoC
(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).
Group: core-security
You need to log in before you can comment on or make changes to this bug.