Skip to content

Commit

Permalink
fix: Fix webkit and CSP related issues. closes #197, #196, #194
Browse files Browse the repository at this point in the history
  • Loading branch information
shdwmtr committed Dec 27, 2024
1 parent 71dabc6 commit e2cd49d
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 53 deletions.
74 changes: 74 additions & 0 deletions src/core/hooks/csp_bypass.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#include <core/loader.h>
#include <core/ffi/ffi.h>

const void BypassCSP()
{
// This function is used to bypass the Content Security Policy (CSP) of a website.
// The Content Security Policy (CSP) is a security standard that helps prevent cross-site scripting (XSS), clickjacking, and other code injection attacks resulting from execution of malicious content in the context of trusted web pages.
// The CSP is implemented by the web server and enforced by the web browser.
// The CSP is a set of rules that the web server sends to the web browser to tell it what content is allowed to be loaded

JavaScript::SharedJSMessageEmitter::InstanceRef().OnMessage("msg", [&] (const nlohmann::json& message, int listenerId)
{
try
{
if (message.contains("id") && message.value("id", -1) == 96876)
{
for (auto& target : message["result"]["targetInfos"])
{
const std::string targetUrl = target["url"].get<std::string>();

if (target["type"] == "page" &&
targetUrl.find("steamloopback.host") == std::string::npos &&
targetUrl.find("https://") != std::string::npos)
{
Sockets::PostGlobal({
{ "id", 567844 },
{ "method", "Target.attachToTarget" },
{ "params", {
{ "targetId", target["targetId"] },
{ "flatten", true }
}}
});

Logger.Log("Bypassing CSP for " + target["url"].get<std::string>());
}
}
}

if (message.value("method", std::string()) == "Target.attachedToTarget")
{
Sockets::PostGlobal({
{ "id", 1235377 },
{ "method", "Page.setBypassCSP" },
{ "sessionId", message["params"]["sessionId"] },
{ "params", {
{ "enabled", true },
}}
});

Logger.Log("Sent CSP bypass request");
}

if (message.contains("id") && message.value("id", -1) == 1235377)
{
Logger.Log("Successfully bypassed CSP");
JavaScript::SharedJSMessageEmitter::InstanceRef().RemoveListener("msg", listenerId);
}
}
catch (const nlohmann::detail::exception& e)
{
LOG_ERROR("error bypassing CSP -> {}", e.what());
}
catch(const std::exception& e)
{
LOG_ERROR("error bypassing CSP -> {}", e.what());
}

});

Sockets::PostGlobal({
{ "id", 96876 },
{ "method", "Target.getTargets" }
});
}
105 changes: 53 additions & 52 deletions src/core/hooks/web_load.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <sys/encoding.h>
#include <sys/http.h>
#include <unordered_set>
#include "csp_bypass.h"
// #include <boxer/boxer.h>

unsigned long long g_hookedModuleId;
Expand All @@ -21,7 +22,7 @@ void WebkitHandler::SetupGlobalHooks()
{ "id", 3242 }, { "method", "Fetch.enable" },
{ "params", {
{ "patterns", {
{ { "urlPattern", "*" }, { "resourceType", "Document" }, { "requestStage", "Request" } },
{ { "urlPattern", "*" }, { "resourceType", "Document" }, { "requestStage", "Response" } },
{ { "urlPattern", fmt::format("{}*", this->m_javaScriptVirtualUrl) }, { "requestStage", "Request" } }
}
}}}
Expand Down Expand Up @@ -85,7 +86,7 @@ void WebkitHandler::RetrieveRequestFromDisk(nlohmann::basic_json<> message)
void WebkitHandler::GetResponseBody(nlohmann::basic_json<> message)
{
hookMessageId -= 1;
m_requestMap->push_back({ hookMessageId, message["params"]["requestId"], message["params"]["resourceType"] });
m_requestMap->push_back({ hookMessageId, message["params"]["requestId"], message["params"]["resourceType"], message });

Sockets::PostGlobal({
{ "id", hookMessageId },
Expand Down Expand Up @@ -156,6 +157,47 @@ const std::string WebkitHandler::PatchDocumentContents(std::string requestUrl, s
return patched.replace(patched.find("<head>"), 6, "<head>" + shimContent);
}

void WebkitHandler::HandleHooks(nlohmann::basic_json<> message)
{
for (auto requestIterator = m_requestMap->begin(); requestIterator != m_requestMap->end();)
{
try
{
auto [id, requestId, type, response] = (*requestIterator);

if (message["id"] != id || !message["result"]["base64Encoded"])
{
requestIterator++;
continue;
}

const std::string patchedContent = this->PatchDocumentContents(response["params"]["request"]["url"], Base64Decode(message["result"]["body"]));

BypassCSP();

Sockets::PostGlobal({
{ "id", 63453 },
{ "method", "Fetch.fulfillRequest" },
{ "params", {
{ "requestId", requestId },
{ "responseCode", response["params"]["responseStatusCode"] },
{ "body", Base64Encode(patchedContent) }
}}
});

requestIterator = m_requestMap->erase(requestIterator);
}
catch (const nlohmann::detail::exception& ex)
{
LOG_ERROR("error hooking WebKit -> {}", ex.what());
}
catch (const std::exception& ex)
{
LOG_ERROR("error hooking WebKit -> {}", ex.what());
}
}
}

void WebkitHandler::DispatchSocketMessage(nlohmann::basic_json<> message)
{
static std::chrono::time_point lastExceptionTime = std::chrono::system_clock::now();
Expand All @@ -164,63 +206,22 @@ void WebkitHandler::DispatchSocketMessage(nlohmann::basic_json<> message)
{
if (message["method"] == "Fetch.requestPaused")
{
if (message["params"]["resourceType"] == "Document")
switch (this->IsGetBodyCall(message))
{

std::string requestId = message["params"]["requestId"].get<std::string>();
std::string requestUrl = message["params"]["request"]["url"].get<std::string>();
nlohmann::json requestHeaders = message["params"]["request"]["headers"];

nlohmann::json responseHeaders = nlohmann::json::array({
{
{ "name", "Content-Security-Policy" },
{ "value", "default-src * 'unsafe-inline' 'unsafe-eval' data: blob:; script-src * 'unsafe-inline' 'unsafe-eval' data: blob:;" }
},
{
{ "name", "Access-Control-Allow-Origin" },
{ "value", "*" }
}
});

for (auto& [key, value] : requestHeaders.items())
case true:
{
responseHeaders.push_back({ { "name", key }, { "value", value } });
this->RetrieveRequestFromDisk(message);
break;
}

nlohmann::json responseHeadersJson;

const auto [originalContent, statusCode] = Http::GetWithHeaders(requestUrl.c_str(), requestHeaders, requestHeaders.value("User-Agent", ""), responseHeadersJson);

for (const auto& item : responseHeadersJson)
case false:
{
if (!std::any_of(responseHeaders.begin(), responseHeaders.end(), [&](const nlohmann::json& existingHeader) {
return existingHeader.at("name") == item.at("name");
})) {
responseHeaders.push_back(item);
}
this->GetResponseBody(message);
break;
}

const std::string patchedContent = this->PatchDocumentContents(requestUrl, originalContent);

nlohmann::json message = {
{ "id", 63453 },
{ "method", "Fetch.fulfillRequest" },
{ "params", {
{ "requestId", requestId },
{ "responseCode", statusCode },
{ "responseHeaders", responseHeaders },
{ "body", Base64Encode(patchedContent) }
}}
};

Sockets::PostGlobal(message);

}
else if (this->IsGetBodyCall(message))
{
this->RetrieveRequestFromDisk(message);
}
}

this->HandleHooks(message);
}
catch (const nlohmann::detail::exception& ex)
{
Expand Down
1 change: 1 addition & 0 deletions src/core/hooks/web_load.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ class WebkitHandler
long long id;
std::string requestId;
std::string type;
nlohmann::basic_json<> message;
};

std::shared_ptr<std::vector<WebHookItem>> m_requestMap = std::make_shared<std::vector<WebHookItem>>();
Expand Down
2 changes: 1 addition & 1 deletion src/core/loader.cc
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ class CEFBrowser
}
}

if (method == "Target.attachedToTarget")
if (method == "Target.attachedToTarget" && json["params"]["targetInfo"]["title"] == "SharedJSContext")
{
sharedJsContextSessionId = json["params"]["sessionId"];
this->onSharedJsConnect();
Expand Down

0 comments on commit e2cd49d

Please sign in to comment.