mirror of
https://forge.fsky.io/oneflux/omegafox.git
synced 2026-02-10 04:52:03 -08:00
Add WebRTC IP spoofing
Implement WebRTC IP spoofing at the protocol level by modifying ICE candidates and SDP before they're sent.
This commit is contained in:
parent
3f105c0ac1
commit
e8126c6819
3 changed files with 218 additions and 2 deletions
27
README.md
27
README.md
|
|
@ -20,6 +20,7 @@ Camoufox aims to be a minimalistic browser for robust fingerprint injection & an
|
|||
- Patches to avoid bot detection ✅
|
||||
- Custom Playwright Juggler implementation for the latest Firefox ✅
|
||||
- Font spoofing & anti-fingerprinting ✅
|
||||
- WebRTC IP spoofing ✅
|
||||
- Patches from LibreWolf & Ghostery to remove Mozilla services ✅
|
||||
- Optimized for memory and speed ✅
|
||||
- Stays up to date with the latest Firefox version 🕓
|
||||
|
|
@ -45,7 +46,7 @@ Camoufox is built on top of Firefox/Juggler instead of Chromium because:
|
|||
|
||||
## Fingerprint Injection
|
||||
|
||||
Camoufox overrides Javascript properties on the lowest level possible, allowing values to be spoofed across all scopes.
|
||||
In Camoufox, data is intercepted at the C++ implementation level, making the changes undetectable through JavaScript inspection.
|
||||
|
||||
To spoof fingerprint properties, pass a JSON containing properties to spoof:
|
||||
|
||||
|
|
@ -221,7 +222,24 @@ Camoufox can override the following network headers:
|
|||
</details>
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
WebRTC IP
|
||||
</summary>
|
||||
|
||||
Camoufox implements WebRTC IP spoofing at the protocol level by modifying ICE candidates and SDP before they're sent.
|
||||
|
||||
| Property | Status | Description |
|
||||
| ----------- | ------ | ------------------- |
|
||||
| webrtc:ipv4 | ✅ | IPv4 address to use |
|
||||
| webrtc:ipv6 | ✅ | IPv6 address to use |
|
||||
|
||||
**Notes:**
|
||||
|
||||
- To completely disable WebRTC, set the `media.peerconnection.enabled` preference to `false`.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
Addons
|
||||
</summary>
|
||||
|
|
@ -281,6 +299,7 @@ Miscellaneous (WebGl spoofing, battery status, etc)
|
|||
- Battery API spoofing
|
||||
- Support for spoofing both inner and outer window viewport sizes
|
||||
- Network headers (Accept-Languages and User-Agent) are spoofed to match the navigator properties
|
||||
- WebRTC IP spoofing at the protocol level
|
||||
- etc.
|
||||
|
||||
#### Anti font fingerprinting
|
||||
|
|
@ -321,7 +340,7 @@ Miscellaneous (WebGl spoofing, battery status, etc)
|
|||
|
||||
### Tests
|
||||
|
||||
Camoufox performs well against every major WAF I've tested. (Test sites from [Botright](https://github.com/Vinyzu/botright/?tab=readme-ov-file#browser-stealth))
|
||||
Camoufox performs well against every major WAF I've tested. (Original test sites from [Botright](https://github.com/Vinyzu/botright/?tab=readme-ov-file#browser-stealth))
|
||||
|
||||
| Test | Status |
|
||||
| -------------------------------------------------------------------------------------------------- | ------------------------------------------------- |
|
||||
|
|
@ -340,6 +359,10 @@ Camoufox performs well against every major WAF I've tested. (Test sites from [Bo
|
|||
| **Cloudflare** | ✔️ |
|
||||
| ‣ [Turnstile](https://nopecha.com/demo/turnstile) | ✔️ |
|
||||
| ‣ [Interstitial](https://nopecha.com/demo/cloudflare) | ✔️ Unstable on Chrome fingerprints |
|
||||
| **WebRTC IP Spoofing** | ✔️ |
|
||||
| ‣ [Browserleaks WebRTC](https://browserleaks.net/webrtc) | ✔️ |
|
||||
| ‣ [CreepJS WebRTC](https://abrahamjuliot.github.io/creepjs/) | ✔️ |
|
||||
| ‣ [BrowserScan WebRTC](https://www.browserscan.net/webrtc) | ✔️ |
|
||||
| **Font Fingerprinting** | ✔️ |
|
||||
| ‣ [Browserleaks Fonts](https://browserleaks.net/fonts) | ✔️ |
|
||||
| ‣ [CreepJS TextMetrics](https://abrahamjuliot.github.io/creepjs/tests/fonts.html) | ✔️ |
|
||||
|
|
|
|||
191
patches/webrtc-ip-spoofing.patch
Normal file
191
patches/webrtc-ip-spoofing.patch
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
diff --git a/dom/media/webrtc/jsapi/PeerConnectionImpl.cpp b/dom/media/webrtc/jsapi/PeerConnectionImpl.cpp
|
||||
index 5b70a58104..579a620c48 100644
|
||||
--- a/dom/media/webrtc/jsapi/PeerConnectionImpl.cpp
|
||||
+++ b/dom/media/webrtc/jsapi/PeerConnectionImpl.cpp
|
||||
@@ -116,6 +116,8 @@
|
||||
|
||||
#include "mozilla/dom/BrowserChild.h"
|
||||
#include "mozilla/net/WebrtcProxyConfig.h"
|
||||
+#include "MaskConfig.hpp"
|
||||
+#include "mozilla/RustRegex.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
// We need to undef the MS macro again in case the windows include file
|
||||
@@ -1705,7 +1707,15 @@ PeerConnectionImpl::SetLocalDescription(int32_t aAction, const char* aSDP) {
|
||||
}
|
||||
};
|
||||
|
||||
- mLocalRequestedSDP = aSDP;
|
||||
+ // Sanitize the SDP to prevent IP leaks
|
||||
+ std::string sanitizedSDP(aSDP);
|
||||
+ nsresult sanitizeResult = SanitizeSDPForIPLeak(sanitizedSDP);
|
||||
+ if (NS_FAILED(sanitizeResult)) {
|
||||
+ CSFLogError(LOGTAG, "%s - Failed to sanitize SDP", __FUNCTION__);
|
||||
+ return sanitizeResult;
|
||||
+ }
|
||||
+
|
||||
+ mLocalRequestedSDP = sanitizedSDP;
|
||||
|
||||
SyncToJsep();
|
||||
|
||||
@@ -3275,12 +3285,22 @@ const std::string& PeerConnectionImpl::GetName() {
|
||||
return mName;
|
||||
}
|
||||
|
||||
-void PeerConnectionImpl::CandidateReady(const std::string& candidate,
|
||||
+void PeerConnectionImpl::CandidateReady(const std::string& candidate_,
|
||||
const std::string& transportId,
|
||||
const std::string& ufrag) {
|
||||
STAMP_TIMECARD(mTimeCard, "Ice Candidate gathered");
|
||||
PC_AUTO_ENTER_API_CALL_VOID_RETURN(false);
|
||||
|
||||
+ const std::string& candidate = [&]() -> const std::string& {
|
||||
+ if (ShouldSpoofCandidateIP()) {
|
||||
+ static std::string spoofedCandidate;
|
||||
+ spoofedCandidate = SpoofCandidateIP(candidate_);
|
||||
+ return spoofedCandidate;
|
||||
+ } else {
|
||||
+ return candidate_;
|
||||
+ }
|
||||
+ }();
|
||||
+
|
||||
if (mForceIceTcp && std::string::npos != candidate.find(" UDP ")) {
|
||||
CSFLogWarn(LOGTAG, "Blocking local UDP candidate: %s", candidate.c_str());
|
||||
STAMP_TIMECARD(mTimeCard, "UDP Ice Candidate blocked");
|
||||
@@ -3343,10 +3363,89 @@ void PeerConnectionImpl::SendLocalIceCandidateToContent(
|
||||
uint16_t level, const std::string& mid, const std::string& candidate,
|
||||
const std::string& ufrag) {
|
||||
STAMP_TIMECARD(mTimeCard, "Send Ice Candidate to content");
|
||||
- JSErrorResult rv;
|
||||
- mPCObserver->OnIceCandidate(level, ObString(mid.c_str()),
|
||||
- ObString(candidate.c_str()),
|
||||
- ObString(ufrag.c_str()), rv);
|
||||
+
|
||||
+ // Check if IP spoofing is enabled
|
||||
+ if (ShouldSpoofCandidateIP()) {
|
||||
+ std::string spoofedCandidate = SpoofCandidateIP(candidate);
|
||||
+ JSErrorResult rv;
|
||||
+ mPCObserver->OnIceCandidate(level, ObString(mid.c_str()),
|
||||
+ ObString(spoofedCandidate.c_str()),
|
||||
+ ObString(ufrag.c_str()), rv);
|
||||
+ } else {
|
||||
+ JSErrorResult rv;
|
||||
+ mPCObserver->OnIceCandidate(level, ObString(mid.c_str()),
|
||||
+ ObString(candidate.c_str()),
|
||||
+ ObString(ufrag.c_str()), rv);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+bool PeerConnectionImpl::ShouldSpoofCandidateIP() const {
|
||||
+ // Checks if either webrtc:ipv4 or webrtc:ipv6 is set in the config
|
||||
+ return MaskConfig::GetString("webrtc:ipv4").has_value() ||
|
||||
+ MaskConfig::GetString("webrtc:ipv6").has_value();
|
||||
+}
|
||||
+
|
||||
+nsresult PeerConnectionImpl::SanitizeSDPForIPLeak(std::string& sdp) {
|
||||
+ auto replaceIP = [&sdp](const char* pattern, const char* pref) {
|
||||
+ if (auto value = MaskConfig::GetString(pref)) {
|
||||
+ mozilla::RustRegex regex(pattern);
|
||||
+ if (regex.IsValid()) {
|
||||
+ std::string result;
|
||||
+ auto iter = regex.IterMatches(sdp);
|
||||
+ size_t lastEnd = 0;
|
||||
+ while (auto match = iter.Next()) {
|
||||
+ result.append(sdp, lastEnd, match->start - lastEnd);
|
||||
+ result.append(value.value());
|
||||
+ lastEnd = match->end;
|
||||
+ }
|
||||
+ result.append(sdp, lastEnd);
|
||||
+ sdp = std::move(result);
|
||||
+ }
|
||||
+ }
|
||||
+ };
|
||||
+
|
||||
+ replaceIP("\\b(?:\\d{1,3}\\.){3}\\d{1,3}\\b", "webrtc:ipv4");
|
||||
+ replaceIP("\\b(?:[A-F0-9]{1,4}:){7}[A-F0-9]{1,4}\\b", "webrtc:ipv6");
|
||||
+
|
||||
+ return NS_OK;
|
||||
+}
|
||||
+
|
||||
+std::string PeerConnectionImpl::SpoofCandidateIP(const std::string& candidate) {
|
||||
+ CSFLogDebug(LOGTAG, "Original candidate: %s", candidate.c_str());
|
||||
+
|
||||
+ std::istringstream iss(candidate);
|
||||
+ std::vector<std::string> tokens{std::istream_iterator<std::string>{iss},
|
||||
+ std::istream_iterator<std::string>{}};
|
||||
+
|
||||
+ bool spoofed = false;
|
||||
+ // Check for IPv4 or .local address
|
||||
+ if (tokens.size() >= 8) {
|
||||
+ if (tokens[4].find('.') != std::string::npos) { // IPv4 or .local
|
||||
+ if (auto value = MaskConfig::GetString("webrtc:ipv4")) {
|
||||
+ tokens[4] = value.value();
|
||||
+ spoofed = true;
|
||||
+ }
|
||||
+ }
|
||||
+ // Check for IPv6
|
||||
+ else if (tokens[4].find(':') != std::string::npos) {
|
||||
+ if (auto value = MaskConfig::GetString("webrtc:ipv6")) {
|
||||
+ tokens[4] = value.value();
|
||||
+ spoofed = true;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (spoofed) {
|
||||
+ std::ostringstream oss;
|
||||
+ std::copy(tokens.begin(), tokens.end(),
|
||||
+ std::ostream_iterator<std::string>(oss, " "));
|
||||
+ std::string result = oss.str();
|
||||
+ CSFLogDebug(LOGTAG, "Spoofed candidate: %s", result.c_str());
|
||||
+ return result;
|
||||
+ }
|
||||
+
|
||||
+ CSFLogDebug(LOGTAG, "Candidate not spoofed: %s", candidate.c_str());
|
||||
+ return candidate;
|
||||
}
|
||||
|
||||
void PeerConnectionImpl::IceConnectionStateChange(
|
||||
@@ -4446,8 +4545,10 @@ bool PeerConnectionImpl::GetPrefDefaultAddressOnly() const {
|
||||
|
||||
uint64_t winId = mWindow->WindowID();
|
||||
|
||||
- bool default_address_only = Preferences::GetBool(
|
||||
- "media.peerconnection.ice.default_address_only", false);
|
||||
+ bool default_address_only =
|
||||
+ Preferences::GetBool("media.peerconnection.ice.default_address_only",
|
||||
+ false) ||
|
||||
+ ShouldSpoofCandidateIP();
|
||||
default_address_only |=
|
||||
!MediaManager::Get()->IsActivelyCapturingOrHasAPermission(winId);
|
||||
return default_address_only;
|
||||
diff --git a/dom/media/webrtc/jsapi/PeerConnectionImpl.h b/dom/media/webrtc/jsapi/PeerConnectionImpl.h
|
||||
index d7b54ad721..8d8e92d14b 100644
|
||||
--- a/dom/media/webrtc/jsapi/PeerConnectionImpl.h
|
||||
+++ b/dom/media/webrtc/jsapi/PeerConnectionImpl.h
|
||||
@@ -624,8 +624,12 @@ class PeerConnectionImpl final
|
||||
RefPtr<MediaPipeline> GetMediaPipelineForTrack(
|
||||
dom::MediaStreamTrack& aRecvTrack);
|
||||
|
||||
- void CandidateReady(const std::string& candidate,
|
||||
+ void CandidateReady(const std::string& candidate_,
|
||||
const std::string& transportId, const std::string& ufrag);
|
||||
+
|
||||
+ bool ShouldSpoofCandidateIP() const;
|
||||
+ nsresult SanitizeSDPForIPLeak(std::string& sdp);
|
||||
+ std::string SpoofCandidateIP(const std::string& candidate);
|
||||
void SendLocalIceCandidateToContent(uint16_t level, const std::string& mid,
|
||||
const std::string& candidate,
|
||||
const std::string& ufrag);
|
||||
diff --git a/dom/media/webrtc/jsapi/moz.build b/dom/media/webrtc/jsapi/moz.build
|
||||
index 05920fc151..34dcf3b9a1 100644
|
||||
--- a/dom/media/webrtc/jsapi/moz.build
|
||||
+++ b/dom/media/webrtc/jsapi/moz.build
|
||||
@@ -62,3 +62,6 @@ EXPORTS.mozilla.dom += [
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = "xul"
|
||||
+
|
||||
+# DOM Mask
|
||||
+LOCAL_INCLUDES += ["/dom/mask"]
|
||||
\ No newline at end of file
|
||||
|
|
@ -13,6 +13,8 @@ pref("browser.sessionstore.max_resumed_crashes", 0);
|
|||
pref("browser.sessionstore.restore_on_demand", false);
|
||||
pref("browser.sessionstore.restore_tabs_lazily", false);
|
||||
|
||||
pref("media.peerconnection.ice.no_host", true);
|
||||
|
||||
// Tweaks that undo Playwright:
|
||||
|
||||
// Force enable content isolation (WAFs can detect this!)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue