[PATCH v1] tapctl: prevent binary planting with netsh
Gert Doering <[email protected]>
| Newsgroups | gmane.network.openvpn.devel |
|---|---|
| Message-ID | <[email protected]> |
From: Heiko Hund <[email protected]> Provide a application name to CreateProcess(), so that it doesn't try to locate an executable - somewhere. Instead construct the full path to netsh.exe in the system dir and pass that to the function instead of NULL. Discovered and reported by BreachX Zero Day Labs, using Typhon AI Mil v2. Contributing Researcher: Vivek Parikh. Reported-by: Vivek Parikh <[email protected]> Tested-by: Vivek Parikh <[email protected]> Github: OpenVPN/openvpn-private-issues#164 CVE: 2026-84226 Change-Id: I70282985a7e8e46add92b2277674cbca6bce39c1 Signed-off-by: Heiko Hund <[email protected]> Acked-by: Razvan Cojocaru <[email protected]> Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1890 --- This change was reviewed on Gerrit and approved by at least one developer. I request to merge it to master. Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1890 This mail reflects revision 1 of this Change. Acked-by according to Gerrit (reflected above): Razvan Cojocaru <[email protected]> diff --git a/src/tapctl/tap.c b/src/tapctl/tap.c index 1d94988..769df6c 100644 --- a/src/tapctl/tap.c +++ b/src/tapctl/tap.c @@ -921,32 +921,38 @@ bEnable ? enable_device : disable_device, pbRebootRequired); } -/* stripped version of ExecCommand in interactive.c */ static DWORD -ExecCommand(const WCHAR *cmdline) +ExecNetsh(PWSTR cmdline) { DWORD exit_code; STARTUPINFOW si; PROCESS_INFORMATION pi; DWORD proc_flags = CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT; - WCHAR *cmdline_dup = NULL; ZeroMemory(&si, sizeof(si)); ZeroMemory(&pi, sizeof(pi)); - si.cb = sizeof(si); - /* CreateProcess needs a modifiable cmdline: make a copy */ - cmdline_dup = _wcsdup(cmdline); - if (cmdline_dup - && CreateProcessW(NULL, cmdline_dup, NULL, NULL, FALSE, proc_flags, NULL, NULL, &si, &pi)) + WCHAR appName[MAX_PATH]; + WCHAR netsh_exe[] = L"\\netsh.exe"; + UINT sysdir_len = GetSystemDirectoryW(appName, _countof(appName)); + if (sysdir_len == 0) + { + wcscpy_s(appName, _countof(appName), L"C:\\Windows\\system32"); + } + else if (sysdir_len + _countof(netsh_exe) > _countof(appName)) + { + return ERROR_INSUFFICIENT_BUFFER; + } + wcscat_s(appName, _countof(appName), netsh_exe); + + if (CreateProcessW(appName, cmdline, NULL, NULL, FALSE, proc_flags, NULL, NULL, &si, &pi)) { WaitForSingleObject(pi.hProcess, INFINITE); if (!GetExitCodeProcess(pi.hProcess, &exit_code)) { exit_code = GetLastError(); } - CloseHandle(pi.hProcess); CloseHandle(pi.hThread); } @@ -955,7 +961,6 @@ exit_code = GetLastError(); } - free(cmdline_dup); return exit_code; } @@ -1013,7 +1018,7 @@ free(szOldName); - dwResult = ExecCommand(szCmdLine); + dwResult = ExecNetsh(szCmdLine); free(szCmdLine); if (dwResult != ERROR_SUCCESS)