Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Critical] IP leaking through webrtc #117

Closed
ghost opened this issue Jan 29, 2018 · 49 comments
Closed

[Critical] IP leaking through webrtc #117

ghost opened this issue Jan 29, 2018 · 49 comments
Assignees
Labels
Milestone

Comments

@ghost
Copy link

ghost commented Jan 29, 2018

  1. Open iPhone : ip 1.1.1.1
  2. Connect to VPN : ip 2.2.2.2
  3. Check web etc leaks : no leak (2.2.2.2)
  4. Open onion browser 2.0.1 : ip 3.3.3.3
  5. Check web rtc leak : leaking 1.1.1.1
@tladesignz
Copy link
Contributor

Most probably same as #112

@tladesignz
Copy link
Contributor

We're trying to push an update, but Apple...

@ebelinski
Copy link

@tladesignz Did you request an expedited review?

@tladesignz
Copy link
Contributor

Thanks for the hint with the expedited review. We finally got it through after working out all the issues with Apple they suddenly found. They are sometimes quite cryptic, when it comes to explaining the issue...

Can you please check again and confirm if we got this fixed?

@ghost
Copy link
Author

ghost commented Feb 5, 2018

Not fixed. https://browserleaks.com/webrtc

@tladesignz
Copy link
Contributor

Also on Twitter now:

https://twitter.com/pwnsdx/status/961413267028619264

@n8fr8
Copy link

n8fr8 commented Feb 8, 2018

@ghost are you saying that Onion Browser 2 leaks outside of the VPN? The WebRTC leak happens even if the VPN is on?

@mtigas
Copy link
Member

mtigas commented Feb 8, 2018

(Update -- April 4 2019. After being fixed on iOS 12, this is apparently happening again on iOS 12.2.)

OK, this was not the same as #112.

Quick notes from some research here.

From the thread of the tweet that tladesignz linked, this started in iOS 11.

It also affects Red Onion and Brave (brave/browser-ios#1148).

My original guess was that we could plug this with the same content-security-policy injection from Onion Browser 1. OB1 disables websockets and 'connect' stuff by by default, it is only optional in Endless/OB2. That was a mistake and will be fixed, but that has no affect on WebRTC.

So this probably affects ALL Onion Browser on iOS 11.X.

Further, there used to be a mitigation in Brave https://github.com/brave/browser-ios/commit/f22e37be5dc59bb7762b1099f65794d3ba7fa7a0 , but it appears to have been removed https://github.com/brave/browser-ios/commit/893af7ea9754558e64a75445dd005241e600972f , and my own testing (adding the trapInstanceMethod bits from that file into https://github.com/mtigas/OnionBrowser/blob/2.X/Endless/Resources/injected.js which should add it to every page) also don't seem to have any affect in the iOS 11.2 simulator. (I'm investigating this further, since simply making RTCPeerConnection calls no-op should mitigate this.)

I'm also investigating whether iOS 11.3 beta changes things, because none of my devices using the 11.3 beta leak IP over WebRTC, even in Safari. https://twitter.com/mtigas/status/961665006344589312

@n8fr8
Copy link

n8fr8 commented Feb 8, 2018

This can also be mitigated by disabling Javascript entirely? Is that feature available still in iOS 11 / Endless codebase?

@mtigas
Copy link
Member

mtigas commented Feb 8, 2018

@n8fr8
yes:
Settings -> Host Settings -> Default Settings
Content policy: "Strict (no JavaScript, video, etc.)"
simulator screen shot - iphone 8 - 2018-02-08 at 15 06 55

@mtigas mtigas self-assigned this Feb 8, 2018
@mtigas mtigas added the bug label Feb 8, 2018
@n8fr8
Copy link

n8fr8 commented Feb 8, 2018

I would tweet that this can be immediately fixed by disable javascript by default for all sites, and show that screenshot: https://github.com/mtigas/OnionBrowser/issues/117#issuecomment-364232729

Perhaps JS should be off by default, and people can selectively enable by host?

@n8fr8
Copy link

n8fr8 commented Feb 8, 2018

img_0975

confirmed disable javascript blocks webrtc leak from happening

@MarkCallow
Copy link

Just tested iOS 12. I changed Content Policy to Permissive then connected to https://browserleaks.com/webrtc. Below is the output. No IP addresses are detected but RTCPeerConnection and RTCDataChannel are both checked. Not sure if this means the issue is resolved or not.

img_0161

@tladesignz
Copy link
Contributor

iOS 12.2 - WebRTC leaks IP address with default configuration:

  • Allow WebRTC: No
  • Content Policy: No XHR/WebSocket/Video connections

Simulator Screen Shot - iOS 12 2 @ iPad Pro - 2019-04-03 at 10 04 01

When Content Policy is changed to "Strict (no JavaScript, video etc.)", leak becomes impossible.

@MarkCallow
Copy link

MarkCallow commented Apr 3, 2019

@tladesignz, the "alt" title on the image you posted suggests it came from the iOS Simulator rather than a real iOS device. If this indeed was from the simulator, please test with a real device.

iOS 12.1 is fine. I just tested. But in view of this issue, I am holding off updating to 12.2.

@tladesignz
Copy link
Contributor

tladesignz commented Apr 4, 2019

@MarkCallow Thanks for your input!

Just tested with a real device running iOS 12.2. Same issue.

Also tested on IOS 11.4 in the simulator. It leaks. But you're right: that could be due to the underlying MacOS 10.14.4.

Unfortunately, I don't have a device around which runs iOS 11.0 - 12.1.

So, thanks again for your input, I really appreciate it!

@mtigas: We need a security warning on the landing page! And a tweet!

@ebelinski
Copy link

I just tested this on my iPad Pro 9.7" running iOS 12.2 and the latest version of Onion Browser from the App Store. As far as I can tell, my IP gets leaked as well. At first when I visited https://browserleaks.com/ip, it said n/a under "WebRTC Leak Test Public IP address". But then when I refreshed the page, I saw my real IP. See screenshots below.

IMG_0004
IMG_0005

@MarkCallow
Copy link

I wonder if this was ever really fixed in iOS 12. I'm running iOS 12.1 and I have just discovered that browserleaks.com's "What is my IP Address" page shows my real IP address in its 2-line WebRTC Leak Test section. However the full WebRTC Leak Test page shows "n/a" even after refresh. When I tested in 12.0, I only looked at the WebRTC Leak Test page.

I have no idea what browserleaks.com is doing that would give it different results on these 2 test pages.

@Baccount
Copy link

Baccount commented Apr 8, 2019

@tladesignz have you reported this leak to product-security@apple.com ? They respond quickly and should be able to fix the ip Leak.
https://support.apple.com/en-us/HT201220

@tladesignz
Copy link
Contributor

@Baccount Thanks for mentioning that! @mtigas said, he will do this.

I did a little investigation.

The way we do blocking is by injecting either a Content-Security HTTP header or injecting JavaScript.

The "Content Policy" setting is done via the CSP header:

if ([CSPmode isEqualToString:HOST_SETTINGS_CSP_STRICT])
CSPheader = @"connect-src 'none'; default-src 'none'; font-src 'none'; media-src 'none'; object-src 'none'; sandbox allow-forms allow-top-navigation; script-src 'none'; style-src 'unsafe-inline' *; image-src 'unsafe-inline' *; report-uri;";
else if ([CSPmode isEqualToString:HOST_SETTINGS_CSP_BLOCK_CONNECT])
CSPheader = @"connect-src 'none'; media-src 'none'; object-src 'none'; report-uri;";
NSString *curCSP = [self caseInsensitiveHeader:@"content-security-policy" inResponse:response];

The "Allow WebRTC" setting is done via JavaScript injection:

if ("##BLOCK_WEBRTC##") {
navigator.mediaDevices = null;
navigator.getUserMedia = null;
window.RTCPeerConnection = null;
window.webkitRTCPeerConnection = null;
}

It was already mentioned: There's this dedicated WebRTC leak test at Browserleaks:

https://browserleaks.com/webrtc

To mitigate that, the "Allow WebRTC" setting is good enough. You can even have your "Content Policy" set to "Open", which doesn't inject any CSP.

However, the test on

https://browserleaks.com/ip

Isn't mitigated by that at all. The only chance to stop it there, is to completely disable JavaScript. I confirmed this by playing around with the CSP header. Only script-src 'none' or sandbox without allow-scripts stopped it.

So, the only viable mitigation I see at the moment, is to set "Content Policy" to "Strict" by default, which disables JavaScript.

A small UI-side-issue btw. is, that "Allow WebRTC" should be set to "No" when "Content Policy" is set to "Strict", as there's not going to be any WebRTC, if there's no JavaScript running.

Besides that: I tried to poke around in the browserleaks source code from within Safari's console, but that wasn't very effective. Does anybody know, if the source code is public and available?

tladesignz added a commit that referenced this issue Apr 9, 2019
…ave "Allow WebRTC: Yes". When no JavaScript is run, there's no WebRTC. So mutually exclude these two.
tladesignz added a commit that referenced this issue Apr 9, 2019
@MarkCallow
Copy link

Besides that: I tried to poke around in the browserleaks source code from within Safari's console, but that wasn't very effective. Does anybody know, if the source code is public and available?

I sent an e-mail 2 days ago to the address at the bottom of the browserleaks web page. So far no reply.

@mtigas mtigas pinned this issue Apr 11, 2019
@mtigas
Copy link
Member

mtigas commented Apr 11, 2019

Gah. Tested it more closely this week. Have held off on emailing Apple since I actually don't think this is the same as the iOS 11 Safari/WebKit behavior that revealed true IP even on VPN.

https://d2p12wh0p3fo1n.cloudfront.net/onionbrowser/20190411-130057-1262.mp4

No VPN:

  • Safari: Real IP (i went too fast in this video so it shows "n/a", but webrtc got my real IP in other)
  • Chrome (WKWebView): Real IP (same as above)
  • Endless (UIWebView): Real IP
  • Onion Browser: client ip = Tor IP, webrtc = Real IP

VPN:

  • Safari: VPN IP
  • Chrome (WKWebView): VPN IP
  • Endless (UIWebView): VPN IP
  • Onion Browser: client ip = Tor IP, webrtc = VPN IP

The bad behavior we saw in iOS 11 is that all browsers were leaking Real IP, even if you were connected to a VPN. So the fact that browserleaks correctly shows the VPN IP in all the other browsers, I think, means that this isn't the OS-level issue anymore.

We do override the window.RTCPeerConnection and other related browser APIs to null, injecting this override at the top of every HTML page and JS file loaded:

if ("##BLOCK_WEBRTC##") {
navigator.mediaDevices = null;
navigator.getUserMedia = null;
window.RTCPeerConnection = null;
window.webkitRTCPeerConnection = null;
}

But this is fragile and can be circumvented with some tricks. Below is a fairly simple case. (Console output below leaves out some of the output of intermediate lines to be a bit more readable.)

> window.RTCPeerConnection
< ƒ RTCPeerConnection() { [native code] }

> window.RTCPeerConnection = null;

> window.RTCPeerConnection
< null

> var iframe = document.createElement("iframe");
> document.body.appendChild(iframe);
> window.RTCPeerConnection = iframe.contentWindow.RTCPeerConnection;
< ƒ RTCPeerConnection() { [native code] }

> window.RTCPeerConnection
< ƒ RTCPeerConnection() { [native code] }

(Adapted from http://perrymitchell.net/article/restoring-overridden-window-and-document-methods-with-archetype/ )

The "Disable WebRTC" flag is not bulletproof with JS still enabled. (Same goes for the other things that may be overridden, like navigator.geolocation.getCurrentPosition(...), etc.)

WebRTC seems to be in the same category as embedded media -- videos played inside WebKit don't follow the same TCP stack as our HTTP(S) requests. HTTP(S) requests rely on URLInterceptor being registered to handle all URIs other than file://, data://, and mailto://. But video that are even on HTTP(S) don't appear in the log of things that the app sees through the NSURLProtocol registration.

So, like embedded media, I don't think there's a technical fix here that is 100% bulletproof other than outright blocking JavaScript. (One thing folks have proposed to me: wince we do intercept all content, we could just regex for all JS calls to these things and just strip some of that out of the incoming source before passing it along to the WebKit renderer. But things doing eval() or other workarounds could hide from such a rewriter, dynamically calling things by obfuscated string fn="win"+"dow.RT"+"CPeerConnection" or such. And that's an arms race we don't want to get into.)

So. Ugh. I think the best we can do is an adjustment to the defaults as @tladesignz mentioned, and prioritizing work on changing the settings UI to make clearer what the levels of safety are. (Rather than feature toggle switches that may or may not work, just use a 3-tier slider in line with what Tor Browser does.)

@zoof
Copy link

zoof commented Jun 6, 2019

Sure.

iOS version:
IMG_0116

https://browserleaks.com/ip:
IMG_0115

@ebelinski
Copy link

Ah I see, thank you @zoof.

In any case, I have iOS 12.3.1 and my IP is still leaking on https://browserleaks.com/ip. So maybe it was fixed in 12.3, but if it was, this issue is back in 12.3.1. I also tried this on iOS 14 developer beta 1 on an iPhone SE and I still saw my real IP leak.

Overall I'm very concerned for the users of Onion Browser. JavaScript is still enabled by default, and we still do not have a warning on the home page about this issue. This means that effectively all Onion Browser users' identities may be exposed by any website they visit, and they have no way of knowing this, because the average Onion Browser user does not peruse issues on GitHub.

Bad actors can see this issue too and can target Onion Browser users with the information here.

I think we need to take immediate action:

  1. Adding a very visible warning to http://onionbr5zulufnuj.onion/ about this issue.
  2. Pushing an update that disables JavaScript, setting Content policy to Strict for all users.
  3. Adding a warning to the app that alerts user to this issue if they choose to re-enable JavaScript.

Without these changes, all the Onion Browser is doing currently is giving users a false sense of security.

@zoof
Copy link

zoof commented Jun 6, 2019

Strangely, after playing around with the content policy settings, it now displays my IP address unless I disable everything.

@seanri2112
Copy link

So I’m one of those that thinks I’m safe when obviously I’m not. I have an iPad Pro 12.9 inch. Strictly WiFi. I have tried everything to find where to disable webrtc and java but I see no clear way of doing that in onion browser. What’s the secret to doing this? Java is disabled in Safari but I’m not using Safari and I see no onion browser in my list of apps in my settings. Any help in my ignorance would be appreciated

@seanri2112
Copy link

Also when I check my ip over a vpn there is no leak. Is this falsely safe or no better then safari with a vpn?

@ebelinski
Copy link

Hi @seanri2112, finding this option is a little hard because it's not under the "Global Settings" option that one would normally expect it to be in. Here are the steps to disable JavaScript:

Step 1: Click on the gear icon in the top-right.

IMG_1200

Step 2: Select "Host Settings".

IMG_1201

Step 3: Select "Default Settings".

IMG_1202

Step 4: Select "Content policy".

IMG_1203

Step 5: Select "Strict (no JavaScript, video, etc.)".

IMG_1204

The "Content policy" should now be "Strict".

IMG_1205

@seanri2112
Copy link

Thanks Ebelinski. Seems so simple now! Haha. Isn’t all this mitigated by just using a vpn with onion?

@tladesignz
Copy link
Contributor

@mitgas: Maybe we're able to avert recovering access to WebRTC objects.

Had an interesting discussion.

This is about JavaScript which is injected to resist fingerprinting, but the technique itself maybe works for us, too:

https://github.com/arthuredelstein/browser-privacy/tree/resist-fingerprinting-js
https://github.com/arthuredelstein/browser-privacy/blob/resist-fingerprinting-js/resist-fingerprinting.js
https://github.com/arthuredelstein/browser-privacy/blob/resist-fingerprinting-js/test_protected.html

@ahjenssen
Copy link

ahjenssen commented Aug 22, 2019

Hi, apologies if this is a stupid question. Does the leak also happen when accessing .onion sites, or does the leak only happen when accessing clear net sites through the onion browser?

@tladesignz
Copy link
Contributor

Hi, apologies if this is a stupid question. Does the leak also happen when accessing .onion sites, or does the leak only happen when accessing clear net sites through the onion browser?

An attacking web page could be loaded through .onion, too, of course. However, the receiver of the Tor-bypassing WebRTC call would need to be a non-onion address, since, without Tor, no Onion service can be reached, obviously.

So, the server would need to disclose its identity, too. If so, then it begs the question: Why use an Onion service in the first place? That's not a rhetorical question. Rather, I guess, there probably is a scenario, where this makes sense. However, I'm curious how that would look like exactly and why.

So: theoretically, yes, practically, maybe.

@tladesignz
Copy link
Contributor

Ok, so I looked into this again.

Unfortunately, it seems, that we can't remove access to window.RTCPeerConnection.

Object.getPrototypeOf(window) // Returns a basically empty object.

// Therefore...

Object.defineProperty(
  Object.getPrototypeOf(window), 
  "RTCPeerConnection",
  {value: undefined, writable: false, configurable: false})

// ...doesn't do a thing.

Object.defineProperty(window, "RTCPeerConnection", 
  {value: undefined, writable: false, configurable: false})

// Works, but that's not a real difference to

window.RTCPeerConnection = undefined

// What browserleaks.com does is

var f = window.RTCPeerConnection;
if (!f) {
  var frame = document.getElementById("rtc-iframe");
  f = frame.contentWindow.RTCPeerConnection;
}

// And there's no way to avoid it.

// We also can't overwrite contentWindow:

Object.defineProperty(
  Object.getPrototypeOf(HTMLIFrameElement), 
  "contentWindow", 
  {get: function() {}, set: function() {}, configurable: false})

// Doesn't work.

Also, setting a Content-Security-Policy header like this...

Content-Security-Policy: frame-src 'none'

...doesn't work. The iframe can't connect anywhere, but the page is nevertheless allowed to create an empty iframe element and use its contentWindow property.

So, @m4mb01t4l14n0, I'm sorry, but it seems the only way to avoid WebRTC leaks from an attacker is disabling JavaScript altogether.

I guess we need to work on the phrasing in the UI instead.

Instead of just "WebRTC on/off" we should probably say something like "Try to block WebRTC on/off". Or "Make WebRTC harder to use" or something...

@ghost
Copy link

ghost commented Oct 10, 2021

Onion browser is leaking IP address through webrtc even when using Nordvpn on iPad using iOS 15.0.1.

Screenshots attached of browserleaks using safari and onion browser.

84143080-D113-4DEE-A7AD-01534E15EE9C
914D4230-B56C-4E1B-94E8-378958747B34

@freep0rt
Copy link

freep0rt commented Oct 10, 2021 via email

@Baccount
Copy link

Baccount commented Oct 10, 2021

Disabling WebRTC does not fix the leak. I can confirm the WebRTC leak occurs on iOS 15.0.1. image
@tladesignz

@tladesignz
Copy link
Contributor

It is finally done. Onion Browser 3.0.0 is released, which relies on Orbot iOS to provide Tor via a Network Extension. Full device traffic tunneling through Tor. Leaks finally stopped.

@tladesignz
Copy link
Contributor

But using Native Tor the leak still exists!

Yes.
Hence it says "The built-in Tor has security problems."
and "video and audio streams don't go through Tor and might get blocked"
and "Websites can uncover your real IP address using JavaScript".

This is a limitation created by Apple through deliberate design choices in iOS:

  • A split between the web rendering engine and the media rendering/streaming engine.
  • The non-existence of any API to interact with the media streaming library directly.
  • The decision to not forward any proxy information from the web renderer to the media renderer.

The solution Apple suggests, is, to use a Network Extension ("VPN"). Hence Orbot.
But Network Extensions on iOS are limited to 50 MB of RAM usage (on devices which have 3 GB, at least!).
Hence Orbot having difficulty to provide its functionality in recent months.

Again: Apple. 🤷 Thanks for nothing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

12 participants