nsTreeSelection EventListener Use-after-free Remote Code Execution Vulnerability (ZDI-CAN-669)

RESOLVED FIXED

Status

()

Core
XUL
RESOLVED FIXED
8 years ago
3 months ago

People

(Reporter: bsterne, Assigned: smaug)

Tracking

({csectype-uaf, verified1.9.0.19, verified1.9.1})

1.9.1 Branch
csectype-uaf, verified1.9.0.19, verified1.9.1
Points:
---
Bug Flags:
blocking1.9.0.19 +

Firefox Tracking Flags

(status1.9.2 unaffected, blocking1.9.1 .9+, status1.9.1 .9-fixed)

Details

(Whiteboard: [sg:dupe 375928] fixed by bug 375928)

(Reporter)

Description

8 years ago
Created attachment 421958 [details]
Proof of concept

ZDI-CAN-669: Mozilla Firefox nsTreeSelection EventListener Use-after-free Remote Code Execution Vulnerability

-- ABSTRACT ------------------------------------------------------------

TippingPoint has identified a vulnerability affecting the following  products:

    Mozilla Firefox 3.5.x

-- VULNERABILITY DETAILS -----------------------------------------------

This vulnerability allows remote attackers to execute arbitrary code on software utilizing a vulnerable version of Mozilla's Firefox. User interaction is required in that the victim must visit a malicious website or be coerced into opening a malicious document. 

The specific flaw exists within how the application handles particular events for an nsTreeSelection element. Upon execution of a "select" event the application will access an element without checking to see if it's been previously freed or not. Successful exploitation can lead to code execution under the context of the application.

This vulnerability occurs due to firing an event on an object that has already been freed and can be reproduced with the following code: 
<tree id="tr" flex="1">
    <treechildren>
        <treeitem>
            <treerow>
                <treecell/>
            </treerow>
        </treeitem>
    </treechildren>
</tree>

tree = document.getElementById('tr');
tree.addEventListener("select", function (e) {}, false);
tree.view.selection.timedSelect(0, 5000);    // XXX: fire "select" event
in 5 seconds
tree.view.selection = null;                  // XXX: freed

Upon calling timedSelect on a tree.view.selection object, the application will instantiate a new timer, and call SelectCallback when it fires.

layout/xul/base/src/tree/src/nsTreeSelection.cpp:336

NS_IMETHODIMP nsTreeSelection::TimedSelect(PRInt32 aIndex, PRInt32
aMsec)
{
  PRBool suppressSelect = mSuppressed;

  if (aMsec != -1)
    mSuppressed = PR_TRUE;

  nsresult rv = Select(aIndex);
  if (NS_FAILED(rv))
    return rv;

  if (aMsec != -1) {
    mSuppressed = suppressSelect;
    if (!mSuppressed) {
      if (mSelectTimer)
        mSelectTimer->Cancel();

      mSelectTimer = do_CreateInstance("@mozilla.org/timer;1");
      mSelectTimer->InitWithFuncCallback(SelectCallback, this, aMsec,  
// XXX
                                         nsITimer::TYPE_ONE_SHOT);
    }
  }

  return NS_OK;
}

At this point, a malicious individual will want to free the tree.view.selection the timer has been created for. Once the timer fires, the callback will then be executed. The following code will load the closure representing the callback, and then execute it.

layout/xul/base/src/tree/src/nsTreeSelection.cpp:847
void
nsTreeSelection::SelectCallback(nsITimer *aTimer, void *aClosure)
{
  nsTreeSelection* self = static_cast<nsTreeSelection*>(aClosure);
  if (self) {
    self->FireOnSelectHandler();        // XXX
    aTimer->Cancel();
    self->mSelectTimer = nsnull;
  }
}

The select handler that's been fired, will load the code for the event and then execute it. At this point the tree.view.selection object has been freed.

layout/xul/base/src/tree/src/nsTreeSelection.cpp:827
nsresult
nsTreeSelection::FireOnSelectHandler()
{
  if (mSuppressed || !mTree)
    return NS_OK;

  nsCOMPtr<nsIBoxObject> boxObject = do_QueryInterface(mTree);
  NS_ASSERTION(boxObject, "no box object!");
  if (!boxObject)
     return NS_ERROR_UNEXPECTED;
  nsCOMPtr<nsIDOMElement> elt;
  boxObject->GetElement(getter_AddRefs(elt));
  NS_ENSURE_STATE(elt);

  nsRefPtr<nsPLDOMEvent> event =
    new nsPLDOMEvent(elt, NS_LITERAL_STRING("select"));
  event->RunDOMEventWhenSafe();     // XXX
  return NS_OK;
}

Version(s)  tested: FireFox 3.6.5 
Platform(s) tested: Windows XP SP3

-- CREDIT --------------------------------------------------------------

This vulnerability was discovered by:
    * regenrecht

-- FURTHER DETAILS -----------------------------------------------------

If you have any questions, comments, concerns or require additional details please feel free to contact me via the following:

    Kate Fly
    Security Liaison
    TippingPoint
    kfly@tippingpoint.com
    Office: +1 512.681.8219

We can alternatively be reached via e-mail at:

    zdi-disclosures@tippingpoint.com

Our PGP key is available from:

    http://www.zerodayinitiative.com/documents/disclosures-pgp-key.asc
Alias: ZDI-CAN-669
OS: Mac OS X → All
Hardware: x86 → All
Summary: nsTreeSelection EventListener Use-after-free Remote Code Execution Vulnerability → nsTreeSelection EventListener Use-after-free Remote Code Execution Vulnerability (ZDI-CAN-669)
(Assignee)

Updated

8 years ago
Assignee: nobody → Olli.Pettay
(Assignee)

Comment 1

8 years ago
The PoC explanation isn't quite right.

But anyway, my bad, this is fixed on 1.9.2/trunk, see bug 375928.
(Assignee)

Updated

8 years ago
Status: NEW → ASSIGNED
blocking1.9.1: --- → ?
Flags: blocking1.9.0.19?
Whiteboard: [sg:critical?] → [sg:critical?][sg:dupe 375928]
Do we have reason to believe that this bug was discovered due to the check-in of the patch in bug 375928?
blocking1.9.1: ? → .9+
status1.9.1: --- → wanted
status1.9.2: --- → unaffected
Depends on: 375928
Flags: blocking1.9.0.19? → blocking1.9.0.19+
Whiteboard: [sg:critical?][sg:dupe 375928] → [sg:critical?][sg:dupe 375928] fixed by bug 375928
Version: Trunk → 1.9.1 Branch
(Assignee)

Comment 3

8 years ago
bug 375928 landed to branches.
status1.9.1: wanted → .9-fixed
Keywords: fixed1.9.0.19
(Assignee)

Updated

8 years ago
Status: ASSIGNED → RESOLVED
Last Resolved: 8 years ago
Resolution: --- → FIXED
Verified for 1.90 with  Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.19pre) Gecko/2010031005 GranParadiso/3.0.19pre (.NET CLR 3.5.30729) on Windows XP.

Verified for 1.9.1 with  Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.9pre) Gecko/20100310 Shiretoko/3.5.9pre (.NET CLR 3.5.30729).

Interestingly, the PoC will crash the debug builds of each completely but retail works fine.
Keywords: fixed1.9.0.19 → verified1.9.0.19, verified1.9.1
(Assignee)

Comment 5

8 years ago
(In reply to comment #4)
> Interestingly, the PoC will crash the debug builds of each completely but
> retail works fine.
You mean debug builds of 1.9.0.19 and 1.9.1.9 crash?
If so, what does the stack trace look like?
My debug builds had an issue so I clobbered and rebuilt. I don't see the issue with them now so it is all good.
Whiteboard: [sg:critical?][sg:dupe 375928] fixed by bug 375928 → [sg:dupe 375928] fixed by bug 375928
Group: core-security
Keywords: csectype-uaf
You need to log in before you can comment on or make changes to this bug.