This is a friendly warning that your web-browser does not currently protecting your privacy and/or security as well as you might want. Click on this message to see more information about the issue(s) that were detected.

Chrome blink Speech­Recognition­Controller use-after-free

(Chromium 455857, CVE-2015-1251)

Synopsis

A specially crafted web-page can cause the blink rendering engine used by Google Chrome and Chromium to continue to use a speech recognition API object after the memory block that contained the object has been freed. An attacker can force the code to read a pointer from the freed memory and use this to call a function, allowing arbitrary code execution.

Known affected software and attack vectors

Repro.html <html> <head> <script> o­Window = window.open(); o­Webkit­Speech­Recognition = new o­Window.webkit­Speech­Recognition(); o­Window.close(); set­Interval(function(){ if (o­Window.closed) { o­Webkit­Speech­Recognition.start(); } }, 10); </script> </head> </html>

Description

Creating a webkit­Speech­Recognition Javascript object in a popup window before closing the popup frees a C++ object used internally by the speech recognition API code but leaves a dangling pointer to the freed memory in another C++ object. When the start() Javascript method is called, this dangling pointer is used to try to read a function pointer from a virtual function table and call that function. An attacker has ample time to groom the heap between the free and re-use in order to control the function pointer used by the code, allowing arbitrary code execution.

This sequence of events describes the process happening in the repro:

  1. When a new window is opened from Javascript, a C++ Speech­Recognition­Client­Proxy object is instantiated.

  2. When a new webkit­Speech­Recognition object is created in Javascript, a Speech­Recognition C++ object is created to back it up internally.

  3. In the constructor of the Speech­Recognition C++ object, the m_­controller member variable is initialized by creating a new Speech­Recognition­Controller C++ object using Speech­Recognition­Controller::from.

    speech/Speech­Recognition.cpp:

    Speech­Recognition::Speech­Recognition(Execution­Context* context)
    /* <<<snip>>> */
        m_­controller = Speech­Recognition­Controller::from(page);
        ASSERT(m_­controller);
    /* <<<snip>>> */
    
  4. In the constructor of the Speech­Recognition­Controller C++ object, the m_­client member variable is initialized by storing a pointer to the Speech­Recognition­Client­Proxy C++ object created in step 1.

    speech/Speech­Recognition­Controller.cpp:

    Speech­Recognition­Controller::Speech­Recognition­Controller(Pass­Own­Ptr<Speech­Recognition­Client> client)
        : m_­client(client)
    /* <<<snip>>> */
    
  5. When the window created in step 1 is closed, the Speech­Recognition­Client­Proxy C++ object created in step 1 is destroyed and the memory previously used to store the object is freed.

  6. When the start Javascript method of the webkit­Speech­Recognition object created in step 2 is called, the start C++ method of the Speech­Recognition­Controller object is called internally. This method in turn calls the start C++ method of the previously freed Speech­Recognition­Client­Proxy object through its m_­client member variable.

    speech/Speech­Recognition.cpp:

    void Speech­Recognition::start(Exception­State& exception­State)
    /* <<<snip>>> */
        m_­controller->start(/* <<<snip>>> */);
    /* <<<snip>>> */
    

    speech/Speech­Recognition­Controller.h:

    void start(/* <<<snip>>> */)
    {
        m_­client->start(/* <<<snip>>> */);
    }
    

    In the last code snippet, when this code is executed, the m_­client member no longer points to a valid object, as this object has been deleted and its memory freed.

Exploit

An attacker looking to exploit this issue is going to want to try and control the contents of the freed memory, before getting the code to use the dangling pointer to call a virtual function. Doing so would allow an attacker to execute arbitrary code. This is made possible because steps 5 and 6 can both be triggered at a time of the attackers choosing, giving the attacker the ability to free the memory in step 5 whenever this is convenient and attempt to reallocate and fill it with any data before executing step 6. This should allow an attacker to create a fake vftable pointer and gain arbitrary code execution. In order to develop a working exploit, existing mitigations will need to be bypassed, most significantly ASLR and DEP. As this vulnerability by itself does not appear to allow bypassing these mitigations, I did not develop a working exploit for it.

Time-line

Bug­Id report: chrome_­child.dll!blink::Speech­Recognition::start Arbitrary AVE(6AD71ABA) This report was generated using a predecessor of Bug­Id, a Python script created to detect, analyze and id application bugs. Don't waste time manually analyzing issues and writing reports but try Bug­Id out yourself today! You'll get even better reports than this one with the current version.
id:             chrome_­child.dll!blink::Speech­Recognition::start Arbitrary AVE(6AD71ABA)
description:    Security: Attempt to execute non-executable arbitrary memory (@0x0501B300) in chrome_­child.dll!blink::Speech­Recognition::start
note:           Based on this information, this is expected to be a security issue!
© Copyright 2016 by Sky­Lined.
Creative Commons License This work is licensed under a Creative Commons Attribution-Non‑Commercial 4.0 International License.

Last updated on 2016-11-21.
If you find this web-site useful and would like to make a donation, you can send bitcoin to 183yyxa9s1s1f7JBp­PHPmz­Q346y91Rx5DX.