netcat-win86

Netcat prebuilt executable for Windows machines
git clone https://s.sonu.ch/~srket/netcat-win86.git
Log | Files | Refs | LICENSE

doexec.c (12081B)


      1 // for license see license.txt
      2 
      3 // Modified 12/27/2004 by Chris Wysopal <weld@vulnwatch.com> 
      4 // fixed vulnerability found by hat-squad
      5 
      6 // portions Copyright (C) 1994 Nathaniel W. Mishkin
      7 // code taken from rlogind.exe
      8  
      9 #include <stdlib.h>
     10 #include <winsock2.h>
     11 #include <winbase.h>
     12 
     13 #ifdef GAPING_SECURITY_HOLE
     14 
     15 
     16 #define BUFFER_SIZE 200
     17 
     18 extern char * pr00gie;
     19 void holler(char * str, char * p1, char * p2, char * p3, char * p4, char * p5, char * p6);
     20 char smbuff[20];
     21 //
     22 // Structure used to describe each session
     23 //
     24 typedef struct {
     25 
     26     //
     27     // These fields are filled in at session creation time
     28     //
     29     HANDLE  ReadPipeHandle;         // Handle to shell stdout pipe
     30     HANDLE  WritePipeHandle;        // Handle to shell stdin pipe
     31     HANDLE  ProcessHandle;          // Handle to shell process
     32 
     33     //
     34     //
     35     // These fields are filled in at session connect time and are only
     36     // valid when the session is connected
     37     //
     38     SOCKET  ClientSocket;
     39     HANDLE  ReadShellThreadHandle;  // Handle to session shell-read thread
     40     HANDLE  WriteShellThreadHandle; // Handle to session shell-read thread
     41 
     42 } SESSION_DATA, *PSESSION_DATA;
     43 
     44 
     45 //
     46 // Private prototypes
     47 //
     48 
     49 static HANDLE
     50 StartShell(
     51     HANDLE StdinPipeHandle,
     52     HANDLE StdoutPipeHandle
     53     );
     54 
     55 static VOID
     56 SessionReadShellThreadFn(
     57     LPVOID Parameter
     58     );
     59 
     60 static VOID
     61 SessionWriteShellThreadFn(
     62     LPVOID Parameter
     63     );
     64 
     65 
     66 
     67 // **********************************************************************
     68 //
     69 // CreateSession
     70 //
     71 // Creates a new session. Involves creating the shell process and establishing
     72 // pipes for communication with it.
     73 //
     74 // Returns a handle to the session or NULL on failure.
     75 //
     76 
     77 static PSESSION_DATA
     78 CreateSession(
     79     VOID
     80     )
     81 {
     82     PSESSION_DATA Session = NULL;
     83     BOOL Result;
     84     SECURITY_ATTRIBUTES SecurityAttributes;
     85     HANDLE ShellStdinPipe = NULL;
     86     HANDLE ShellStdoutPipe = NULL;
     87 
     88     //
     89     // Allocate space for the session data
     90     //
     91     Session = (PSESSION_DATA) malloc(sizeof(SESSION_DATA));
     92     if (Session == NULL) {
     93         return(NULL);
     94     }
     95 
     96     //
     97     // Reset fields in preparation for failure
     98     //
     99     Session->ReadPipeHandle  = NULL;
    100     Session->WritePipeHandle = NULL;
    101 
    102 
    103     //
    104     // Create the I/O pipes for the shell
    105     //
    106     SecurityAttributes.nLength = sizeof(SecurityAttributes);
    107     SecurityAttributes.lpSecurityDescriptor = NULL; // Use default ACL
    108     SecurityAttributes.bInheritHandle = TRUE; // Shell will inherit handles
    109 
    110     Result = CreatePipe(&Session->ReadPipeHandle, &ShellStdoutPipe,
    111                           &SecurityAttributes, 0);
    112     if (!Result) {
    113         holler("Failed to create shell stdout pipe, error = %s",
    114 			itoa(GetLastError(), smbuff, 10), NULL, NULL, NULL, NULL, NULL);
    115         goto Failure;
    116     }
    117     Result = CreatePipe(&ShellStdinPipe, &Session->WritePipeHandle,
    118                         &SecurityAttributes, 0);
    119 
    120     if (!Result) {
    121         holler("Failed to create shell stdin pipe, error = %s",  
    122 			itoa(GetLastError(), smbuff, 10), NULL, NULL, NULL, NULL, NULL);
    123         goto Failure;
    124     }
    125     //
    126     // Start the shell
    127     //
    128     Session->ProcessHandle = StartShell(ShellStdinPipe, ShellStdoutPipe);
    129 
    130     //
    131     // We're finished with our copy of the shell pipe handles
    132     // Closing the runtime handles will close the pipe handles for us.
    133     //
    134     CloseHandle(ShellStdinPipe);
    135     CloseHandle(ShellStdoutPipe);
    136 
    137     //
    138     // Check result of shell start
    139     //
    140     if (Session->ProcessHandle == NULL) {
    141         holler("Failed to execute shell", NULL,
    142 			 NULL, NULL, NULL, NULL, NULL);
    143 			
    144         goto Failure;
    145     }
    146 
    147     //
    148     // The session is not connected, initialize variables to indicate that
    149     //
    150     Session->ClientSocket = INVALID_SOCKET;
    151 
    152     //
    153     // Success, return the session pointer as a handle
    154     //
    155     return(Session);
    156 
    157 Failure:
    158 
    159     //
    160     // We get here for any failure case.
    161     // Free up any resources and exit
    162     //
    163 
    164     if (ShellStdinPipe != NULL) 
    165         CloseHandle(ShellStdinPipe);
    166     if (ShellStdoutPipe != NULL) 
    167         CloseHandle(ShellStdoutPipe);
    168     if (Session->ReadPipeHandle != NULL) 
    169         CloseHandle(Session->ReadPipeHandle);
    170     if (Session->WritePipeHandle != NULL) 
    171         CloseHandle(Session->WritePipeHandle);
    172 
    173     free(Session);
    174 
    175     return(NULL);
    176 }
    177 
    178 
    179 
    180 BOOL
    181 doexec(
    182     SOCKET  ClientSocket
    183     )
    184 {
    185     PSESSION_DATA   Session = CreateSession();
    186     SECURITY_ATTRIBUTES SecurityAttributes;
    187     DWORD ThreadId;
    188     HANDLE HandleArray[3];
    189 	int i;
    190 
    191     SecurityAttributes.nLength = sizeof(SecurityAttributes);
    192     SecurityAttributes.lpSecurityDescriptor = NULL; // Use default ACL
    193     SecurityAttributes.bInheritHandle = FALSE; // No inheritance
    194 
    195     //
    196     // Store the client socket handle in the session structure so the thread
    197     // can get at it. This also signals that the session is connected.
    198     //
    199     Session->ClientSocket = ClientSocket;
    200 
    201     //
    202     // Create the session threads
    203     //
    204     Session->ReadShellThreadHandle = 
    205         CreateThread(&SecurityAttributes, 0,
    206                      (LPTHREAD_START_ROUTINE) SessionReadShellThreadFn, 
    207                      (LPVOID) Session, 0, &ThreadId);
    208 
    209     if (Session->ReadShellThreadHandle == NULL) {
    210         holler("Failed to create ReadShell session thread, error = %s", 
    211 			itoa(GetLastError(), smbuff, 10), NULL, NULL, NULL, NULL, NULL);
    212 
    213         //
    214         // Reset the client pipe handle to indicate this session is disconnected
    215         //
    216         Session->ClientSocket = INVALID_SOCKET;
    217         return(FALSE);
    218     }
    219 
    220     Session->WriteShellThreadHandle = 
    221         CreateThread(&SecurityAttributes, 0, 
    222                      (LPTHREAD_START_ROUTINE) SessionWriteShellThreadFn, 
    223                      (LPVOID) Session, 0, &ThreadId);
    224 
    225     if (Session->WriteShellThreadHandle == NULL) {
    226         holler("Failed to create ReadShell session thread, error = %s", 
    227 			itoa(GetLastError(), smbuff, 10), NULL, NULL, NULL, NULL, NULL);
    228 
    229         //
    230         // Reset the client pipe handle to indicate this session is disconnected
    231         //
    232         Session->ClientSocket = INVALID_SOCKET;
    233 
    234         TerminateThread(Session->WriteShellThreadHandle, 0);
    235         return(FALSE);
    236     }
    237 
    238     //
    239     // Wait for either thread or the shell process to finish
    240     //
    241 
    242     HandleArray[0] = Session->ReadShellThreadHandle;
    243     HandleArray[1] = Session->WriteShellThreadHandle;
    244     HandleArray[2] = Session->ProcessHandle;
    245 
    246 	
    247     i = WaitForMultipleObjects(3, HandleArray, FALSE, 0xffffffff);
    248     
    249 	
    250 	switch (i) {
    251       case WAIT_OBJECT_0 + 0:
    252         TerminateThread(Session->WriteShellThreadHandle, 0);
    253         TerminateProcess(Session->ProcessHandle, 1);
    254         break;
    255 
    256       case WAIT_OBJECT_0 + 1:
    257         TerminateThread(Session->ReadShellThreadHandle, 0);
    258         TerminateProcess(Session->ProcessHandle, 1);
    259         break;
    260       case WAIT_OBJECT_0 + 2:
    261         TerminateThread(Session->WriteShellThreadHandle, 0);
    262         TerminateThread(Session->ReadShellThreadHandle, 0);
    263         break;
    264  
    265 	  default:
    266         holler("WaitForMultipleObjects error: %s", 
    267 			itoa(GetLastError(), smbuff, 10), NULL, NULL, NULL, NULL, NULL);
    268 
    269         break;
    270     }
    271 
    272 
    273     // Close my handles to the threads, the shell process, and the shell pipes
    274 	shutdown(Session->ClientSocket, SD_BOTH);
    275   	closesocket(Session->ClientSocket);
    276 	
    277 	DisconnectNamedPipe(Session->ReadPipeHandle);
    278     CloseHandle(Session->ReadPipeHandle);
    279 
    280 	DisconnectNamedPipe(Session->WritePipeHandle);
    281     CloseHandle(Session->WritePipeHandle);
    282 
    283 
    284     CloseHandle(Session->ReadShellThreadHandle);
    285     CloseHandle(Session->WriteShellThreadHandle);
    286 
    287     CloseHandle(Session->ProcessHandle);
    288  
    289     free(Session);
    290 
    291     return(TRUE);
    292 }
    293 
    294 
    295 // **********************************************************************
    296 //
    297 // StartShell
    298 //
    299 // Execs the shell with the specified handle as stdin, stdout/err
    300 //
    301 // Returns process handle or NULL on failure
    302 //
    303 
    304 static HANDLE
    305 StartShell(
    306     HANDLE ShellStdinPipeHandle,
    307     HANDLE ShellStdoutPipeHandle
    308     )
    309 {
    310     PROCESS_INFORMATION ProcessInformation;
    311     STARTUPINFO si;
    312     HANDLE ProcessHandle = NULL;
    313 
    314     //
    315     // Initialize process startup info
    316     //
    317     si.cb = sizeof(STARTUPINFO);
    318     si.lpReserved = NULL;
    319     si.lpTitle = NULL;
    320     si.lpDesktop = NULL;
    321     si.dwX = si.dwY = si.dwXSize = si.dwYSize = 0L;
    322     si.wShowWindow = SW_HIDE;
    323     si.lpReserved2 = NULL;
    324     si.cbReserved2 = 0;
    325 
    326     si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
    327 
    328     si.hStdInput  = ShellStdinPipeHandle;
    329     si.hStdOutput = ShellStdoutPipeHandle;
    330 
    331     DuplicateHandle(GetCurrentProcess(), ShellStdoutPipeHandle, 
    332                     GetCurrentProcess(), &si.hStdError,
    333                     DUPLICATE_SAME_ACCESS, TRUE, 0);
    334 
    335     if (CreateProcess(NULL, pr00gie, NULL, NULL, TRUE, 0, NULL, NULL,
    336                       &si, &ProcessInformation)) 
    337     {
    338         ProcessHandle = ProcessInformation.hProcess;
    339         CloseHandle(ProcessInformation.hThread);
    340     } 
    341     else 
    342         holler("Failed to execute shell, error = %s", 
    343 			itoa(GetLastError(), smbuff, 10), NULL, NULL, NULL, NULL, NULL);
    344 
    345 
    346     return(ProcessHandle);
    347 }
    348 
    349 
    350 // **********************************************************************
    351 // SessionReadShellThreadFn
    352 //
    353 // The read thread procedure. Reads from the pipe connected to the shell
    354 // process, writes to the socket.
    355 //
    356 
    357 static VOID
    358 SessionReadShellThreadFn(
    359     LPVOID Parameter
    360     )
    361 {
    362     PSESSION_DATA Session = Parameter;
    363     BYTE    Buffer[BUFFER_SIZE];
    364     BYTE    Buffer2[BUFFER_SIZE*2+30];
    365     DWORD   BytesRead;
    366 
    367 	// this bogus peek is here because win32 won't let me close the pipe if it is
    368 	// in waiting for input on a read.
    369     while (PeekNamedPipe(Session->ReadPipeHandle, Buffer, sizeof(Buffer), 
    370                     &BytesRead, NULL, NULL)) 
    371     {
    372 		DWORD BufferCnt, BytesToWrite;
    373         BYTE PrevChar = 0;
    374 
    375 		if (BytesRead > 0)
    376 		{
    377 			ReadFile(Session->ReadPipeHandle, Buffer, sizeof(Buffer), 
    378                     &BytesRead, NULL);
    379 		}
    380 		else
    381 		{
    382 			Sleep(50);
    383 			continue;
    384 		}
    385 
    386 
    387         
    388         //
    389         // Process the data we got from the shell:  replace any naked LF's
    390         // with CR-LF pairs.
    391         //
    392         for (BufferCnt = 0, BytesToWrite = 0; BufferCnt < BytesRead; BufferCnt++) {
    393             if (Buffer[BufferCnt] == '\n' && PrevChar != '\r')
    394                 Buffer2[BytesToWrite++] = '\r';
    395             PrevChar = Buffer2[BytesToWrite++] = Buffer[BufferCnt];
    396         }
    397 
    398         if (send(Session->ClientSocket, Buffer2, BytesToWrite, 0) <= 0) 
    399             break;
    400     }
    401 
    402     if (GetLastError() != ERROR_BROKEN_PIPE)
    403         holler("SessionReadShellThreadFn exitted, error = %s", 
    404 			itoa(GetLastError(), smbuff, 10), NULL, NULL, NULL, NULL, NULL);
    405 
    406 	ExitThread(0);
    407 }
    408 
    409 
    410 // **********************************************************************
    411 // SessionWriteShellThreadFn
    412 //
    413 // The write thread procedure. Reads from socket, writes to pipe connected
    414 // to shell process.  
    415 
    416 
    417 static VOID
    418 SessionWriteShellThreadFn(
    419     LPVOID Parameter
    420     )
    421 {
    422     PSESSION_DATA Session = Parameter;
    423     BYTE    RecvBuffer[1];
    424     BYTE    Buffer[BUFFER_SIZE];
    425     DWORD   BytesWritten;
    426     DWORD   BufferCnt;
    427 
    428     BufferCnt = 0;
    429 
    430     //
    431     // Loop, reading one byte at a time from the socket.    
    432     //
    433     while (recv(Session->ClientSocket, RecvBuffer, sizeof(RecvBuffer), 0) != 0) {
    434 
    435         Buffer[BufferCnt++] = RecvBuffer[0];
    436         if (RecvBuffer[0] == '\r')
    437                 Buffer[BufferCnt++] = '\n';
    438 
    439 
    440 		// Trap exit as it causes problems
    441 		if (strnicmp(Buffer, "exit\r\n", 6) == 0)
    442 			ExitThread(0);
    443 
    444 
    445         //
    446         // If we got a CR, it's time to send what we've buffered up down to the
    447         // shell process.
    448         // SECURITY FIX: CW 12/27/04 Add BufferCnt size check.  If we hit end of buffer, flush it
    449         if (RecvBuffer[0] == '\n' || RecvBuffer[0] == '\r' || BufferCnt > BUFFER_SIZE-1) {
    450             if (! WriteFile(Session->WritePipeHandle, Buffer, BufferCnt, 
    451                             &BytesWritten, NULL))
    452             {
    453                 break;
    454             }
    455             BufferCnt = 0;
    456         }
    457     }
    458 
    459 	ExitThread(0);
    460 }
    461 
    462 #endif