Talos Vulnerability Report


Shimo VPN helper tool code-signing privilege escalation vulnerability

April 15, 2019
CVE Number



An exploitable privilege escalation vulnerability exists in the Shimo VPN helper service due to improper validation of code signing. A user with local access can use this vulnerability to raise their privileges to root. An attacker would need local access to the machine to successfully exploit this bug.

Tested Versions

Shimo VPN

Product URLs


CVSSv3 Score

8.8 - CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H


CWE-19: Improper Input Validation


Shimo VPN is a VPN client for Mac OSX used to connect to multiple VPN accounts in one place. The application uses what is defined as a “Helper Tool” to do some of the privileged work on its behalf. The helper tool is installed as root when the application is first installed and is a LaunchD daemon, meaning it will be restarted if it is killed. The service listens using:

v3 = objc_msgSend(&OBJC_CLASS___NSXPCListener, "alloc");
v4 = objc_msgSend(v3, "initWithMachServiceName:", CFSTR("com.feingeist.shimo.helper"));

The second argument registers the string passed in as a service and tells it to begin listening. The service can then be connected to using Objective-C XPC calls.A similar section of code needs to be executed to connect a client to this service.

 v8 = objc_msgSend(v7, "initWithMachServiceName:options:", CFSTR("com.feingeist.shimo.helper"), 4096LL); [1]
  v11 = objc_msgSend(
          &OBJC_PROTOCOL___ShimoHelperToolProtocol);                                                      [2]

At [1], the same call as the one above is used, except this time, the options variable is used to signify that the client is connecting rather than listening. At [2], a special protocol is passed in that defines all the functions available to the client. The server must have the same protocol defined in order for these calls to work. We can begin to see the vulnerabilities arise by looking at the protocol.

This vulnerability is present inside of the connection management code for all the different provided VPN services. We will be focusing on connectOpenVPNWithConfig:withManagementPort:withReply: for this report. When one first installs the Shimo application, it bundles multiple VPN clients to actually instantiate the connections. These include, among others, openconnect, openvpn and vpnc. All of these executables are vulnerable to this code-signing attack. Below is the relevant code for the connectOpenVPN command.

v20 = objc_msgSend(self->shimoBundle, "pathForAuxiliaryExecutable:", CFSTR("openvpn"));         [3]
openvpn_path = objc_retainAutoreleasedReturnValue(v20);
          "runServiceAtPath:withArguments:withComPort:waitUntilExit:withError:",                [4]

The above code snippet simply takes the path for the openvpn executable path,[3] and passes it into a helper function designed to run the service passing in the required arguments, [4]. The vulnerability becomes apparent when looking at the runServiceAtPath function.

if (  v13 = objc_msgSend(v11, "fileExistsAtPath:", v9),                                               [5]
      v14 = v13 == 0,
      v9 = v12,
      v14) )

if ( -[ShimoHelperTool codeSignStateForExecutable:](self, "codeSignStateForExecutable:", v12) != 2 )  [6]
  objc_msgSend(v16, "setLaunchPath:", v12);
  objc_msgSend(v16, "setCurrentDirectoryPath:", self->tmpDirPath);
  if ( v22 )
    objc_msgSend(v16, "setArguments:", v22);
  v37 = v16;
  objc_msgSend(v16, "launch");                                                                         [7]

At location [5], the passed-in executable is verified to actually exist. Then, at location [6], the executable is checked to be properly signed, and at [7], the program is launched with the required arguments. The issue with the code comes at location [6]. If we look at the function codeSignStateForExecutable, it will give us a bit more information as to what is happening at this line.

 v7 = 0LL;
  v3 = objc_msgSend(&OBJC_CLASS___NSURL, "fileURLWithPath:", a3);
  v4 = objc_retainAutoreleasedReturnValue(v3);
  SecStaticCodeCreateWithPath(v4, 0LL, &v7);
  v5 = 6;
  if ( v7 )
    switch ( SecStaticCodeCheckValidityWithErrors(v7, 6LL, 0LL, 0LL) + 67062 )            [8]

This function first verifies that the file exists at the path. Then, at location [8], it calls out to an Apple-provided security API to check the code-signing of an executable. The second argument passed in the expected level of code-signing verification performed by this function call. Looking at the API, we can see that 6 correlates to kSecCSBasicValidateOnly. What this means is that the check is only verifying that the code is properly signed. There are no checks or verifications on the signing authority and thus any properly signed binary can be executed here. It is trivial to create a self-signed certificate to pass this check. Then, any application can be put into the place of the provided executable and be executed under root context. This creates a privilege escalation vulnerability.

Exploit Proof of Concept

This vulnerability is demonstrated with a program we have created and signed ourselves included with this report called openvpn_dummy. When run through the Shimo app this program will create a file called root.txt in the root directory, which is not writeable to any other than the root user. The Shimo application needs to attempt to establish a connection using OpenVpn and the replacement executable needs to be put into the application directory replacing the provided OpenVpn binary. Example command is shown below.

mv openvpn_dummy Shimo.app/Contents/MacOS/openvpn 


2018-09-21 - Vendor Disclosure
2018-09-22 - Vendor acknowledged and gave main developer contact
2018-09-26 - Reports sent to main developer
2018-10-08 - First follow up
2018-11-09 - 2nd follow up
2018-12-04 - 3rd follow up
2019-03-14 - Final follow up for public disclosure
2019-04-15 - Zero day/Public release


Discovered by Tyler Bohan of Cisco Talos.