This all started when my wife said her computer was booting slower and "being weird." I booted her computer and noticed that indeed, it was booting up slowly. The computer was also flashing odd grey squares intermittently on the otherwise black screen in the bootup process. I began my investigation by checking the usual troublesome areas.
Initial Investigation
First I looked at any programs that start automatically upon system boot that may be slowing things down. To do this, I checked for programs that automatically run at login. These programs are typically used for user-level services and background processes that need user interface access, such as menu bar apps, user-specific background services, or apps that need to display notifications.
ls /Library/LaunchAgents
The above lists the launch agents that affect all users of the system, so I also checked for any launch agents that are only affecting my user role as well:
ls ~/Library/LaunchAgents
Next, I checked for launch daemons. Launch daemons are processes that run at boot time, as opposed to login time for agents. They always run with "root" privileges (i.e. the maximum set of privileges). Unlike launch agents, launch daemons cannot access the user interface or user session. They are used for system services, network services, and other background processes that need to run continuously regardless of whether any user is logged in or not.
ls /Library/LaunchDaemons
The above resulted in me finding a bunch of developer programs that I didn't need anymore and were still running in the background, so I removed them. I restarted and things were still running slowly and the odd grey squares were still there, so I decided to dig further to see what else I could find. I checked for system extensions:
systemextensionsctl list
Oddly, I found that ProtonVPN had three related system extensions that were activated even though I had uninstalled the application a few weeks prior via the process recommended by the vendor, so seeing these system extensions still active gave me pause. The system extensions were ProtonVPN, OpenVPN, and OpenVPN-Extension.
I attempted to uninstall the ProtonVPN system extension by running:
systemextensionsctl uninstall [TEAM ID] [BUNDLE ID]
However, when I ran this command I found that it wouldn't execute due to System Integrity Protection (SIP) being enabled. SIP was implemented by Apple to protect critical system files and processes from being modified, even by users with root privileges. It is a great security addition to MacOS but I knew I had to disable it in order to uninstall the system extension. Before I did that though, I wanted to make sure I was removing the entire application and that there were no files that would re-install.
To check this, I ran:
ps aux | grep -i vpn
This is actually a set of commands rather than a single command. The commands search all running processes for those with "vpn" in the name. Breaking it down part by part:
- "ps" shows the status of actively running processes
- "aux" is not actually a command but rather flags that specify how the output returns
- " | " is called a pipe and it takes the results from the left command and runs the right command on that specific data set
- "grep" is a powerful search command for specific strings within a data set
- "-i" is another flag that specifies that the string search should be case-insensitive
- Finally, "vpn" is the string that is being searched for
The result showed me that a process called "ch.protonvpn.ProtonVPNStarter" was still running in the background, even though I had uninstalled the software. Even more weirdly, nothing related to ProtonVPN was listed in Library/LaunchAgents, so it was unclear where the application was launching from. I tried to find the files that were re-launching the application:
find ~/Library -iname "*proton*" 2>/dev/null
sudo find /Library -iname "*proton*" 2>/dev/null
Let's break down these commands further:
- The "sudo" command elevated privileges so that the user (me) can read filenames in directories that are restricted from access by regular users
- The "find" command searches for strings in filenames across an entire directory, in this case the /Library directory
- The "-iname" is a flag that makes it case-insensitive
- "2>/dev/null" redirects standard errors to a special file that discards the data, reducing noise
The results showed me that there were ProtonVPN related files in the following directories:
/Users/username/Library/Saved Application State/ch.protonvpn.mac.savedState
/Users/username/Library/Application Scripts/ch.protonvpn.mac
/Users/username/Library/Application Scripts/group.ch.protonvpn.mac
/Users/username/Library/Group Containers/group.ch.protonvpn.mac
/Users/username/Library/Containers/ch.protonvpn.mac
/Users/username/Library/Caches/ch.protonvpn.mac
So a container was running in the background despite my uninstallation! I couldn't remove the container because it was still active due to built-in MacOS protections. So I had to grant the terminal Full Disk access temporarily, and then removed all the files using:
rm -rf ~/Library/Containers/ch.protonvpn.mac
However, when I checked again using ps aux, the container was installed and running again! I must have missed a file. I checked the PrivilegedHelperTools directory and found even more proton-related files:
/Library/SystemExtensions/[UUID]/ch.protonvpn.mac.OpenVPN-Extension.systemextension
/Library/SystemExtensions/[UUID]/ch.protonvpn.mac.OpenVPN-Extension.systemextension/Contents/MacOS/ch.protonvpn.mac.OpenVPN-Extension
I used lsof to find what files the process was using, and found it running from an unexpected place - the Trash!
/Users/username/.Trash/ProtonVPN.app/Contents/Library/LoginItems/ProtonVPNStarter.app/Contents/MacOS/ProtonVPNStarter
Lessons Learned
What a journey. I traversed hidden corners of the Unix-type operating system (MacOS is based on UNIX), had to temporarily disable security features, and got sneaky with files restarting processes from the Trash. The application employs multiple techniques commonly associated with malware, including running from the Trash after uninstallation, resisting termination commands, obscuring process names, and requiring system-level security features (SIP) to be disabled for complete removal.
In my opinion, there isn't a good reason that the application is architected this way. The persistence mechanisms go beyond reasonable requirements for an application, but especially for a privacy tool. What is more, if these deep system hooks were to be compromised, they could provide an attacker with significant system access.
The moral of the story is that folks need to be vigilant when it comes to "security" and "privacy" software, even from ostensibly reputable companies. It truly is a jungle out there.