Manual and Automated Process to resolve Unquote Service Path issues
The Risk
The remote Windows host contains services installed that use unquoted service paths, which contains at least one whitespace. A local attacker can gain elevated privileges by inserting an executable file in the path of the affected service.
The Fix
- Open the registry editor in Administrator Mode
- Goto HKLM\System\CurrentControlSet\Services
- Locate the service which has been highlighted as the issue
e.g.
- OpenVPNConnectorService
Value name: ImagePath
Value data: C:\Program Files\OpenVPN Connect\ovpnconnector.exe run
- OpenVPNConnectorService
- Enclose the path in quote marks
e.g.
- OpenVPNConnectorService
Value name: ImagePath
Value data: "C:\Program Files\OpenVPN Connect\ovpnconnector.exe" run
- OpenVPNConnectorService
Also
You can search for any "Unquoted Path" issues using the following command
wmic service get name,displayname,pathname,startmode |findstr /i “auto” |findstr /i /v “c:\windows\\” |findstr /i /v “””
You can also run a script to change any identified paths, either as a one-off or as a repeating task inside an RMM tool or similar
#Check we are running in admin mode
function Test-Administrator
{
$user = [Security.Principal.WindowsIdentity]::GetCurrent();
(New-Object Security.Principal.WindowsPrincipal $user).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)
}
cls
If(Test-Administrator)
{
Write-Host "Running in Admin Mode" -ForegroundColor Yellow
Write-Host "Checking for Unquoted Service Paths" -ForegroundColor Cyan
}
else
{
Write-Host "Not Running in Admin Mode - Please execute in Admin Mode"
Exit
}
#Collect a list of IndividualServices running on the machine being checked
$InstalledServices = Get-ChildItem "HKLM:\SYSTEM\CurrentControlSet\Services"
#Check each and every service
foreach($IndividualService in $InstalledServices)
{
$ImagePathExists = $false
foreach($Property in $IndividualService.Property)
{
#Does the service have an image path?
if($Property -eq "ImagePath")
{
$ImagePathExists = $true
break;
}
}
#If we cannot find an Image Path on the service we can move on and ignore
if(-not($ImagePathExists))
{
continue
}
#Copy the image path variable so we can work with it in the scipt
$ImagePathCopy = [string]$IndividualService.GetValue("ImagePath")
# If the ImagePathCopy has no spaces we can ignore it
if(-not ($ImagePathCopy.Contains(" ")))
{ continue }
#Variables for executable and parameters
$executables = ""
$parameters = ""
#Is this a driver with .SYS extension
if($ImagePathCopy.Contains('.sys'))
{
# Split executable path and arguments for drivers
if($ImagePathCopy.Contains('.sys"'))
{
$splitPoint = $ImagePathCopy.IndexOf(".sys")+5
$executables = $ImagePathCopy.Substring(0,$splitPoint)
$arguments = ($ImagePathCopy.Substring($splitPoint-1))
} else
{
$splitPoint = $ImagePathCopy.IndexOf(".sys")+4
$executables = $ImagePathCopy.Substring(0,$splitPoint)
$arguments = ($ImagePathCopy.Substring($splitPoint))
}
#Is this an executable file with a .exe extension
} elseif($ImagePathCopy.Contains('.exe'))
{
# Split executable path and arguments for drivers
if($ImagePathCopy.Contains('.exe"'))
{
$splitPoint = $ImagePathCopy.IndexOf(".exe")+5
$executables = $ImagePathCopy.Substring(0,$splitPoint)
$arguments = ($ImagePathCopy.Substring($splitPoint-1))
} else
{
$splitPoint = $ImagePathCopy.IndexOf(".exe")+4
$executables = $ImagePathCopy.Substring(0,$splitPoint)
$arguments = ($ImagePathCopy.Substring($splitPoint))
}
}
#Check for spaces in the executable path
If($executables.Contains(' '))
{
#Are there spaced and no quotes
if(-not(($executables.StartsWith('"') -and $executables.EndsWith('"'))))
{
# Add quotes
"$($Individualservice.name) was identified with an unquoted path ($imagePathCopy)"
$executables = "`"$executables`""
$NewImagePath = "$executables$arguments"
# Change registry path to add the quotes
$IndividualServicePath = $IndividualService.Name.Replace("HKEY_LOCAL_MACHINE","HKLM:")
# Update the ImagePath
"changing to $NewImagePath"
Set-ItemProperty -Path $IndividualServicePath -Name "ImagePath" -Value $newImagePath
}
}
}
Write-Host "Completed Unquoted Service Path Checking" -ForegroundColor Green