TL;DR
This blog unveils a remote code execution vulnerability, identified as CVE-2023-22524, in Atlassian Companion for macOS, which has recently been patched. This critical vulnerability stemmed from an ability to bypass both the app’s blocklist and macOS Gatekeeper, potentially allowing the execution of harmful code. Users are advised to upgrade to version 2.0.0 or later.
In my latest exploration into Atlassian Companion, an application for editing Confluence files through desktop applications, I discovered a new remote code execution (RCE) vulnerability affecting all macOS users. This exploration was sparked by Wojciech Reguła’s informative blog, which highlighted a RCE vulnerability arising from the absence of `.class` files in the app’s extensive blocklist of over 350 extensions. Reguła’s discovery specifically affects macOS users with Java installed and requires them to click the “Edit” button on a `.class` file within a trusted Confluence site.
Atlassian’s Quick Fix
Following Reguła’s revelation, I became intrigued by Atlassian’s fix—simply adding the `.class` extension to the blocklist. This felt a bit like a never-ending game of whack-a-mole and I pondered, if just one harmful extension slips through, are we back to square one with remote code execution? This concern was heightened by Atlassian Companion bypassing macOS Gatekeeper, a security feature that verifies and ensures downloaded applications are from recognized developers and free of malware before they are allowed to run.
Atlassian’s decision not to add the quarantine attribute to files downloaded via the Companion app might be driven by a focus on user convenience, as the quarantine attribute can cause additional steps for users to access their downloaded files. Atlassian may have chosen to prioritize ease of use and efficiency. However, it’s important to consider the security implications of this decision, and the vulnerability I discovered illustrates just that.
Reviewing The Code
As an Electron application, Atlassian Companion offers accessible source code, which is always a great advantage when trying to find vulnerabilities. To access this source code, one can use commands to unpack the application’s `asar` archive, commonly found in the resources directory. This is typically done using the `asar` utility, installed via npm, and the command `asar extract app.asar destination_folder` to extract the files. The app uses WebSockets for communication with Confluence, explicitly running a WebSocket server on port 31459 open to all origins. There are two options for authentication: “jwt” and “server.” The “jwt” option uses JWT tokens verified by public keys fetched from trusted keystore URLs. However, it was the “server” option that caught my attention. This method checks if the WebSocket connection’s origin is listed among trusted domains. If the domain isn’t already trusted, Atlassian Companion displays a popup, asking the user whether to trust the requesting domain. Interestingly, by including a “siteTitle” in the authentication message, one can manipulate the popup text asking users to trust a domain.
This manipulation could mislead users into trusting harmful domains. To add to the confusion, we could redirect users to a website such as confluence.atlassian.com before triggering a popup.
Below, you can see the before and after for the trust popup:
Once a domain is trusted, various API calls become accessible, notably “launch-file-in-app” and “list-apps.” The former downloads and executes a file, while the latter identifies suitable applications for a given MIME type. Combining these allows one to open virtually any file with any application, provided the file extension is not on the blocklist, and the application can be found using “list-apps.”
I looked closer at how Atlassian Companion finds applications for different MIME types. It employs an internal library, @atlassian/file-associations, which utilizes Objective-C++ and Apple’s Launch Services methods `LSCopyDefaultRoleHandlerForContentType` and `LSCopyAllRoleHandlersForContentType` to identify both the default and all other applications supporting a given MIME type.
The FileManager class was another focus area. This class orchestrates all the main functionality, including downloading and storing files and determining which files to block. The blocklist for macOS integrates several risk categories plus an optional environment variable, COMPANION_BLOCK_LIST. Notably, even though the blocklist effectively stopped dangerous files, it did so only after storing them on the user’s system, which proved valuable for exploitation.
It dawned on me that the ability to directly communicate with the WebSocket server significantly broadens the attack surface and increases the chances of uncovering a bug that could allow remote code execution. This situation differed from the one described in Reguła’s blog: I could download multiple files and selectively determine the applications used to open them.
To delve deeper into how this behavior could be exploited, I modified `querier.mm` to extract all available applications from a default macOS installation that can be found using the ‘list-apps’ call. This effort resulted in a list of 39 applications.
Shortcut Shenanigans
If you’ve read previous Imperva findings, you know that symbolic links can be a great asset. Among the many obscure file extensions I’ve examined, I stumbled upon `.fileloc,` a shortcut file used on macOS systems. It acts as a reference to another file or folder, making it ideal for bypassing blocklists. For example, downloading a `.class` file, which, as I mentioned earlier, gets blocked but is still stored on the user’s file system, and then downloading and running a `.fileloc` that points to it will result in remote code execution.
However, unlike symbolic links, the `.fileloc` file requires the absolute path to the target file, and Atlassian Companion generates a random folder inside the `~/.atlassian-companion/` path for every downloaded file. I needed to find a way to leak both the macOS username and the folder name of the `.class` file.
Reviewing the WebSocket communication, I noticed that the folder UUID was sent back, leaving only the macOS username to be identified. While looking at the blocklist, I saw that the `.html` extension was also blocked. This led me to an idea: when opening local HTML files, the window.location.href reflects the full file path, including the macOS username. Since only `.html` was blocked, other extensions like `.svg,` `.xml,` and `.htm` could be used for browser JavaScript execution.
The Exploit
Putting this all together—The exploit first downloads a `.class` file, blocked by the extension validation but stored on the user’s system. We retain the folder UUID and download and execute a `.htm` file, which sends back the macOS username. With this information, we dynamically generate a `.fileloc` file pointing to the `.class` file using the UUID and the username. The `.fileloc` is executed with JavaLauncher, enabling remote code execution.
However, this requires the user to have Java installed. To overcome this, I inadvertently found a more straightforward solution using Automator, a macOS tool designed to create workflows to automate repetitive tasks. Initially, I used Automator binaries – essentially, executable files created by Automator – for their ease in quickly developing functional macOS applications. With this setup, I wrote a script to open the Automator executable with each of the 39 applications I had identified. Notably, when the calculator application was triggered, it revealed that com.apple.ScriptEditor2, macOS’s built-in Script Editor, could execute these Automator binaries, suggesting a new approach: change the `.class` file to a `.zip` file. When executed, it will unzip our Automator application onto the user’s file system. Then, we leak the username and download and run a `.fileloc` file pointing to it with Script Editor. Voilà, remote code execution that doesn’t require Java!
You can get the complete exploit source code on GitHub.
The Fix
Imperva responsibly disclosed both exploits to Atlassian and communicated the issues related to macOS Gatekeeper. Atlassian responded by releasing version 2.0.0, ending support for WebSockets and adding the “.fileloc” extension to the blocklist which addresses the vulnerability. After further communication, version 2.0.1 was released adding the “.inetloc” extension to the blocklist as well. Users are advised to upgrade to the latest version.
Upon examining the update, I noticed that communication relies solely on the Atlassian Companion protocol. While this change prevents remote code execution, it still leaves some weaknesses. Notably, downloaded files still don’t have the quarantine attribute, which could be useful for attackers as a way to bypass macOS Gatekeeper.
Conclusion
Update to the latest Atlassian Companion. We appreciate Atlassian’s responsiveness and cooperation in resolving the reported security issue. We believe in the significance of identifying and addressing vulnerabilities, and we are committed to ongoing collaborations with providers like Atlassian to make the online world safer for everyone.
Try Imperva for Free
Protect your business for 30 days on Imperva.