Blog: Vulnerability Advisory

PrivEsc in Lenovo Vantage. Two minutes later

Ceri Coburn 20 Mar 2020

TL;DR

The latest and greatest Lenovo Vantage software which ships with the most recent Lenovo devices is affected by a privilege escalation vulnerability.

Whilst Vantage has been released since circa 2016, the software replaced Lenovo Solutions Centre (LSC) as the recommended platform management and system update tool for Lenovo devices. LSC was end of life’d back in November 2018, you may remember us reporting a privilege escalation in LSC last year.

The core of the issues lies with a directory traversal bug which can be exploited through manipulating application and plugin names to cause untrusted execution of arbitrary executables or DLL’s that are in control by an unprivileged account.

If you have got the Lenovo Vantage software running on your devices then you are advised to update to the latest version from Lenovo. The issues have been assigned CVE-2020-8319 and CVE-2020-8324.

CVE-2020-8319 and CVE-2020-8324

Lenovo Vantage depends on a service called System Interface Foundation Service. This service performs all sorts of Lenovo specific behaviours through an intricate system of plugins. These plugins perform anything from performing system updates to simple battery gauge readings and generally map to features found within the Vantage software.

Each plugin has a signed PackageManifest.xml file within its installation directory describing the plugin contract that it has to offer in addition to whether the plugin should run under the user privilege context or SYSTEM context. On my test laptop there appeared to be 5 plugins available that run under the SYSTEM context, one of which was the LenvoAppScenarioSystem plugin.

Plugin Manifest File:

The Contract

As mentioned, each plugin offers a contract to the underlaying service, which in turn is exposed over an IPC mechanism open to any user via a UMDF driver interface.  Each plugin offers many functions within the contract that is exposed over the IPC interface.  In addition to the plugin contract, the service itself has its own internal contract for performing updates and other general software maintenance tasks.  One such command offered by the internal contract is Install-PendingUpdates.

Typically, when new plugin updates are downloaded from Lenovo, they are eventually placed inside the %PROGRAMDATA%\Lenovo\ImController\Plugins folder with the same name as the plugin and an underscore appended.

For example, if we take the LenvoAppScenarioSystem plugin, the final pre update folder location would end up being PROGRAMDATA%\Lenovo\ImController\Plugins\LenovoAppScenarioSystem_.

Once the update folder has been prepared, a plugin update timer is fired every 2 minutes or roughly 180 seconds that will overwrite the files in the existing plugin folder at PROGRAMDATA%\Lenovo\ImController\Plugins\LenovoAppScenarioSystem.

Good things come in threes twos

So, why chose the LenovoAppScenarioPluginSystem plugin to attack.  The answer to this is twofold.  The first reason is that Lenovo Vantage plugins can run under the context of the user or system account as mentioned within the first part of this blog post.  As its name suggests, the LenovoAppScenarioPluginSystem plugin runs under the SYSTEM context.

The second reason is signature checking.  Lenovo have put efforts in place to prevent non Lenovo signed plugins from executing.  Let’s say for example, a path traversal exploit is found, and a plugin is updated with a malicious equivalent, the idea here is to prevent the plugin from executing 😉.

OK, so let’s talk turkey.  How can we exploit the LenovoAppScenarioPluginSystem plugin? We use the UDMF driver interface to send a specially crafted request to the command broker.

<InstallPendingRequest>
  <PackageList>
    <Package name=""..\..\..\LenovoAppScenarioPluginSystem""/>
  </PackageList>
</InstallPendingRequest>

Due to the unchecked package name attribute, the ImController service now searches for the plugin download location at %PROGRAMDATA%\Lenovo\LenovoAppScenarioPluginSystem_.  As you’ve probably already guessed, this location is writable by unprivileged users.  The folder is then copied to PROGRAMDATA%\Lenovo\ImController\Plugins\LenovoAppScenarioSystem_ ready for the timer to kick off and place the plugin into its final resting place.

The chain is broken

With a mechanism now in place to replace plugin files using an unprivileged account, we now need a way to bypass the signature checks.  Prior to any plugin DLL being loaded by the plugin broker service, the DLL is checked to ensure that it is signed by a Lenovo certificate.  If the DLL is not signed by a valid Lenovo certificate, the broker refuses to load the plugin and the request fails.

But there was something different about the LenovoAppScenarioPluginSystem plugin, it had dependencies on other DLL’s, and specifically a native DLL called TouchScreenContronlDLL.dll.  Analysing the plugin, it was found to import the native DLL using the DllImport attribute.

namespace Lenovo.Modern.Plugins.SmartSetting.AppScenarioSettingPluginSystem
{    
    public class DependDll
    {
        
        public static bool GetTouchScreenStatus()
        {
            int num = 0;
            try
            {
                num = DependDll.GetTouchStatus();
            }
            catch
            {
            }
            return num == 2;
        }

        public static int SetTouchScreenStatus(bool isOpen)
        {
            if (isOpen)
            {
                return DependDll.TouchScreenContronl(1);
            }
            return DependDll.TouchScreenContronl(0);
        }

        [DllImport("TouchScreenContronlDLL.dll")]
        public static extern int TouchScreenContronl(int ops);


        [DllImport("TouchScreenContronlDLL.dll")]
        public static extern int GetTouchStatus();
    }
}

Unfortunately, due to this minor oversight by Lenovo developers, the chain of trust within this Lenovo plugins eco system was broken.  Since no additional certificate checks were performed on DLL’s loaded by the plugin itself, we now have a valid attack chain.  Replacing TouchScreenContronlDLL.dll with our own malicious version prior to deploying our custom plugin update would enable us to obtain privilege escalation to SYSTEM.

2 minutes later

The final step of the analysis was to determine how to call the exported GetTouchStatus function when utilising the LenovoAppScenarioPluginSystem.  It was found that each plugin can expose their own contracts to the contract broker, and below is the contract exposed by the plugin in question.

LenovoAppScenarioPluginSystem exposed contract:

With the contract now known, a broker request executing the Get-TouchScreenState command should eventually lead to the loading of the native DLL TouchScreenContronlDLL.dll which is under our control.

Now that we have all the information needed, some questionable C# code 30 minutes later and a meterpreter reverse shell, this led to fully automated privilege escalation vulnerability after waiting around 2 minutes for the update timer to trigger.

Disclosure and fix

Lenovo released an update to System Interface Foundation on the 16th of March 2020.  The fix should already be installed for those that have Lenovo Vantage set to automatically update.  Checks are now performed to determine if the package name is valid and the additional native DLL’s are now checked for a Lenovo certificate prior to loading the DLL.

  • 16th Jan 2020 – Details sent to Lenovo PSIRT and tracked with id LEN-30401.
  • 17th Jan 2020 – Lenovo development team confirmed vulnerability.
  • 11th March 2020 – Lenovo assign CVE-2020-8319 and CVE-2020-8324 to internal issue LEN-30401.
  • 16th March 2020 – Lenovo release update to System Interface Foundation fixing both CVE’s.
  • 19th March 2020 – Fixes confirmed to be effective.