about CVE-2019-8658: improper binding betweeen the compiler and the dom engine leads to a uxss condition. ***CSP Implemantation in webkit - brief overview*** for enforcing CSP in safari the primary defenitions are implemented at: webkit/tree/master/Source/WebCore/page/csp [5]. the reader is encouraged to look at the implementation by itself, but we would describe some of the main features and usage of this implementation in webkit:
in general, if we look at .../ContentSecurityPolicy.cpp from source [5], we can see a set of api's, to be used by the renderer and other DOM Components. as an example we would look at the following Constructor: ```c ContentSecurityPolicy::ContentSecurityPolicy(URL&& protectedURL, ContentSecurityPolicyClient* client) : m_client { client } , m_protectedURL { WTFMove(protectedURL) } { updateSourceSelf(SecurityOrigin::create(m_protectedURL).get()); } ``` As we can see, when creating a dom object, while rendering or via the dom api, the CSP Policy is initiated, to be checked later on for any possible violations. an additional set of api's are provided. for example, for access checks within a page, the following class is implemented inside webkit/blob/master/Source/WebCore/page/SecurityOrigin.cpp#L1866 [6]: ```c Ref SecurityOrigin::create(const URL& url) { if (RefPtr cachedOrigin = getCachedOrigin(url)) return cachedOrigin.releaseNonNull(); if (shouldTreatAsUniqueOrigin(url)) return adoptRef(*new SecurityOrigin); if (shouldUseInnerURL(url)) return adoptRef(*new SecurityOrigin(extractInnerURL(url))); return adoptRef(*new SecurityOrigin(url)); } ``` for an example this class contains the following api function: ```c bool SecurityOrigin::canAccess(const SecurityOrigin& other) const ``` later in /Source/WebCore/bindings/js/JSDOMBindingSecurity.cpp [7] this api is made public to the dom api, and used by the renderer process to check for permissions on dom access due to CSP restrictions: ```c bindings/js/JSDOMWindowCustom.cpp#L424 [8]: bool JSDOMWindow::defineOwnProperty(JSC::JSObject* object, JSC::ExecState* exec, JSC::PropertyName propertyName, const JSC::PropertyDescriptor& descriptor, bool shouldThrow) { JSDOMWindow* thisObject = jsCast(object); // Only allow defining properties in this way by frames in the same origin, // as it allows setters to be introduced. if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->wrapped(), ThrowSecurityError)) return false; // Don't allow shadowing location using accessor properties. if (descriptor.isAccessorDescriptor() && propertyName == Identifier::fromString(exec, "location")) return false; return Base::defineOwnProperty(thisObject, exec, propertyName, descriptor, shouldThrow); } ``` in the above function, the reader should see, that before we can use the Javascript api, defineOwnProperty, the JSDOMWindow api is checking for the proper permissions by going to the api's implemented in [7] and defined at [6]. this check is done because of the dynamic nature of javascript. meaning, that even if we cannot load a script directly to some object. defining a property on a cross-origin object, might invoke callbacks and lead to arbitrary javascript execution on cross-origin domains -> a CSP violation. ***Variant analysis - CVE-2017-7037.*** CVE-2017-7037 was disscovered by lokihardt of google project zero, in april 2017. the report can be seen at the issue tracker. lets look at the poc and description of this vulnerability, given by the finder at the report in the bug tracker: " JSObject::putInlineSlow and JSValue::putToPrimitive use getPrototypeDirect instead of getPrototype to get an object's prototype. So JSDOMWindow::getPrototype which checks the Same Origin Policy is not called. The PoC shows to call a setter of another origin's object. PoC 1 - JSValue::putToPrimitive: ```html ``` " With the background given the reader should understand the root cause of this vulnerability from lokihardt's description. ***Real world exploitation of CVE-2017-7037.*** if you would visit the original report at the google project zero bug tracker you would see comment 5: " Comment 5 by cainiao...@gmail.com on Tue, Jul 25, 2017, 3:29 PM GMT+3 i don't see how to use any one can tell me ? " as described in section 1.3, and with the assumption that we save the following poc to a file named 'poc.html' and launch it on a vulnerable version of apple safari. then looking at the network section in the WebInspector would show that we got two different origins in the document: file:// and data/... . now the comment given here is not redundant, as this seems like not a 'real' issue: if we can create an iframe where we can already run code at (data/..), then why is this a problem at all? the sharp reader should notice, that replacing 'data/..' origin with any other would still result with a property assignment to the cross origin prototype. so, 'real world exploitation' of this bug would be of the form: *) locate a cross domain of interest, say: juicy-data.com . *) locate access to some defined property that can invoke a callback (toString, valueOf), example: by comparing this object (and then a valueOf or toString is invoked). the access to this property can be done from any side loaded javascript to that website. *) define the valueOf, toString callback to retrieve data from that origin, example: by issuing an XMLHttpRequest that send the document.cookie data back to a server, controlled by the attacker. *) Host an exploit page that embeds the juicy-data.com domain in an hidden iframe,and runs javascript on that page with the given logic issue. ***About Apple fix for CVE-2017-7037.*** running the CVE-2017-7037 poc code in safari would not produce a CSP . violation. instead it seems that apple fixed the bug by forcing the relevent operations to use getPrototype instead of getPrototypeDirect, so we basicaly cannot get a hold of the cross origin prototype anymore, so we dont get a csp violation.. but if we run the following javascript code, we can see that we do get a CSP violation in the debugger: ```html ``` Console output: ``` SecurityError: Blocked a frame with origin "null" from accessing a cross-origin frame. Protocols, domains, and ports must match. ``` for example: 'let v = f.contentWindow.eval', would result with a violation. so the developers needs to check every operation, including assignments via the discussed operations.. by having two api's: getprototype -> leads to the dom bindings, and getprototypedirect, they basicaly created this csp bypass bug class.. in my opinion this is an error prominent design pattern, that can lead the developers to mistakes. ***SOP Bypass*** given the above analysis, and after reviewing different 'put' functions in jsc source code (see the patch below) the following bypass's for CVE-2017-7037 can be constructed: ```html ```
```html ``` [etc] [etc] [etc] you are encouraged to read the patch at: https://bugs.webkit.org/attachment.cgi?id=371184 (notice the cocoa..) ref: [adv] https://www.zerodayinitiative.com/advisories/ZDI-19-683/ [apple] https://support.apple.com/en-us/HT210346 [1] https://bugs.chromium.org/p/project-zero/issues/detail?id=1240 [2] https://bugs.chromium.org/p/project-zero/issues/detail?id=1094 [5] https://github.com/WebKit/webkit/tree/master/Source/WebCore/page/csp [6] https://github.com/WebKit/webkit/blob/master/Source/WebCore/page/SecurityOrigin.cpp#L1866 [7] https://github.com/WebKit/webkit/blob/89c28d471fae35f1788a0f857067896a10af8974/Source/WebCore/bindings/js/JSDOMBindingSecurity.cpp [8] https://github.com/WebKit/webkit/blob/5cf2d3ed6657a12a51898d9bb0377aab0ef260a1/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp#L424