[Openvpn-devel,v1] tapctl: prevent binary planting with netsh
Commit Message
From: Heiko Hund <heiko@ist.eigentlich.net>
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 <vivek.parikh@breachx.ai>
Tested-by: Vivek Parikh <vivek.parikh@breachx.ai>
Github: OpenVPN/openvpn-private-issues#164
CVE: 2026-84226
Change-Id: I70282985a7e8e46add92b2277674cbca6bce39c1
Signed-off-by: Heiko Hund <heiko@ist.eigentlich.net>
Acked-by: Razvan Cojocaru <razvanc@mailbox.org>
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 <razvanc@mailbox.org>
Comments
Change looks reasonable, detailed review from Razvan both in "private GH"
and +2 on Gerrit (thanks). Compile- and unit-tested via GHA.
Your patch has been applied to the master, release/2.7 and release/2.6
branch. 2.6 needed a bit of massaging due to different wrapping in
the old CreateProcessW() call - but uncrustify is also fine with the
new wrapping, so the new code is 1:1 the same in 2.6 and onwards.
commit 03f8b88898b06d0d0acb3bded18eba82fa2e6277 (master)
commit 19b1b9f82d93b481b4a9a6c2a22782ee7a630186 (release/2.7)
commit d836a52b7f8117558d36b6f7133f2812b838a475 (release/2.6)
Author: Heiko Hund
Date: Wed Sep 2 11:57:29 2026 +0200
tapctl: prevent binary planting with netsh
Signed-off-by: Heiko Hund <heiko@ist.eigentlich.net>
Acked-by: Razvan Cojocaru <razvanc@mailbox.org>
Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1890
Message-Id: <20260902095734.26857-1-gert@greenie.muc.de>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg38894.html
Signed-off-by: Gert Doering <gert@greenie.muc.de>
--
kind regards,
Gert Doering
@@ -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)