ALPC Task Scheduler SchRpcSetSecurity LPE (CVE-2018-8440)¶
Task Scheduler'ın ALPC interface'i
SchRpcSetSecuritymetodunu export eder; bu metot, attacker'ın verdiği bir DACL'iC:\Windows\Tasksaltındaki bir path'e caller'ı impersonate etmeden yazar. Bir hardlink ile birleştiğinde, yetkisiz bir kullanıcı sistemdeki herhangi bir dosyanın ACL'ini yeniden yazar ve SYSTEM'a yükselir (privilege escalation).
Mechanism¶
Eksik bir impersonation, bir DACL setter'ı neden SYSTEM primitive'ine çevirir
Windows Task Scheduler servisi SYSTEM olarak çalışır ve bir
ALPC (Advanced Local Procedure Call) RPC endpoint'i sunar. Metotlarından
biri olan SchRpcSetSecurity, zamanlanmış bir task'ın security descriptor'ını
(DACL) set etmek içindir. Implementation'da birbirini besleyen iki kusur var:
-
Target üzerinde permission check yok.
SchRpcSetSecurity, caller'ın verdiği DACL'iC:\Windows\Tasksaltındaki bir dosyaya, caller'ın o object'in güvenliğini değiştirmeye yetkili olup olmadığını önce doğrulamadan uygular. -
Impersonation yok. Diskteki dosyaya dokunurken servis, (yetkisiz) RPC caller'ı impersonate etmez — kendi SYSTEM token'ı ile çalışır. Dolayısıyla kernel,
SetSecurityişlemini SYSTEM authority ile gerçekleştirir.
Yetkili bir servisin koruması gereken invariant şu: bir client adına bir
resource üzerinde işlem yaparken o client'ı impersonate et ki kernel'in
access check'i servisin değil client'ın token'ını kullansın. Task Scheduler
bunu burada bozuyor. Herhangi bir kullanıcı C:\Windows\Tasks içinde dosya
oluşturabildiğinden, attacker oraya bir dosya yerleştirir ve onu, başka türlü
korunan keyfi bir target'a (SYSTEM/TrustedInstaller'a ait bir DLL veya
executable) işaret eden bir hardlink'e çevirir. SchRpcSetSecurity'den
yerleştirilen ad üzerinde DACL set etmesi istendiğinde, SYSTEM servisi
hardlink'i takip eder ve attacker'ın seçtiği DACL'i (örneğin Everyone: Full
Control) gerçek target'a damgalar.
Attacker, bir SYSTEM process'inin daha sonra okuyup execute edeceği bir
dosyanın DACL'ini kontrol ettiği an, escalation mekanik hale gelir: o dosyayı
kötü niyetli bir payload ile overwrite et ve SYSTEM process'ini onu load
etmeye tetikle. Public PoC, bu yeni write erişimini Print Spooler path'ine
zincirledi — SYSTEM seviyesindeki spooler'ın load ettiği bir printer driver
DLL'i (örneğin printer başına UpdateTask/PrintConfig component'i) — böylece
bir printer eklemek attacker kodunu SYSTEM olarak çalıştırdı. Bug, SandboxEscaper
tarafından 27 Aug 2018'de bir 0day olarak yayımlandı, günler içinde PowerPool
malware ekibi tarafından silahlandırıldı ve 11 Sep 2018'de patch'lendi.
Bu, UNIX'teki "privileged daemon bir attacker symlink'i üzerinden yazar" (link-following / TOCTOU sınıfı) bug'ının Windows karşılığıdır: corruption primitive'i file ACL rewrite, kaldıraç ise impersonation yok + servisin güvendiği bir directory'ye kullanıcı write erişimi.
Walkthrough¶
Step 1 — Task Scheduler ALPC endpoint'ine bind ol ve vulnerable metodu çağır.
Public PoC, local RPC interface'i reverse-engineer etti ve SchRpcSetSecurity'yi
doğrudan çağırdı:
// SchRpcSetSecurity(path, sddl, flags) over the schedule-service ALPC port.
// 'path' is interpreted relative to the Tasks store; 'sddl' is the new DACL.
hr = SchRpcSetSecurity(
L"..\\..\\..\\..\\<relative path into C:\\Windows\\Tasks\\hardlink>",
L"D:(A;;FA;;;WD)", // Everyone (WD) : Full Access (FA)
0);
Step 2 — hardlink'i yerleştir. Attacker (yetkisiz) C:\Windows\Tasks içinde
dosya oluşturabildiğinden, orada ACL'ini ele geçirmek istediğin gerçek,
SYSTEM'a ait target'a resolve olan bir hardlink oluştur:
Step 3 — fire the call. Because the service does not impersonate and does not check permission, it rewrites the DACL of the hardlink's target:
Before: <targetDLL>.dll owner=TrustedInstaller, write denied to users
After: <targetDLL>.dll DACL = Everyone:Full (attacker now owns the ACL)
Expected observable: icacls C:\Windows\System32\<targetDLL>.dll now shows
Everyone:(F).
Step 4 — convert ACL control into SYSTEM code execution. Overwrite the now attacker-writable DLL with a payload, then induce a SYSTEM process to load it. The reference chain abused the print subsystem so that adding/refreshing a printer caused the SYSTEM spooler to load the replaced driver DLL:
copy payload.dll C:\Windows\System32\<targetDLL>.dll (overwrite)
Add-Printer / spooler refresh -> spoolsv.exe (SYSTEM) loads <targetDLL>.dll
-> payload runs as NT AUTHORITY\SYSTEM
Step 5 — verify. The payload (e.g. a cmd.exe spawn) runs in session 0 as
SYSTEM:
Why the relative-path + hardlink combination is the whole trick
SchRpcSetSecurity was only ever supposed to touch a task's descriptor
inside the scheduler's store. The PoC passes a path that escapes that store
only as far as a file the user can already create (C:\Windows\Tasks),
then relies on NTFS hardlinks to make that user-creatable name alias a
file the user cannot normally modify. The privileged service does the
forbidden write on the user's behalf because it never re-checks who is
asking. Microsoft's fix added the missing access/impersonation checks so the
DACL set is evaluated against the caller's token.
Detection¶
- File-integrity / EDR: DACL changes (
SetSecurity) on System32 DLLs, or new hardlinks created inC:\Windows\Taskspointing outside the Tasks store, by a non-system process. - Spooler anomaly:
spoolsv.exeloading a freshly-modified driver DLL, or printer-add operations immediately following ACL changes. - PowerPool IOCs: the in-the-wild campaign that weaponized this is documented by AV vendors; the dropped second stage modified Task Scheduler artifacts.
Mitigation¶
- Apply the September 2018 cumulative update (fixes CVE-2018-8440) — it adds the
missing permission/impersonation checks in
SchRpcSetSecurity. - Restrict / monitor write access to
C:\Windows\Tasksand watch for hardlink creation there (link-following hardening). - General defense for "no-impersonation" service bugs: privileged services must impersonate the client before touching client-named filesystem objects.