https://www.ryanpickren.com/safari-uxss
[11062b_6a1]
Home
Hacking the Apple Webcam (again)
Gaining unauthorized camera access via Safari UXSS: the story of how
a shared iCloud document can hack every website you've ever visited.
Ryan Pickren
Summary
It's been over a year since my last Apple camera hacking project, so
I decided to give it another go.
My hack successfully gained unauthorized camera access by exploiting
a series of issues with iCloud Sharing and Safari 15. While this bug
does require the victim to click "open" on a popup from my website,
it results in more than just multimedia permission hijacking. This
time, the bug gives the attacker full access to every website ever
visited by the victim. That means in addition to turning on your
camera, my bug can also hack your iCloud, PayPal, Facebook, Gmail,
etc. accounts too.
This research resulted in 4 0day bugs (CVE-2021-30861,
CVE-2021-30975, and two without CVEs), 2 of which were used in the
camera hack. I reported this chain to Apple and was awarded $100,500
as a bounty.
Safari UXSS
Background
Apple fixed my last 0day chain (CVE-2020-3852 + CVE-2020-3864 +
CVE-2020-3865) by making camera access drastically more difficult.
Now multimedia access is only allowed when the protocol is "https:"
and the domain matches your saved settings. This means that cleverly
malformed URIs won't cut it anymore. Now we need to genuinely inject
our evil code into the target origin. In other words, we need to find
a Universal Cross-Site Scripting (UXSS) bug.
But what exactly is UXSS? Google Project Zero has a nice summary in
their paper, "Analysis of UXSS exploits and mitigations in Chromium"
-
"UXSS attacks exploit vulnerabilities in the browser itself [...] to
achieve an XSS condition. As a result, the attacker does not just get
access to user session on a single website, but may get access to any
[website]."
The authors of this paper go on to call UXSS "among the most
significant threats for users of any browser" and "almost as valuable
as a Remote Code Execution (RCE) exploit with the sandbox escape."
Sounds pretty great, right? Imagine building a website that can jump
into https://zoom.com to turn on the camera, hop into https://
paypal.com to transfer money, and hijack https://gmail.com to steal
emails.
Before we go any further, I should clarify how exactly this bug
differs from my last Safari Camera Hacking project. That bug
specifically targeted stored multimedia permissions. It did not give
me the ability to execute code on arbitrary origins. Check out my
attack diagram to see which origins were being used. In other words,
that hack let me leverage Skype's camera permission but did not let
me steal Skype's cookies.
Let's try to find a UXSS bug in the latest version of Safari (Safari
v15 beta at time of writing). As always, the first step is to do a
lot of research into prior work. After all, the best security
research comes from standing on the shoulders of giants.
The Attack Plan
After reading numerous write-ups about patched Safari UXSS bugs, I
decided to focus my research on webarchive files. These files are
created by Safari as an alternative to HTML when a user saves a
website locally.
Screen Shot 2021-08-12 at 10.43.16 AM.png
Safari saving a website as a Webarchive file
A startling feature of these files is that they specify the web
origin that the content should be rendered in.
Apple Webarchive File Format
Webarchive File Format
This is an awesome trick to let Safari rebuild the context of the
saved website, but as the Metasploit authors pointed out back in
2013, if an attacker can somehow modify this file, they could
effectively achieve UXSS by-design.
According to Metasploit, Apple did not view this attack scenario as
very realistic because "the webarchives must be downloaded and
manually opened by the client." Granted this decision was made nearly
a decade ago, when the browser security model wasn't nearly as mature
as it is today.
Apple's decision to support this ultra-powerful filetype gave way to
an era of hackers trying to forcefully open them on victims'
machines. Fundamentally, this attack can be broken into two steps:
1) Forcefully download an evil webarchive file
2) Forcefully open it
Until recently, there were no protections to prevent step #1. Prior
to Safari 13, no warnings were even displayed to the user before a
website downloaded arbitrary files. So planting the webarchive file
was easy. (Now with Safari 13+, users are prompted before each
download)
Opening the webarchive file was trickier, but still manageable by
somehow navigating to the file:// URI scheme. Back when Safari's
error pages lived on the file:// scheme, hackers figured out how to
purposely invoke an error page to just alter its pathname, a hack
delightfully dubbed "Errorjacking." See here and here for two
variations. Another approach that worked back in the day was to
simply set the tag to file://.
Fast forward to 2022 and things get a lot harder. Not only are
auto-downloads prevented by default, but webarchive files are
considered malicious applications by macOS Gatekeeper. This means
that users can't even manually open foreign webarchives themselves
anymore. Apple seems to have changed their 2013 stance about how
dangerous these files can be.
Screen Shot 2021-08-12 at 1.17.50 PM.png
Download prompt in Safari 13+
Gatekeeper Webarchive Prompt
Gatekeeper Launch Prevention
Still, webarchive files just seem too juicy to give up on. Let's
explore how this old-school hack can still occur on the latest Safari
and macOS builds.
Exploration of custom URI Schemes
I found success with my last Safari Camera Hacking project by
conducting a deep dive into official IANA-registered URI schemes.
This project was heavily guided by RFCs and public documentation. But
there is an entire world of custom URL schemes that I neglected to
talk about. These unofficial and (mostly) undocumented schemes are
usually used by third party iOS/macOS apps as a form of deep linking.
There is actually an entire community built around discovering and
using these schemes cross-app for both fun and hacking projects.
An interesting note is that several first-party system apps such as
Apple Help Viewer (help://), FaceTime (facetime-audio://), and Apple
Feedback (applefeedback://) also support custom URI schemes. Abusing
these schemes from a website in Safari is not a novel technique.
Indeed, hackers have been finding ways to use custom schemes to
launch (and exploit bugs in) system applications for a while now.
Hacks range from annoyingly placing calls, aiding in social
engineering, to arbitrary file execution. Seriously, there is some
awesome research in this space.
To help combat these attacks, modern versions of Safari warn the user
before blindly launching secondary applications. That is, unless they
are one of the hardcoded exceptions identified in this great Blackhat
presentation.
Screen Shot 2021-08-12 at 2.33.07 PM.png
Custom URI Schemes that Safari will launch without Prompt
All of these schemes are registered with Launch Services, so you can
list them (and others) via this command:
/System/Library/Frameworks/CoreServices.framework/Versions/A/
Frameworks/LaunchServices.framework/Versions/A/Support/lsregister
-dump | grep -B6 bindings:.*: | grep -B6 apple-internal
After digging through internal Apple schemes and cross-referencing
them with the ones trusted by Safari, I found one that caught my eye-
"icloud-sharing:". This scheme appears to be registered by an iCloud
Sharing Application called "ShareBear."
Screen Shot 2021-08-12 at 2.38.00 PM.png
LaunchServices data about the icloud-sharing: scheme
ShareBear was interesting to me because sharing iCloud documents
seemed like a plausible path towards downloading & launching
webarchive files. I couldn't find any publicly available
documentation or research about this scheme so I just started poking
at it myself.
ShareBear Application
At this point we have identified an application that can be
automatically launched by Safari, however we do not know how to
correctly open it yet. Luckily, it was pretty straight forward.
Some quick research shows that iCloud File Sharing can generate a
public Share Link.
d69b081b8b7300b9da7fe35cb6fdaad1.png
Creating a public iCloud Share Link
These Share Links look something like this:
https://www.icloud.com/iclouddrive/01fooriERbarZSTfikqmwQAem
Simply replacing "https" with "icloud-sharing" is all that's needed
to have Safari automatically open ShareBear with this file as a
parameter.
evil.html
Great, so what does ShareBear do now? Some quick testing showed this
behavior:
sharebear.png
ShareBear Behavior Flowchart
There is a subtle, but wildly impactful, design flaw with this
behavior. Let's dig into what happens if the user has not opened this
file before. The user will be shown a prompt, similar to the one
below.
propt.png
ShareBear Open Prompt
This innocuous little prompt, with the default value of "Open," seems
pretty straightforward. A user should expect to have the image,
example.png, opened if they agree. But in actuality, they are
agreeing to much more than that.
Once the user clicks Open, the file is downloaded onto the victim's
machine at the location /Users//Library/Mobile Documents/
com~apple~CloudDocs then automatically opened via Launch Services.
Then the user will never see this prompt again. From that point
forward, ShareBear (and thus any website in Safari) will have the
ability to automatically launch this file. The truly problematic part
of this agreement is that the file can be changed by anybody with
write access to it. For example, the owner of the file could change
the entire byte content and file extension after you agree to open
it. ShareBear will then download and update the file on the victim's
machine without any user interaction or notification.
In essence, the victim has given the attacker permission to plant a
polymorphic file onto their machine and the permission to remotely
launch it at any moment. Yikes.
Agreed to view my PNG file yesterday? Well today it's an executable
binary that will be automatically launched whenever I want.
Apple fixed this behavior in macOS Monterey 12.0.1 as a result of my
report without issuing a CVE because it is more of a design flaw than
a bug per-se.
Bonus Bug: Iframe Sandbox Escape
While fuzzing the icloud-sharing:// scheme, I stumbled upon a fun bug
unrelated to the UXSS hunt. ShareBear appears to check the path of
the URL for "/iclouddrive/*" before performing the behavior outlined
above. If the path happens to be "/photos/*" then ShareBear makes a
pretty silly mistake. It will tell Safari to open a new tab pointing
to the iCloud web app... but it does not verify that the domain name
is actually the iCloud web app.
In normal operation, the user is simply presented with the website, "
https://photos.icloud.com." However because this domain name is never
validated, we can trick ShareBear into instructing Safari into
opening a new tab to any website.
The implications of this behavior may not be obvious. This doesn't
seem all that different than just calling window.open('https://
example.com') normally. However there are situations in the web where
websites aren't allowed to do that. One example is if popup blocker
is enabled. Another, more devious, example is when your website is
inside of a sandboxed iframe.
The sandbox iframe attribute is typically used when you want to embed
untrusted 3rd party content on your website. For example, you may
want to display an ad banner on your blog but you don't want this ad
to be able to run JavaScript (who knows, maybe the ad author has a
browser 0day).
iframe-sandbox.png
An important rule for sandboxed iframes is that new windows opened
from that iframe should inherit the same restrictions as the iframe
itself. Otherwise escaping the sandbox would be as trivial as opening
a popup.
Well this bug tricks Safari into opening a 'fresh' new tab without
any sandbox restrictions!
Website trapped in a Sandboxed Iframe
So ShareBear neglecting to verify the domain gives us an easy
popup-blocker bypass and an iframe sandbox escape. Nice! (fixed in
Safari 15.2 without being assigned a CVE) Live demo on BugPoC -
https://bugpoc.com/poc#bp-S4HH6YcO PoC ID: bp-S4HH6YcO, Password:
loVEDsquId01. Note this demo will only work with Safari <15.2 pre
macOS Monterey 12.1.
Now back to the Camera/UXSS hunt.
Quarantine and Gatekeeper
Quick reminder of where we are -
Our website can prompt the user to open a shared PNG file. If the
user agrees, we can automatically launch this file at any point in
the future, even after we alter the file content and extension.
staging.png
The attacker can then modify the file on his own machine and
ShareBear will take care of updating it on the victim's machine.
Attacker's Machine
Victim's Machine
Mutating the Polymorphic File
The attacker's website can then automatically launch this
newly-updated file using the same icloud-sharing:// URL that he used
to display the original prompt.
launching.png
This seems very close to our goal of forcefully downloading & opening
an evil webarchive file. We can just swap out the content of
puppy.png for a webarchive file and rename it "evil.webarchive",
right? Unfortunately for us, pesky macOS Gatekeeper won't allow that.
Screen Shot 2021-08-12 at 1.19.38 PM.png
Gatekeeper Launch Prevention
It appears that ShareBear correctly gives downloaded files the '
com.apple.quarantine' attribute and according to Apple, "Gatekeeper
prevents quarantined executable files and other similar files (shell
scripts, web archives, and so on) from opening or executing." For a
deep dive into how macOS treats this attribute, as well as how
Gatekeeper performs code signing, check out this great write-up.
For our purposes, there are two big limitations introduced by this OS
protection -
1) We can't run our own apps
2) We can't directly open webarchive files
Side Bar - while we can't run our own apps, launching existing,
approved, apps is trivial. Just use a fileloc to point to a local app
(this technique is quite common). This attack is sometimes referred
to as "Arbitrary File Execution" and is often misunderstood because
it looks so scary.
URL
file:///System/Applications/Calculator.app
fileloc pointing to macOS Calculator
Using the icloud-sharing:// scheme to launch the fileloc
While this attack might look scary, launching an already-approved app
doesn't have much impact. Let's focus on opening webarchives.
Shortcuts
The above technique to open local apps is reminiscent of an
old-school symlink attack. It basically just uses a "shortcut" to
trick software into opening something it doesn't expect.
Lots of different operating systems and applications have reinvented
the wheel over the years when it comes to shortcuts. Nowadays, the
term "shortcut" could be referring to a Unix symlink, a macOS alias,
a Window's linkfile, a Safari webloc, an Edge bookmark, etc.
I was hopeful that I could use this technique to bypass Gatekeeper
and open a webarchive file. This idea seemed promising to me because
the actual application I want to open is Safari (an existing,
approved, application). Gatekeeper doesn't have a problem with me
launching Safari, it just gets upset when I attempt to open any file
ending in ".webarchive".
So I needed to find a shortcut filetype that launches Safari, then
tells Safari to open a different file. After some trial and error, I
found just that - the ancient Windows URL File!
[{000214A0-0000-0000-C000-000000000046}]
Prop3=19,2
[InternetShortcut]
URL=file:///path/to/webarchive
IDList=
evil.url file pointing to a local webarchive
Launching evil.url successfully opens Safari and instructs it to load
the webarchive file without asking Gatekeeper for permission!
(CVE-2021-30861) There was only one small hiccup - I need to know the
full path to the webarchive file. Assuming the webarchive gets
downloaded via ShareBear, it will live in /Users//Library/
Mobile Documents/com~apple~CloudDocs, which includes the victim's
username (not a very scalable attack).
Luckily, there is a neat trick to circumvent this requirement - we
can mount the webarchive file into the known /Volumes/ directory
using a DMG file.
Using the icloud-sharing:// scheme to mount the dmg
Now we know exactly where the webarchive file resides. Which means
the below evil.url file will work every time.
[{000214A0-0000-0000-C000-000000000046}]
Prop3=19,2
[InternetShortcut]
URL=file:///Volumes/folder/evil.webarchive
IDList=
evil.url file pointing to a known-location local webarchive
Using the icloud-sharing:// scheme to launch evil.url to open
evil.webarchive
And just like that, we are executing JavaScript code anywhere we
want. The above screen recording injects 'alert(origin)' in https://
google.com.
Let's tie this together into one final attack.
Full Chain
Using ShareBear to download and open a webarchive file for us can be
broken down into 3 steps:
1) Trick the victim into giving us permission to plant the
polymorphic file
staging.png
2) Turn puppies.png into evil.dmg and launch it
mount.png
3) Turn evil.dmg into evil.url and launch it
urlfile.png
Of course turning "File A" into three different payloads will require
some server-side coordination. Another (less fun) way to pull-off
this attack is to have the victim agree to open a shared folder that
already has all the files ready-to-go.
Screen Recording of UXSS via viewing an iCloud Shared Folder
In the above screen recording, the victim agrees to view a folder
that contains some PNG images. This folder also has two hidden files
- .evil.dmg & .evil.url.
The website uses the icloud-sharing:// URL Scheme to automatically
launch both of the hidden files to successfully bypass Gatekeeper and
open a webarchive file. Note that no additional prompts are displayed
to the victim after he agrees to view the shared folder. The example
webarchive file above injects code into https://www.icloud.com to
exfiltrate the victim's iOS camera roll.
Of course this is just an example, this UXSS attack allows the
attacker to inject arbitrary code into arbitrary origins. It would be
just as easy to inject JavaScript code to turn on the webcam when
hijacking a trusted video chat website like https://zoom.us or https:
//facetime.apple.com. Mission accomplished.
Ryan Pickren hacked Apple Webcam
Screenshot of UXSS hijacking Zoom Website to turn on webcam
Remediation
So how did Apple fix these issues?
The first fix was to have ShareBear just reveal files instead of
launch them (fixed in macOS Monterey 12.0.1 without being assigned a
CVE).
The second fix was to prevent WebKit from opening any quarantined
files (fixed in Safari 15 as CVE-2021-30861; see fix implementation
here).
Bonus Material (#1)
Before I discovered the evil.url trick, I actually found a different
way to trick Launch Services into (indirectly) opening a webarchive
file. I found this bug on the latest public release of Safari
(v14.1.1). A few days after reporting this bug to Apple, they
informed me that the beta Safari v15 was not vulnerable. It appeared
that an unrelated code refactor made v15 impervious. For completeness
sake, I will quickly go over that bug anyway-
The obvious way to open Safari via Launch Services is with a local
html file. Once opened, this page will have the file:// URI scheme.
From there, JavaScript is allowed to navigate to other file:// URIs.
local HTML file navigating to another local file
So what happens if the file we are navigating to is a webarchive?
Well, Safari just hangs.
Screen Recording of Safari refusing to render a webarchive
This annoying hang occurred for every type of page navigation I could
think of (anchor href, iframe src, meta redirect, etc.) when the
destination file was a webarchive.
Then I found this bug:
local HTML file navigating to a local webarchive file
Safari forgets to perform the webarchive check when there is a host
value in a file:// URL! Funny enough, this bug appears to have been
introduced when Apple fixed my old file:// bug (CVE-2020-3885).
When Apple informed me that Safari Beta v15 wasn't vulnerable, I went
back to the drawing board and found the evil.url hack.
Bonus Material (#2)
There was still one thing that bugged me after I finished the UXSS
chain.... it can't be used to steal local files. Sure, UXSS can be
used to indirectly steal files by injecting code into https://
dropbox.com or https://drive.google.com, but files exclusively on the
victim's hard drive are out of reach.
The excellent Blackhat Presentation I referenced earlier inspired me
to look for other System applications that could run my JavaScript in
a more privileged context than Safari. After digging around for a
while, I stumbled upon an obscure filetype recognized my macOS Script
Editor called "Scripting Additions" (.osax). These files (or rather '
bundles') contained a nested xml-based file called a "Dictionary
Document" (.sdef). This dictionary document was used to display
human-readable, developer-defined, terms used by an AppleScript
application. Phew.
The important discovery was that these xml-based files are allowed to
contain HTML. As it turns out, the HTML renderer also has a
JavaScript engine and this engine does not enforce SOP! (fixed in
macOS Big Sur 11.6.2 as CVE-2021-30975) Which means stealing /etc/
passwd is easy-
fetch('file:///etc/passwd').then(x=>{x.text
().then(y=>{document.write(y);})})
]]>
evil.sdef displaying the content of /etc/passwd
Luckily for us, Gatekeeper does not mind us opening Scripting
Addition files. So we just take evil.sdef, package it in evil.osax,
and send it to the victim via ShareBear. Then our icloud-sharing://
URI can automatically launch it in Script Editor.
Screen Recording of ShareBear opening evil.osax to steal /etc/passwd
Nice, so now in addition to UXSS, this hack can also circumvent
sandbox restrictions and steal local files!
Conclusion
This project was an interesting exploration of how a design flaw in
one application can enable a variety of other, unrelated, bugs to
become more dangerous. It was also great example of how even with
macOS Gatekeeper enabled, an attacker can still achieve a lot of
mischief by tricking approved apps into doing malicious things.
I submitted these bugs to Apple in mid July 2021. They patched all
issues in early 2022 and rewarded me $100,500 as a bounty.