Beyond good ol’ Run key, Part 53

Most of the persistence methods described in this blog series so far focused on the old-school assumption that the system is a typical ‘bare metal’ Windows host. Over last couple of years many hosts are no longer real, and VDIs and Guest OS technologies they rely on introduce new techniques that attackers and malware can potentially use to stay persistent on the system. The features that are designed to support work of VDI may as well serve a malicious purpose. And this is what this post is about.

I will describe the example of VMWare Workstation as it is easy to test with, but it applies to VM server/cluster technologies as well.

VMWare Workstation is one of the most popular VM products on the market. Among many rich features that it offers, it is also including a well-documented mechanism that leverages a number of batch files that are executed when the power state of the guest OS changes – these states are:

  • Power On
  • Power Off
  • Suspend
  • Resume

Anyone who does reverse engineering for living uses these features all the time. VMs are an excellent solution to ‘freeze’ the session, test some code path, and revert to the previous snapshot if the code ‘escapes’ or program exits/crashes. It speeds up the analysis a lot and allows us to work in a comfort zone no other reversing tools can typically provide.

The VMware Workstation stores its batch files inside the c:\Program Files\VMware\VMware Tools\ directory – exploring this location we can quickly find a number of interesting files:

  • c:\Program Files\VMware\VMware Tools\poweroff-vm-default.bat
  • c:\Program Files\VMware\VMware Tools\poweron-vm-default.bat
  • c:\Program Files\VMware\VMware Tools\resume-vm-default.bat
  • c:\Program Files\VMware\VMware Tools\suspend-vm-default.bat

The top of the files typically states that:

@REM ########################################################################
@REM # DO NOT modify this file directly as it will be overwritten the next
@REM # time the VMware Tools are installed. 
@REM ########################################################################

but of course, we are not going to listen.

Modification of these files can provides a decent persistence mechanism. Obviously, re-installing the VMTools and/or reverting to a previous snapshots can mitigate it, but if the VDI host is indeed running for a long time, this could be a possible good place to run something malicious from. In the VDI farm/cluster scenario, anyone who cans modify the source code of a vmware tools baseline could establish such persistent mechanism on (and infect) the whole cluster (deployment to all nodes).

Interestingly, these batch files can serve another purpose: they can cause some DoS annoyance (for a lack of a better name as it’s hardly an anti-vm trick). Adding a simple ‘pause’ command to any of these files will ‘prevent’ the VMWare from executing the state-changing operation as it will wait for the cmd.exe process that handles the ‘pause’ command to exit:

Since ‘pause’ requires pressing the key and the script is running in a different session the vmtoold.exe will just enter a sort of never-ending loop. The side-effect of it is that the user won’t be able to f.ex. ‘suspend’ or ‘power off’ the guest system.

Beyond good ol’ Run key, Part 52

When you google for “PSScripts.ini” you will find only around 200 results or so. This is a bit surprising, given the fact Microsoft documents this Powershell-based persistence mechanism on their web page for quite some time and even describes in detail the syntax of the PSScripts.ini file. Let alone the fact the mechanism – a close cousin of scripts.ini which I described in the past – is available on Windows 7 and Windows 2008 Server R2 for many years…

To access the configuration of the PSScripts.ini we can launch gpedit.msc and find the familiar settings:

Clicking ‘Startup’ or ‘Shutdown’ properties will open a new dialog box where we can see two tabs: one for scripts.ini (Windows Startup Scripts) and the second one for PSScripts.ini (PowerShell Startup Scripts):

The information provided at the bottom of the dialog confirms that ‘PowerShell scripts require at least Windows 7 or Windows Server 2008 R2’ – not a big problem nowadays.

If we now add our own test script called malware.ps1:

we will notice that a number of artifacts have been added to the system:

  • c:\Windows\System32\GroupPolicy\Machine\Scripts\psscripts.ini
[Startup]
0CmdLine=malware.ps1
0Parameters=
  • c:\Windows\System32\GroupPolicy\Machine\Scripts\Startup\malware.ps1 (this is the test script; it just waits for a key to be pressed)
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown');
  • HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\
    Group Policy\State\Machine\Scripts\Startup\0\0
"Script"="malware.ps1"
"Parameters"=""
"ExecTime"=hex(b):00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
  • HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\
    Group Policy\Scripts\Startup\0\0
"Script"="malware.ps1"
"Parameters"=""
"IsPowershell"=dword:00000001
"ExecTime"=hex(b):00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
  • HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy\
    History\{42B5FAAE-6536-11d2-AE5A-0000F87571E3}\0
"Options"=dword:00000000
"Version"=dword:00010001
"DSPath"="LocalGPO"
"FileSysPath"="C:\\Windows\\System32\\GroupPolicy\\Machine"
"DisplayName"="Local Group Policy"
"Extensions"="[{42B5FAAE-6536-11D2-AE5A-0000F87571E3}{40B6664F-4972-11D1-A7CA-0000F87571E3}]"
"Link"="Local"
"GPOName"="Local Group Policy"
"GPOLink"=dword:00000001
"lParam"=dword:00000000

The ’42B5FAAE-6536-11d2-AE5A-0000F87571E3′ GUID is associated with a component named ‘ProcessScriptsGroupPolicy’.

After restarting the system we can immediately see that the script was launched:

We can confirm it’s indeed our script by inspecting the properties of powershell.exe process pointing to our test script (since it waits for the key to be pressed it just runs idle in a background):

The good news is that Autoruns already detects these entries:

We are now half way through, so bear with me :).

There can be 2 PSScripts.ini on the system – the second configured for (all) the users. If you go back to to the gpedit.msc dialog box, you can browse the user configuration as well:

The 2 events that Powershell scripts can be associated with are ‘Logon’ and ‘Logoff’. When we now add a similar test script we will achieve persistence that will be attached to one or both of these events.

I don’t describe it here, but it’s possible to decide in what sequence the script.ini and PSscript.ini should be processed.

Back to our User-specific scripts. The artifacts can be found in the Registry under the following keys:

  • HKCU\Software\Microsoft\Windows\CurrentVersion\Group Policy\Scripts
  • HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy\
    State\[SID]\Scripts

and the files are in a pretty much same place as the system-specific scripts:

  • c:\Windows\System32\GroupPolicy

The file system tree where the scripts are located looks like this:

├───Machine
│   └───Scripts
│       ├───Shutdown
│       └───Startup
└───User
    └───Scripts
        ├───Logoff
        └───Logon

Last, but not least – the latest Autoruns doesn’t seem to be detecting the user-specific scripts.