Closed Bug 540100 Opened 10 years ago Closed 10 years ago

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

Categories

(Core :: XUL, defect)

1.9.1 Branch
defect
Not set

Tracking

()

RESOLVED FIXED
Tracking Status
status1.9.2 --- unaffected
blocking1.9.1 --- .9+
status1.9.1 --- .9-fixed

People

(Reporter: bsterne, Assigned: smaug)

References

Details

(Keywords: csectype-uaf, verified1.9.0.19, verified1.9.1, Whiteboard: [sg:dupe 375928] fixed by bug 375928)

Attached file 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: nobody → Olli.Pettay
The PoC explanation isn't quite right.

But anyway, my bad, this is fixed on 1.9.2/trunk, see bug 375928.
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+
Depends on: CVE-2010-0175
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
bug 375928 landed to branches.
Status: ASSIGNED → RESOLVED
Closed: 10 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.
(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
You need to log in before you can comment on or make changes to this bug.