telephony-tapsrv-arbitrary-dword-write-to-rce.md (5658B)
1 --- 2 title: "Telephony tapsrv Arbitrary DWORD Write to RCE (TAPI Server Mode)" 3 section: "Windows" 4 sectionSlug: "windows-hardening" 5 sourcePath: "src/windows-hardening/windows-local-privilege-escalation/telephony-tapsrv-arbitrary-dword-write-to-rce.md" 6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/windows-hardening/windows-local-privilege-escalation/telephony-tapsrv-arbitrary-dword-write-to-rce.md" 7 sha: "188de82beb54e70956b2952367a0af91d26758b8" 8 isIndex: false 9 modified: true 10 license: "CC-BY-NC-4.0" 11 --- 12 13 # Telephony tapsrv Arbitrary DWORD Write to RCE (TAPI Server Mode) 14 15 When the Windows Telephony service (TapiSrv, `tapisrv.dll`) is configured as a **TAPI server**, it exposes the **`tapsrv` MSRPC interface over the `\pipe\tapsrv` named pipe** to authenticated SMB clients. CVE-2026-20931 in asynchronous event delivery lets an attacker turn a purported mailslot handle into a **controlled 4-byte write to a pre-existing file writable by `NETWORK SERVICE`**. The published chain overwrites the Telephony administrator list, then reaches an administrator-only DLL load and executes as `NETWORK SERVICE`.<sup>[[1]](#references)[[2]](#references)</sup> 16 17 ## Attack Surface 18 19 - **Remote exposure only when enabled**: `HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Telephony\Server\DisableSharing` must allow sharing (or configured via `TapiMgmt.msc` / `tcmsetup /c <server>`). By default `tapsrv` is local-only. 20 - Interface: MS-TRP (`tapsrv`) over **SMB named pipe**, so the attacker needs valid SMB auth. 21 - Service account: `NETWORK SERVICE` (manual start, on-demand).<sup>[[1]](#references)</sup> 22 23 ## Primitive: Mailslot Path Confusion → Arbitrary DWORD Write 24 - `ClientAttach(pszDomainUser, pszMachine, ...)` initializes async event delivery. In pull mode, the service does: 25 ```c 26 CreateFileW(pszDomainUser, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 27 ``` 28 without validating that `pszDomainUser` is a mailslot path (`\\*\MAILSLOT\...`). Any **existing filesystem path** writable by `NETWORK SERVICE` is accepted. 29 - Every async event write stores a single **`DWORD` = `InitContext`** (attacker-controlled in the subsequent `Initialize` request) to the opened handle, yielding **write-what/write-where (4 bytes)**.<sup>[[1]](#references)</sup> 30 31 ## Forcing Deterministic Writes 32 1. **Open target file**: `ClientAttach` with `pszDomainUser = <existing writable path>` (e.g., `C:\Windows\TAPI\tsec.ini`). 33 2. For each `DWORD` to write, execute this RPC sequence against `ClientRequest`: 34 - `Initialize` (`Req_Func 47`): set `InitContext = <4-byte value>` and `pszModuleName = DIALER.EXE` (or another top entry in the per-user priority list). 35 - `LRegisterRequestRecipient` (`Req_Func 61`): `dwRequestMode = LINEREQUESTMODE_MAKECALL`, `bEnable = 1` (registers the line app, recalculates highest priority recipient). 36 - `TRequestMakeCall` (`Req_Func 121`): forces `NotifyHighestPriorityRequestRecipient`, generating the async event. 37 - `GetAsyncEvents` (`Req_Func 0`): dequeue/completes the write. 38 - `LRegisterRequestRecipient` again with `bEnable = 0` (unregister). 39 - `Shutdown` (`Req_Func 86`) to tear down the line app. 40 - Priority control: the “highest priority” recipient is chosen by comparing `pszModuleName` against `HKCU\Software\Microsoft\Windows\CurrentVersion\Telephony\HandoffPriorities\RequestMakeCall` (read while impersonating the client). If needed, insert your module name via `LSetAppPriority` (`Req_Func 69`). 41 - The file **must already exist** because `OPEN_EXISTING` is used. Common `NETWORK SERVICE`-writable candidates: `C:\Windows\System32\catroot2\dberr.txt`, `C:\Windows\ServiceProfiles\NetworkService\AppData\Local\Temp\MpCmdRun.log`, `...\MpSigStub.log`.<sup>[[1]](#references)</sup> 42 43 ## From DWORD Write to RCE inside TapiSrv 44 1. **Grant yourself Telephony “admin”**: target `C:\Windows\TAPI\tsec.ini` and append `[TapiAdministrators]\r\n<DOMAIN\\user>=1` using the 4-byte writes above. Start a **new** session (`ClientAttach`) so the service re-reads the INI and sets `ptClient->dwFlags |= 9` for your account. 45 2. **Admin-only DLL load**: send `GetUIDllName` with `dwObjectType = TUISPIDLL_OBJECT_PROVIDERID` and supply a path via `dwProviderFilenameOffset`. For admins, the service does `LoadLibrary(path)` then calls the export `TSPI_providerUIIdentify`: 46 - Works with UNC paths to a real Windows SMB share; some attacker SMB servers fail with `ERROR_SMB_GUEST_LOGON_BLOCKED`. 47 - Alternative: slowly drop a local DLL using the same 4-byte write primitive, then load it. 48 3. **Payload**: the export executes under `NETWORK SERVICE`. A minimal DLL can run `cmd.exe /c whoami /all > C:\Windows\Temp\poc.txt` and return a non-zero value (e.g., `0x1337`) so the service unloads the DLL, confirming execution.<sup>[[1]](#references)</sup> 49 50 ## Hardening / Detection Notes 51 - Install the Microsoft security update for CVE-2026-20931. Independently disable TAPI server mode unless required and block remote access to `\pipe\tapsrv`. 52 - Enforce mailslot namespace validation (`\\*\MAILSLOT\`) before opening client-supplied paths. 53 - Lock down `C:\Windows\TAPI\tsec.ini` ACLs and monitor changes; alert on `GetUIDllName` calls loading non-default paths.<sup>[[1]](#references)</sup> 54 55 ## References 56 57 - [1] [Who’s on the line? Exploiting RCE in Windows Telephony Service (CVE-2026-20931)](https://swarm.ptsecurity.com/whos-on-the-line-exploiting-rce-in-windows-telephony-service/) 58 - [2] [Microsoft Security Response Center — CVE-2026-20931](https://msrc.microsoft.com/update-guide/vulnerability/CVE-2026-20931)