Closed
Bug 443299
(CVE-2008-0017)
Opened 16 years ago
Closed 16 years ago
Investigate possible buffer overflow in nsDirIndexParser
Categories
(Core :: XPCOM, defect, P1)
Core
XPCOM
Tracking
()
RESOLVED
FIXED
People
(Reporter: bsterne, Assigned: jdschuh)
References
Details
(Keywords: fixed1.8.1.18, fixed1.9.1, verified1.9.0.4, Whiteboard: [sg:critical])
Attachments
(3 files, 1 obsolete file)
1.64 KB,
text/plain
|
Details | |
1.06 KB,
text/plain
|
Details | |
1.32 KB,
patch
|
Biesinger
:
review+
dveditz
:
approval1.8.1.18+
dveditz
:
approval1.9.0.4+
asac
:
approval1.8.0.next+
|
Details | Diff | Splinter Review |
Justin Schuh of the IBM X-Force reported the following issue via security@m.o. The issue appears to require specially-formatted HTTP response headers, so I will send email to the reporter to see if they have a PoC CGI they can provide. From the advisory: Summary: The http-index-format parser does not check for an allocation failure on a format array. The resulting array is then terminated with a sentinel value of 0xFFFFFFFF. A malicious party can exploit this issue to execute arbitrary code by overwriting a sensitive memory location (such as a buffer length or boolean variable). Details: When handling a content type of "application/http-index-format", a specially crafted 200 header line in an HTTP index response can result in an exploitable memory corruption condition. The following code fails to check for a NULL pointer returned from a new [] statement (and no exception is thrown). netwerk\streamconv\converters\nsDirIndexParser.cpp lines 203-204 mFormat = new int[num+1]; mFormat[num] = -1; The resulting pointer is then dereferenced by four times the number of tokens provided in the header line, and a 32-bit integer value of -1 (0xFFFFFFFF) is assigned to the dereferenced location. By manipulating the currently available memory (such as through Javascript) a malicious party can reliably exploit this issue to overwrite an arbitrary memory location with the 4-byte value 0xFFFFFFFF.
Reporter | ||
Comment 1•16 years ago
|
||
Sent email to reporter requesting proof-of-concept CGI for exploit.
Whiteboard: [sg:investigate]
Reporter | ||
Updated•16 years ago
|
Whiteboard: [sg:investigate] → [sg:needinfo]
Reporter | ||
Comment 2•16 years ago
|
||
Reporter sent additional exploit notes but isn't able to send CGI code for PoC due to his company's internal policies. From his email: General Exploitation -------------------- The exploit runs against Firefox 2.0.0.14 on Windows, and takes advantage of a 4-byte write of 0xFFFFFFFF to an arbitrary (attacker selectable) location by dereferencing a NULL pointer. The exploit occurs in multiple stages in which memory is fragmented, a buffer length is overwritten (nsHTMLTags::sMaxTagNameLength at 0xB45AD0), and a group of function pointers are then overwritten past the buffer's intended bounds. Stage 1 ------- This stage fragments memory in the browser by using JavaScript to create a large number of canvas elements set to consume roughly 0xB419E8 bytes. The canvas element was chosen because it is initialized reasonably quickly to a controllable size and does not result in a crash on allocation failure. Stage 2 ------- This stage delivers a application/http-index-format content body containing a single 200 header line with exactly 0x2D16B4 space-delimited, single-character tokens. In the interest of efficiency, this content is delivered gzip-compressed, resulting in a 5778-byte buffer. If the fragmentation is successful this will result in a failed allocation of nsDirIndexParser::mFormat and the value 0xFFFFFFFF being written to the nsHTMLTags::sMaxTagNameLength at address 0xB45AD0. Because the token string matches no standard tokens, the token buffer nsDirIndexParser::mFormat is never written to after being terminated. Further examination will likely reveal other exploit methods (particularly if common plugins are considered). However, this location is adequate for demonstration purposes and has been shown to produce a 100% reliable code execution exploit. Stage 3 ------- This stage contains a malformed HTML tag to write beyond the bounds of the static variable buf (address 0xB45CA8) in nsHTMLTags::LookupTag(). The exploit buffer overwrites several function pointers and replaces them with a pointer to the shellcode stub. Current tests have shown that the overwritten value previously containing uxtheme.OpenThemeDat () is called immediately after the overwrite occurs. Stage 3 always proceeds regardless of whether stage 2 succeeded or not. If code execution does not result from this stage, available memory is altered and stage 2 is repeated.
Assignee | ||
Comment 3•16 years ago
|
||
The the obvious fix is to change line 203 in nsDirIndexParser::ParseFormat() to check for an allocation failure with something like this: if ((mFormat = new int[num+1]) == NULL) return NS_ERROR_OUT_OF_MEMORY; As for triggering the bug, that's a little more annoying and the impact is OS and runtime dependent. You also have to force an allocation failure, which is why the proof of concept exploit is a bit complicated. So, I'm attaching a python script (not the exploit script) that should crash Firefox on Windows, but the crash is very slow and will consume over a gig of memory in the process. An offending content body will look something like what I've shown below, but with a much longer string of "x x x" tokens (enough that the new call will fail). The address at the tokens * 4 is then overwritten with 0xFFFFFFFF. Also, the script gzips the content to save some time (and even then it's intolerably slow). Response Content Body: HTTP/1.0 200 OK Content-Type: application/http-index-format 200: x x x x x x x x x x x x x x x
Assignee | ||
Comment 4•16 years ago
|
||
I just realized that this bug is mislabeled. It affects all hardware/OS/versions. In some combinations it's a code execution bug (Firefox 2.0 and below on Windows) and on some it's a crash bug (like Firefox 3.0 on Windows). Whether it's code execution or crash depends primarily on if the new call throws an unhandled exception (which Firefox 3.0 does). After that, exploitation is a matter of finding a reasonable address to overwrite.
Assignee | ||
Comment 5•16 years ago
|
||
This prevents the vulnerability both by checking for an excessive number of column headers and identifying a failed allocation. Checking the column headers isn't necessary to fix the bug, but there's no good reason to allow an arbitrary number of columns given the spec at http://www.mozilla.org/projects/netlib/dirindexformat.html
Attachment #335756 -
Flags: review?(bsterne)
Reporter | ||
Updated•16 years ago
|
Attachment #335756 -
Flags: review?(bsterne) → review?(dveditz)
Updated•16 years ago
|
Flags: wanted1.8.1.x+
Flags: blocking1.9.1?
Flags: blocking1.9.0.4?
Flags: blocking1.8.1.18?
Comment 6•16 years ago
|
||
Assigning to Justin since he's supplied the patch, but we'll find someone to check it in for you
Assignee: nobody → jdschuh
Flags: blocking1.9.0.4?
Flags: blocking1.9.0.4+
Flags: blocking1.8.1.18?
Flags: blocking1.8.1.18+
Whiteboard: [sg:needinfo] → [sg:critical?]
Assignee | ||
Updated•16 years ago
|
OS: Mac OS X → All
Hardware: PC → All
Updated•16 years ago
|
Whiteboard: [sg:critical?] → [sg:critical?] needs r=dveditz
Comment 7•16 years ago
|
||
Comment on attachment 335756 [details] [diff] [review] Path to limit columns and catch NULL deref sr=dveditz Looks good to me, but we need a network peer to also OK this. Looks like the original code should have had "if(!*pos) break;" before incrementing num, but it doesn't really hurt to allocate one too many if the format ends with extra spaces. Irrelevant to the security problem.
Attachment #335756 -
Flags: superreview+
Attachment #335756 -
Flags: review?(dveditz)
Attachment #335756 -
Flags: review?(cbiesinger)
Updated•16 years ago
|
Whiteboard: [sg:critical?] needs r=dveditz → [sg:critical?] needs r=cbiesinger
Updated•16 years ago
|
Whiteboard: [sg:critical?] needs r=cbiesinger → [sg:critical] needs r=cbiesinger
Updated•16 years ago
|
Attachment #335756 -
Flags: review?(cbiesinger) → review-
Comment 8•16 years ago
|
||
Comment on attachment 335756 [details] [diff] [review] Path to limit columns and catch NULL deref + // There are a maximum of six allowed header fields (doubled + terminator, just in case) please limit your lines to 80 characters + if (num > (2*(sizeof(gFieldTable) / sizeof(gFieldTable[0])))) spaces around the * operator, please. and use NS_ARRAY_LENGTH to get the size of the array + return NS_ERROR_OUT_OF_MEMORY; no tabs please
Comment 9•16 years ago
|
||
Attachment #344000 -
Flags: review?(cbiesinger)
Updated•16 years ago
|
Attachment #335756 -
Attachment is obsolete: true
Comment 10•16 years ago
|
||
Christian: did you have substantive complaints about the patch? I've addressed your comments, please re-review so we can get this in for the code-freeze.
Updated•16 years ago
|
Attachment #344000 -
Flags: review?(cbiesinger) → review+
Updated•16 years ago
|
Whiteboard: [sg:critical] needs r=cbiesinger → [sg:critical]
Updated•16 years ago
|
Attachment #344000 -
Flags: approval1.9.0.4?
Attachment #344000 -
Flags: approval1.8.1.18?
Updated•16 years ago
|
Whiteboard: [sg:critical] → [sg:critical] needs trunk landing
Comment 11•16 years ago
|
||
Comment on attachment 344000 [details] [diff] [review] updated to comments Approved for 1.8.1.18 and 1.9.0.4, a=dveditz for release-drivers
Attachment #344000 -
Flags: approval1.9.0.4?
Attachment #344000 -
Flags: approval1.9.0.4+
Attachment #344000 -
Flags: approval1.8.1.18?
Attachment #344000 -
Flags: approval1.8.1.18+
Comment 12•16 years ago
|
||
Fix checked into trunk http://hg.mozilla.org/mozilla-central/rev/6fb0d02dc606
Status: NEW → RESOLVED
Closed: 16 years ago
Resolution: --- → FIXED
Whiteboard: [sg:critical] needs trunk landing → [sg:critical]
Comment 13•16 years ago
|
||
Fix checked into the 1.8 and 1.9.0 branches
Keywords: fixed1.8.1.18,
fixed1.9.0.4
Comment 14•16 years ago
|
||
So, reading above, we don't have a repro case because we didn't get a PoC cgi. QA would like to know if there is a way to verify this fix works.
Comment 15•16 years ago
|
||
Never mind, I see that the python file acts as a server for the creating the bug conditions. Script says: localhost - - [28/Oct/2008 17:18:42] "GET / HTTP/1.1" 200 - 388877 compressed bytes served when running and a connection is made to it via 127.0.0.1. Running with 3.0.3, Firefox peaks memory usage at around 490 MB and pegs my CPU at 100% while doing it. After about 15 minutes, it recovers and Firefox is usable again. No crash is evident... Running with last night's 1.9.0.4 nightly on the same virtual machine (Ubuntu 8.04), I'm seeing the exact same behavior with no difference at all. Comment 4 states that with Firefox 3, I should get a crash when I try this in 3.0.3. I'm going to try this on Windows as well but I need to set up an environment to do so.
Comment 16•16 years ago
|
||
Interesting. Testing on Windows XP, the same test crashed Firefox 3.0.3. With the nightly 1.9.0.4 with the fix (Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.4pre) Gecko/2008102905 GranParadiso/3.0.4pre), the memory usage rose but it eventually recovered with no crash. Marking verified for 1.9.0.4.
Keywords: fixed1.9.0.4 → verified1.9.0.4
Comment 17•16 years ago
|
||
Testing with Firefox 2.0.0.17 on Windows XP, I get up to about 420 MB of RAM usage (and 99% cpu) before it drops back to 28 MB of RAM and no cpu usage, bringing up a page. I cannot get 2.0.0.17 to crash with this.
Assignee | ||
Comment 18•16 years ago
|
||
(In reply to comment #17) > Testing with Firefox 2.0.0.17 on Windows XP, I get up to about 420 MB of RAM > usage (and 99% cpu) before it drops back to 28 MB of RAM and no cpu usage, > bringing up a page. I cannot get 2.0.0.17 to crash with this. Try editing the python script and changing the value 800000000 on the commented line to something bigger like 1000000000 or 1200000000. Or, if the test system is low on memory, try changing it to something smaller like 500000000. The proof-of-concept exploit used JavaScript to dynamically set up the memory space since that varies between installations.
Comment 19•16 years ago
|
||
So, I've tried this a bunch of different times with 2.0.0.17 on XP, even dropping the available RAM in the virtual machine down to 128 MB to constrain things. While I can get 3.0.3 to crash, nothing ever happens with 2.0.0.17 other than it becoming very busy for a while Has anyone actually seen this crash 2.0.0.17 or earlier?
Comment 20•16 years ago
|
||
Comment on attachment 344000 [details] [diff] [review] updated to comments a=asac for 1.8.0 branch
Attachment #344000 -
Flags: approval1.8.0.15+
Updated•16 years ago
|
Flags: blocking1.8.0.15+
Comment 21•16 years ago
|
||
I'm unable to verify this fix in 1.8.1.18 because of the inability to replicate the crash on a 1.8.1.x build.
Updated•16 years ago
|
Summary: Investigate CVE 2008-0017: possible buffer overflow in nsDirIndexParser → Investigate possible buffer overflow in nsDirIndexParser
Updated•16 years ago
|
Group: core-security
Comment 22•16 years ago
|
||
the patch is not nice: 206 mFormat = new int[num+1]; 207 // Prevent NULL Deref - Bug 443299 208 if (mFormat == nsnull) 209 return NS_ERROR_OUT_OF_MEMORY; operator |new| throws exception on OOM, it doesn't return 0 as demonstrated by this proggie: int *mFormat; mFormat=new int[-2000]; if (mFormat == 0) cout << "==" << endl; return 0; ./a.out terminate called after throwing an instance of 'std::bad_alloc' what(): std::bad_alloc Aborted
Comment 23•16 years ago
|
||
georgi: this isn't the case with gecko 1.8 on windows, the toolchain we use is msvc6 where new returns null instead of throwing. handling oom by null checking is the way all of our code expects to work. until we've changed things, we should continue to ensure we have null checks.
Comment 24•15 years ago
|
||
This landed before 1.9.1 branched
Flags: blocking1.9.1? → blocking1.9.1+
Priority: -- → P1
Updated•15 years ago
|
Keywords: fixed1.9.1
Updated•13 years ago
|
Depends on: CVE-2011-0070
You need to log in
before you can comment on or make changes to this bug.
Description
•