Address bar spoofing using firefox://open-url in Firefox iOS
Categories
(Firefox for iOS :: General, defect)
Tracking
()
| Tracking | Status | |
|---|---|---|
| fxios | 123 | --- |
People
(Reporter: sdna.muneaki.nishimura, Assigned: lmarceau)
References
()
Details
(Keywords: csectype-spoof, reporter-external, sec-moderate, Whiteboard: [reporter-external] [client-bounty-form] [verif?])
Attachments
(4 files)
Firefox iOS supports a custom URL scheme called "firefox://open-url" for opening specified URL by Firefox from other apps. Normally, Firefox prohibits opening URLs with javascript: scheme, but when using "open-url", it becomes possible to open them. Additionally, if the URL contains "://" immediately after the URL scheme, the address bar of Firefox iOS shows only the rest of the URL.
These two behaviors make spoofing the address bar.
As an example, consider the following URL:
When the following URL is opened in iOS Safari:
firefox://open-url?url=javascript://google.com%2Fsearch?q=foo%26source=%2F%250adocument.body.innerHTML='%253ch1%2520style=color:red%253eHacked!'
the JavaScript code specified through the URL is executed in Firefox, so the text "Hacked!" is displayed on the screen. And then, the address bar shows "google.com/search?q=foo...".
A reproduction URL is below. Open the page in Safari on an iOS device, and tap the link on the page.
https://csrf.jp/2023/fxios-url-spoof.php
Updated•2 years ago
|
Comment 1•2 years ago
|
||
Didn't we previously fix a bug to limit external URLs to a defined whitelist of acceptable ones? javascript should definitely not be on that list.
And any scheme-hiding code should be strictly limited to http/https. Anything else needs to show the scheme and could be a spoofing problem all on its own.
I assume if launching this from Firefox itself was possible Muneaki would have mentioned that, but I'll call this sec-moderate in case it is possible. If this is really only possible when Firefox isn't even the user's preferred browser (in which case it's likely not even installed) then we could downgrade it to sec-low. The external app might not be a browser like Safari though, it could be a social app that opens links in browsers.
Tracking progress on this issue with https://mozilla-hub.atlassian.net/browse/FXIOS-7331
Note that firefox://open-url will open Firefox even if the browser is not set as default. It will open the app if the app is installed, but will open the URL in Safari if the OS cannot find the Firefox app I believe.
The JavaScript scheme handling that you mention :dveditz I believe is done when a new navigation action is handled by a webview. That code is here and we made sure apparently to stop supporting javascript scheme since bugzilla 1588928. So it seems the decisionHandler doesn't get called in this case when we navigate from firefox://open-url with a Javascript URL. Unless I am missing something, this is an oversight since the webkit delegate methods aren't called in this particular case (and so we open javascript URLs when we shouldn't take that action).
On the UX perspective, I wonder what should happen, should we just block that navigation and stay on the tab we were before this happen (for example, homepage)?
I also wonder if there are other schemes that could be taken advantage of with those same steps?
| Reporter | ||
Comment 4•2 years ago
|
||
As you commented above, firefox://open-url is available regardless of whether Firefox is the default browser or not.
Originally, I demonstrated the attack by opening the malicious link in Safari, but the same attack can be achieved by opening the URL sent to the built-in SMS or email application. Also, even if Firefox is the default browser, "ftp:" scheme URL link is opened in the pre-installed Safari. Recently, "ftp:" is no longer opened in Safari, but in a slightly earlier version, it's possible to initiate the attack chain by launching Safari from Firefox through a "ftp:" link.
Similar to firefox://open-url, Google Chrome also supports "googlechrome:" and "googlechromes:"" URL schemes that can open the specified URL in Chrome. If an invalid URL is passed to this URL, Chrome seems to stay on the previous page or home screen.
Comment 5•2 years ago
|
||
Comment 6•2 years ago
|
||
(In reply to lmarceau from comment #3)
The JavaScript scheme handling that you mention :dveditz I believe is done when a new navigation action is handled by a webview. That code is here and we made sure apparently to stop supporting javascript scheme
There are a whole bunch of func webView() defined in that file; when do the various ones get used? Is that function called by webkit when we navigate? I don't see "open-url" defined around there so I'm guessing there is a different place called when the OS hands us a URL from outside the app than when webkit is letting us handle or veto navigations from content that we're already handling in the app. Unfortunately I don't know Swift or the iOS SDK so I'm stumbling around a bit here, but it looks like the Router stuff is related
https://github.com/mozilla-mobile/firefox-ios/blob/fc66a2023be3cbd9ac240de2e45af7e661ccf31a/Client/Coordinators/Router/DeeplinkInput.swift#L13
https://github.com/mozilla-mobile/firefox-ios/blob/main/Client/Coordinators/Router/RouteBuilder.swift#L53
I'm a bit stumped there because "search" is too common to search for. Is that our function or part of the webview API? Is "search" the same function as would be called when you type into the address bar? That would be problematic because there's nothing passed in letting it know this particular search came from OUTSIDE the app vs. a user typing it in which we can trust more not to be malicious. If "search" is a webkit function then we've got to strip "javascript:" URLs (and a lot more bad stuff potentially) before we call it. If it's ours then that's likely where we want to limit scheme usage.
On the UX perspective, I wonder what should happen, should we just block that navigation and stay on the tab we were before this happen (for example, homepage)?
If this URL is coming from some external app then most likely we don't even have focus. Does the OS raise us to the top when it hands us a URL, or do we do that ourselves? Ideally if we get "bad input" from outside we could just ignore it and do nothing. That is, stay on the page we were on (or the Homepage if we were closed?). But If the user clicks on a link in some app and then the OS raises up Firefox, the user is going to wonder what happened to the thing they clicked on. We might need to put up a message saying it was an invalid URL ("Could not open javascript://blah blah" -- but be careful rendering that so we don't introduce an XSS bug).
I also wonder if there are other schemes that could be taken advantage of with those same steps?
I'm sure there are, or if not now someone will invent them later. That's why I keep stressing we need to implement an allow-list of schemes we're willing to handle from external sources. Which means the decision needs to be made at some point where we know the difference between external input, a user-typed address, and a web navigation.
http: and https: are safe. data: is potentially spoofy, but otherwise safe. Do other apps need to have us open local file links (like, some other app downloads a PDF and we register as the PDF handler or something like that)? If so we might need to include "file:" on the "Good" list. That might be about all we should accept.
Comment 7•2 years ago
|
||
The severity field is not set for this bug.
:jeevans, could you have a look please?
For more information, please visit BugBot documentation.
| Reporter | ||
Comment 8•2 years ago
|
||
It seems this bug has not been progressed for two months since it was reported. Is there anything I can help with? Also, as far as I looked at security bugs I reported, e.g., Bug 1861405 or Bug 1861420, bugs in iOS are not handled by anybody. For example, should I create an issue on GitHub as well for the reference to the Bugzilla?
Hello Muneaki, you're right there hasn't been any progress on those. The team has limited capacity, and although this isn't a good reason not to be working on those, this is the only one I can give. I will bring this up the chain, so we can find time as a team to fix those tickets, as some in here are at least sec-moderate which means important to give them a higher priority. As for GitHub, it's preferable not to open security tickets over there as it's public. Thank you for your understanding, and thank you for having the security of Firefox for iOS at heart!
| Reporter | ||
Comment 10•2 years ago
|
||
The cause of this bug seems to be that URL scheme given from outside is not checked in the following source code.
https://github.com/mozilla-mobile/firefox-ios/blob/main/Client/Coordinators/Router/RouteBuilder.swift#L54
For example, it looks like this can be prevented by changing this line as follows.
return .search(url: ["http", "https"].contains(urlQuery?.scheme?.lowercased()) ? urlQuery : nil, isPrivate: isPrivate)
| Assignee | ||
Comment 11•2 years ago
|
||
Thanks Muneaki, you're right we should check the scheme when opening links from deeplinking sources. I'll take a look into improving this area, this is a great suggestion thank you!
Updated•2 years ago
|
| Assignee | ||
Comment 12•2 years ago
|
||
Updated•2 years ago
|
Updated•2 years ago
|
Updated•2 years ago
|
Comment 16•2 years ago
|
||
Verified as fixed on v123 (38400) with iPhone 15 Pro (17.1.2).
Please note that I did the following steps:
- Opened Firefox and added to the background.
- Opened Safari and accessed
https://csrf.jp/2023/fxios-url-spoof.php. - Tap on the
Tap herebutton from the above link. - Open in Firefox? Prompt is displayed
- Tap on Open
- Firefox is in the foreground (resumed) but no webpage or anything related to
"google.com/search?q=foo...".opened/displayed and there is noHacked!text displayed. - Here is a video text. Video
Muneaki Nishimura if you can please confirm that this is the behavior we want to see I would appreciate it.
| Reporter | ||
Comment 17•2 years ago
|
||
Thanks for your confirmation. The behavior described above is as expected. I have also confirmed that it is fixed in the master branch.
Updated•2 years ago
|
| Assignee | ||
Comment 18•2 years ago
|
||
Updated•1 year ago
|
Updated•1 year ago
|
Description
•