A vulnerability in the Mac Zoom Client allows any malicious website to enable your camera without your permission. The flaw potentially exposes up to 750,000 companies around the world that use Zoom to conduct day-to-day business.
UPDATE — July 9th (am)
As far as I can tell this vulnerability also impacts Ringcentral. Ringcentral for their web conference system is a white labeled Zoom system.
UPDATE — July 9th (pm)
According to Zoom, they will have a fix shipped by midnight tonight pacific time removing the hidden web server; hopefully this patches the most glaring parts of this vulnerability. The Zoom CEO has also assured us that they will be updating their application to further protect users privacy.
This vulnerability allows any website to forcibly join a user to a Zoom call, with their video camera activated, without the user's permission.
On top of this, this vulnerability would have allowed any webpage to DOS (Denial of Service) a Mac by repeatedly joining a user to an invalid call.
Additionally, if you’ve ever installed the Zoom client and then uninstalled it, you still have a localhost web server on your machine that will happily re-install the Zoom client for you, without requiring any user interaction on your behalf besides visiting a webpage. This re-install ‘feature’ continues to work to this day.
Yep, no joke.
This vulnerability leverages the amazingly simple Zoom feature where you can just send anyone a meeting link (for example https://zoom.us/j/492468757) and when they open that link in their browser their Zoom client is magically opened on their local machine. I was curious about how this amazing bit of functionality was implemented and how it had been implemented securely. Come to find out, it really hadn’t been implemented securely. Nor can I figure out a good way to do this that doesn’t require an additional bit of user interaction to be secure.
This vulnerability was originally responsibly disclosed on March 26, 2019. This initial report included a proposed description of a ‘quick fix’ Zoom could have implemented by simply changing their server logic. It took Zoom 10 days to confirm the vulnerability. The first actual meeting about how the vulnerability would be patched occurred on June 11th, 2019, only 18 days before the end of the 90-day public disclosure deadline. During this meeting, the details of the vulnerability were confirmed and Zoom’s planned solution was discussed. However, I was very easily able to spot and describe bypasses in their planned fix. At this point, Zoom was left with 18 days to resolve the vulnerability. On June 24th after 90 days of waiting, the last day before the public disclosure deadline, I discovered that Zoom had only implemented the ‘quick fix’ solution originally suggested.
Ultimately, Zoom failed at quickly confirming that the reported vulnerability actually existed and they failed at having a fix to the issue delivered to customers in a timely manner. An organization of this profile and with such a large user base should have been more proactive in protecting their users from attack.
On Mac, if you have ever installed Zoom, there is a web server on your local machine running on port 19421. You can confirm this server is present by running lsof -i :19421 in your terminal.
First off, let me start off by saying having an installed app that is running a web server on my local machine with a totally undocumented API feels incredibly sketchy to me. Secondly, the fact that any website that I visit can interact with this web server running on my machine is a huge red flag for me as a Security Researcher.
Here’s the code on the Zoom site that tipped me off to this localhost server.
My original thoughts when I learned that this web server existed was that if there is a buffer overflow anywhere in the parameter handling of this web server, someone could achieve RCE on my machine. That’s not what I’ve found, but that was my original thought process.
If you look at what’s logged to the web developer console when visiting one of those Zoom ‘join’ links, you should see something like this:
Browser console logs when visiting https://zoom.us/j/492468757
I also found that, instead of making a regular AJAX request, this page instead loads an image from the Zoom web server that is locally running. The different dimensions of the image dictate the error/status code of the server. You can see that case-switch logic here.
The two numbers are the pixel dimensions of the image returned by the web server.
The scary thing is that this enum seemed to indicate that this web server can do far more than just launch a Zoom meeting. What I found out was that this web server can also re-install the Zoom app if a user has uninstalled it, more on that later.
One question I asked is, why is this web server returning this data encoded in the dimensions of an image file? The reason is, it’s done to bypass Cross-Origin Resource Sharing (CORS). For very intentional reasons, the browser explicitly ignores any CORS policy for servers running on localhost.
Chrome does not support localhost for CORS requests (an open bug since 2010).
I’m guessing that this is intentionally done for security reasons. Regardless, it seems that Zoom is abusing a hack to bypass CORS protection. More on that later.
The Video Call Vulnerability
I created a personal meeting with a different account and cracked open Postman and started to remove parameters to see what the minimal GET request was that was required to launch a Zoom meeting.
There are a lot of random parameters that are sent to the localhost web server but the only ones that seem to matter are the following.
Using the following GET request from Postman I was successfully able to get my computer to join the Zoom call that the other account had created.
Once I had this, I started tinkering with what other “action” parameters I might be able to pass to get the client to do other things. I wasn’t able to find anything even after searching through the various public documents and the public ProtoBuff schema for hints about what hidden functionality may exist. Again, this webserver’s API is completely undocumented as far as I can tell and I’ve spent several hours searching for any mention of this Desktop web server in the official and unofficial documentation.
So now I had a minimal POC that I could use to maliciously get any user into a call, however, the default setting for the “New Meeting” is to allow the user to choose whether to join their Audio/Video. I would consider this alone a security vulnerability.
The above-described behavior continues to work to this day! You can still use this exploit to launch someone into a call without their permission.
I read about the Tenable Remote Code Execution in Zoom security vulnerability which was only patched within the last 6 months. Had the Tenable vulnerability been combined with this vulnerability it would have allowed RCE against any computer with the Zoom Mac client installed. If a similar future vulnerability were to be found, it would allow any website on the internet to achieve RCE on the user’s machine.
I advised Zoom that if they have any users that are still using Zoom 4.1.33259.0925 versions or lower, this would be a very potent attack.
So far, I could only achieve getting a user into a call without their permission. Although this has hypothetical security implications, I didn’t have a true exploit. I started tinkering with figuring out how to get someone’s camera activated. When setting up a meeting for work I was greeted with this screen.
You can choose to enable a participant’s video camera when they join the call.
Enabling “Participants: On” when setting up a meeting, I discovered that anyone joining my meeting automatically had their video connected.
When I got back to my personal machine, I tried this same functionality and found that it worked exactly the same.
This prompted me to create the Proof Of Concept below.
Proof Of Concept
The local client Zoom web server is running as a background process, so to exploit this, a user doesn’t even need to be “running” (in the traditional sense) the Zoom app to be vulnerable.
One line, it’s really that simple.
Or if you want the video camera activated, just embed a Zoom join link in your site with an iframe.
All a website would need to do is embed the above in their website and any Zoom user will be instantly connected with their video running. This is still true today!
A fully working POC that you can test out yourself can be found at the link below. Warning: Clicking this link on Mac will launch you into a Zoom call!
A fully working POC that will launch you into a call with your video camera active can be found here. Warning: Clicking this link on Mac will launch you into a Zoom call with your camera activated!
To fix the “auto join with video” part of the vulnerability, I advised Zoom on their backend server they immediately disable a meeting creator’s ability to automatically enable a participants video by default. I advised that this was 100%, not a complete fix. However, it could serve as a quick way to protect users from the invasion of privacy component of this attack.
I also advised that if there is hidden functionality where a meeting host can forcibly join computer audio (perhaps something I’m not seeing because I don’t have a Pro account), this should also be disabled.
I commented that allowing a host to choose whether or not a participant will automatically join with video should be considered it’s own standalone security vulnerability.
To this advisement, I received the following response:
Zoom believes in giving our customers the power to choose how they want to Zoom. This includes whether they want a seamless experience in joining a meeting with microphone and video automatically enabled, or if they want to manually enable these input devices after joining a meeting. Such configuration options are available in the Zoom Meeting client audio and video settings.
However, we also recognize the desire by some customers to have a confirmation dialog before joining a meeting. Based on your recommendations and feature requests from other customers, the Zoomteam [sic] is evaluating options for such a feature, as well as additional account level controls over user input device settings. We will be sure to keep you informed of our plans in this regard.
When responding to responsible disclosure, don’t go into PR spin mode. It’s counterproductive.
It’s important to note that the default configuration for Zoom is to allow a host to choose whether or not your camera is enabled or not by default.
Zoom did end up patching this vulnerability, but all they did was prevent the attacker from turning on the user’s video camera. They did not disable the ability for an attacker to forcibly join to a call anyone visiting a malicious site.
UPDATE: July 7th, 2019: There has been a regression in the fix implemented by Zoom thus allowing this vulnerability to be exploited with the video camera activated.
The Denial Of Service (DOS) Vulnerability
This same vulnerability also allowed the attacker to DOS any user’s machine. By simply sending repeated GET requests for a bad number, Zoom app would constantly request ‘focus’ from the OS. The following simple POC demonstrated this vulnerability.
Proof of concept for a DOS attack against any Zoom user on Mac
This DOS vulnerability was patched in version 4.4.2 of the Zoom client.
The Install Vulnerability
If you have ever installed Zoom on your computer, this web server is installed. It continues to run if you uninstall Zoom from your computer.
This server also supports updating and installing a new version of Zoom in addition to launching a call. I did some additional decompilation of the Zoom web server to see the code path that these endpoints seemed to call.
Using Hopper Disassembler to disassemble the Objective-C bytecode of the web server I found the following method.
Takes arguments from some API request and uses it to craft a download URL used to upgrade the version of Zoom installed?
This method is gated by the following logic.
Ensures the download URL is only under ‘trusted’ subdomains.
One of the API’s inside of this web server running on all Macs with Zoom installed is an endpoint that allows the current version of Zoom that’s installed to be updated or re-installed by this server.
You can confirm that this logic does indeed exist by doing the following:
Using the list of domains listed inside of the application that could be used to download updates for the Zoom app, I decided to check and see what each of the sites returned when visited. For example, here’s the result of visiting https://zipow.com/upgrade?os=mac
You can clearly see the URL to be used to download the zoom installer if Zoom needs to be re-installed.
Doing a whois lookup on all of the domains listed in the source code returned some interesting results. For example, the domain zoomgov.comwas scheduled to expire on May 1st, 2019. Had this domain registration been allowed to lapse, the takeover of this domain would have allowed an attacker to host an infected version of the Zoom installer from this site and infected users who had uninstalled Zoom from their computers. Essentially, this would have made this vulnerability a Remote Code Execution (RCE) vulnerability. I disclosed this bit of information to the Zoom team during my call with the Mozilla security team on April 26th, 2019. Within 5 hours of the end of that call that domain had been registered out to May 1st, 2024.
Fundamental Security Vulnerability
In my opinion, websites should not be talking to Desktop applications like this. There is a fundamental sandbox that browsers are supposed to enforce to prevent malicious code from being executed on users machines.
In discussing this vulnerability with both the Chromium and Mozilla Firefox security team they both said that they couldn’t do anything about this vulnerability. The Chromium team pointed me to CORS-RFC1918 which is a proposal that will require browser vendors to query users for permission before allowing sites to make requests against local resources like localhostand the 192.168.1.* address space.
Linked in that RFC is a wonderful and fun to read bug report where Tavis Ormandy of Google’s Project Zero found a similar vulnerability in TrendMicro’s Password Manager allowing remote code execution via the browser and the exfiltration of a user’s passwords from a password vault. That story is well worth the read.
When this same vulnerability was reported to the Mozilla Firefox team, they closed it as it wasn’t considered a vulnerability against Firefox. However, they soon reopened the report as a vulnerability against their internal infrastructure. As a result, I was invited into a call with the Zoom and Mozilla Firefox team to discuss the vulnerability on April 26th, 2019. During this call, they promised Mozilla and me that this vulnerability would be patched well before the end of the 90-day disclosure deadline. This turned out to be false.
Zoom’s Proposed Fixes
The fix proposed by the Zoom team was to digitally ‘sign’ the request made to the client. However, this simply means that an attacker would have to have a backend server that makes requests to the Zoom site first to gain a valid signature before forwarding the signature on to the client.
They also proposed locking the signature to the IP that made the request. This would mean that as long as the attacker’s server was behind the same NAT router as the victim, the attack would still work.
I described to the Zoom team how both of these solutions were not enough to fully protect their users. Unfortunately, this left the Zoom team with only 18 days before public disclosure to come up with some better solution.
Unfortunately, even after my warning, this was the solution they chose to go with. This new signature or token is embedded in a new parameter called confid. The simplest way to bypass this new confid check was to simply use the iframe workaround described above. Alternatively, if you and the victim are behind the same NAT router, you can make a request for the join page, extract the #lhs_launch_parames field from the HTML document and embed it in the HTML response from the malicious page.
As of 2015 Zoom had over 40 million users. Given that Macs are 10% of the PC market and Zoom has had significant growth since 2015 we can assume that at least 4 million of Zoom’s users are on Mac. Tools like Zoom, Google Meet or Skype for Business is a staple of today's modern office.
Any vulnerability in an application with this many users must be considered a serious threat to all those users. All of the vulnerabilities described in this report can be exploited via “drive-by attack” methodologies. Many times during my conversation with the Zoom security team they seemed to argue that the seriousness of this vulnerability was limited because it would require “user interaction” to exploit these. My response to this was finally “I would highly suggest that you not hang your hat on ‘user interaction required’ for protecting your users given that this ‘user interaction’ is simply clicking a link or visiting a webpage.”
I believe that in order to fully protect users, I truly believe that this localhost web server solution needs to be removed. Alternative methodologies like registering custom URI handlers (for example, a zoom:// URI handler) with the browsers is a more secure solution. When these URI handlers are triggered, the browser explicitly prompts the user for confirmation about opening the app. According to the Zoom team, the only reason this localhost server continues to exist is that Apple’s Safari doesn’t support URI handlers.
This is essentially a Zero Day. Unfortunately, Zoom has not fixed this vulnerability in the allotted 90-day disclosure window I gave them, as is the industry standard. As such, the 4+ million users of Zoom on Mac are now vulnerable to an invasion of their privacy by using this service.
Additionally, due to a lack of sufficient auto-update capabilities, many users continue to run outdated versions of Zoom for months after new releases are shipped leaving them vulnerable to exploits like these.
If you want to patch this vulnerability for yourself you can do the following.
Disable the ability for Zoom to turn on your webcam when joining a meeting.
Alternatively, use this terminal command.
Instead of using the UI for the application to disable this, you can also use the terminal.
To shut down the web server, run lsof -i :19421 to get the PID of the process, then do kill -9 [process number]. Then you can delete the ~/.zoomus directory to remove the web server application files.
To prevent this server from being restored after updates you can execute the following in your terminal:
If you want a full description of how to resolve this on Windows and Mac see the Gist below.
Notes For Researchers
Given the massive install base for Zoom, I highly recommend that other researchers take the time to explore this Zoom web server to see what other vulnerabilities exist. This being said, I also recommend that any researcher that finds a vulnerability in Zoom’s software does not directly report the vulnerability to Zoom. Instead, I recommend that researchers report these vulnerabilities via the Zero Day Initiative (ZDI). The ZDI disclosure program gives vendors 120 days to resolve the vulnerability, the ZDI will pay researchers for their work, and researchers have the ability to publicly disclose their findings.
If you want to decompile the Zoom client application for yourself, it’s located in the ~/.zoomus directory on your computer.
The source code repository for my POC examples can be found on GitHub.
Quote from: Jonathan Leitschuh