Secure Honey

SSH honeypot written in C

Creating an SSH Session

Friday 18th October 2013 12:21

laptop connectedLast week I ended by saying I needed to adjust my server.c code to use a secure socket in order to create an SSH session

However, having researched how to create a secure socket in C (Stack overflow: Turn a simple Socket into an SSL Socket), and then spending an entire afternoon implementing the code, it didn't work.

Running a server on a secure socket isn't enough to initiate an SSH session. With the server running I tried using an SSH client to connect - nothing happened.

So I looked at the RFC (Wikipedia page on RFC) for SSH. The main SSH RFC protocol (RFC 4251), Section 1: Introduction, explains how there are three major components to the SSH protocol:

I read through the details of the SSH_TRANS protocol. In particular Section 4: Connection Setup.

Having read through the protocol details I now understood that an SSH session in initiated over a standard TCP/IP connection. The first communication that's sent between client and server is the identification string:

SSH-protoversion-softwareversion SP comments CR LF

Now I'm starting to gain an understanding of how the SSH protocol works I'm also realising just how much work would be involved in setting up my own SSH session.

At this point I emailed my project supervisor and he suggested I looked for a library that already implements the SSH protocol.

There are various SSH libraries out there (openssh, libssh2, libssh), but only libssh supports implementing an SSH server or more commonly known as an SSH daemon (sshd for short) - see Wikipedia page on what a daemon is.

libssh

So, at this point I've found a library which should allow implementation of an sshd. I just need to find a good example of how to implement it.

While browsing around the libssh source code on GitHub I found an example of an sshd: samplesshd.c.

The above example of an sshd has really helped me to understand how to create an SSH session in C. So the final task is for me to write my own C code which will allow an SSH client to connect.

At this early stage of the honeypot project, to keep things simple, I just want to log all attempted username and passwords. I don't want to actually authorise anyone just yet, that comes later.

I haven't had time yet this week to start writing the code for the basic SSH honeypot. However, thanks to my project supervisor for pointing me in the right direction, I have found an excellent example of what I'd like to achieve in order to get the ball rolling with this project.

While browsing through existing projects at GitHub, we stumbled across sshpot by Pete Morris.

This is the example code I've been looking for: (source: sshpot by Peter Morris)

#include "config.h"
#include "auth.h"

#include <libssh/libssh.h>
#include <libssh/server.h>

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <getopt.h>
#include <errno.h>
#include <sys/wait.h>

#define MINPORT 0
#define MAXPORT 65535

/* Global so they can be cleaned up at SIGINT. */
static ssh_session session;
static ssh_bind sshbind;


/* Print usage information to `stream', exit with `exit_code'. */
static void usage(FILE *stream, int exit_code) {
    fprintf(stream, "Usage: sshpot [-h] [-p <port>]\n");
    fprintf(stream,
            "   -h  --help          Display this usage information.\n"
            "   -p  --port <port>   Port to listen on; defaults to 22.\n");
    exit(exit_code);
}


/* Return the c-string `p' as an int if it is a valid port 
 * in the range of MINPORT - MAXPORT, or -1 if invalid. */
static int valid_port(char *p) {
    int port;
    char *endptr;

    port = strtol(p, &endptr, 10);
    if (port >= MINPORT && port <= MAXPORT && !*endptr && errno == 0) 
        return port;

    return -1;
}


/* Signal handler for cleaning up after children. We want to do cleanup
 * at SIGCHILD instead of waiting in main so we can accept multiple
 * simultaneous connections. */
static int cleanup(void) {
    int status;
    int pid;
    pid_t wait3(int *statusp, int options, struct rusage *rusage);

    while ((pid=wait3(&status, WNOHANG, NULL)) > 0) {
        if (DEBUG) { printf("process %d reaped\n", pid); }
    }

    /* Re-install myself for the next child. */
    signal(SIGCHLD, (void (*)())cleanup);

    return 0;
}


/* SIGINT handler. Cleanup the ssh* objects and exit. */
static void wrapup(void) {
    ssh_disconnect(session);
    ssh_bind_free(sshbind);
    ssh_finalize();
    exit(0);
}


int main(int argc, char *argv[]) {
    int port = DEFAULTPORT;

    /* Handle command line options. */
    int next_opt = 0;
    const char *short_opts = "hp:";
    const struct option long_opts[] = {
        { "help",   0, NULL, 'h' },
        { "port",   1, NULL, 'p' },
        { NULL,     0, NULL, 0   }
    };

    while (next_opt != -1) {
        next_opt = getopt_long(argc, argv, short_opts, long_opts, NULL);
        switch (next_opt) {
            case 'h':
                usage(stdout, 0);
                break;

            case 'p':
                if ((port = valid_port(optarg)) < 0) {
                    fprintf(stderr, "Port must range from %d - %d\n\n", MINPORT, MAXPORT);
                    usage(stderr, 1);
                }
                break;

            case '?':
                usage(stderr, 1);
                break;

            case -1:
                break;

            default:
                fprintf(stderr, "Fatal error, aborting...\n");
                exit(1);
        }
    }

    /* There shouldn't be any other parameters. */
    if (argv[optind]) {
        fprintf(stderr, "Invalid parameter `%s'\n\n", argv[optind]);
        usage(stderr, 1);
    }

    /* Install the signal handlers to cleanup after children and at exit. */
    signal(SIGCHLD, (void (*)())cleanup);
    signal(SIGINT, (void(*)())wrapup);

    /* Create and configure the ssh session. */
    session=ssh_new();
    sshbind=ssh_bind_new();
    ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDADDR, LISTENADDRESS);
    ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT, &port);
    ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, "ssh-rsa");
    ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY,RSA_KEYFILE);

    /* Listen on `port' for connections. */
    if (ssh_bind_listen(sshbind) < 0) {
        printf("Error listening to socket: %s\n",ssh_get_error(sshbind));
        return -1;
    }
    if (DEBUG) { printf("Listening on port %d.\n", port); }

    /* Loop forever, waiting for and handling connection attempts. */
    while (1) {
        if (ssh_bind_accept(sshbind, session) == SSH_ERROR) {
            fprintf(stderr, "Error accepting a connection: `%s'.\n",ssh_get_error(sshbind));
            return -1;
        }
        if (DEBUG) { printf("Accepted a connection.\n"); }

        switch (fork())  {
            case -1:
                fprintf(stderr,"Fork returned error: `%d'.\n",-1);
                exit(-1);

            case 0:
                exit(handle_auth(session));

            default:
                break;
        }
    }

    return 0;
}

So, this week I'll be attempting to implement my own version of sshpot and hopefully I can start logging some SSH login attempts on my server.

Image credit: "Connected to the World" by Stuart McKinnon, flickr.com/photos/stuballscramble/2941702825/

Comments

There are no comments for this blog post yet

Add Comment

Name

Email (won't be displayed)

Website (optional)

Comments

Live Stats (see full stats)

Attempted logins

date range # attempts
today393
yesterday194
past 7 days4,426
past 30 days17,357
all time4,114,040

Top 5 passwords

password # attempts
12345618,562
admin8,503
password6,536
-6,393
root4,833

Top 5 usernames

username # attempts
root3,927,129
admin78,772
test4,046
oracle3,356
nagios2,648

Stats represent data collected from SSH login attempts on multiple honeypots. Parts of some stats may be filtered to maintain anonymity.

Updated: Tue, 07 Jun 2016 16:33:48 +0000

Live Password Cloud

12qwaszx 963852741 1234%^ POIUYT 12344321 zxcvbn 111 zaqxsw 888888 111111 asdfghjkl a123456 windows qwer1234 q1w2e3 Passw0rd zxcv support 1111 server iloveyou welcome123 user !@ abcdef a cisco 123abc qwer qwerty123 q123456 manager 54321 alpine qq123456 huawei 11223344 password zaqxswcde qazwsx default 1 qwe123 test okokok 88888888 ubnt dragon 159753 147852369 12345678 passwd qwertyuiop 23456 power qwaszx huawei123 changeme123 123123123 5201314 Aa123456 qwe 1qazxsw2 nagios redhat zaqxswcdevfr q1w2e3r4 1234qwer 1qaz2wsx3edc monitor 12345 pass root1234 password123 123qweasd 000000 z1x2c3v4 qaz qazwsx123 f**kyou admin123!@# Pass123 121212 p@ssword 1a2s3d4f 1qaz2wsx Admin123456 woaini zaq1xsw2 linux adminadmin _ system 1qaz@WSX P@ssw0rd1 sapp a1b2c3d4 654321 qazwsxedc 1234 sqlpp qazxsw asdf sysadmin qqpp abc123 idc2008 123123 666666 123456 123qwe 987654321 admin123 admin@123 zhang 789789 11111111 idcidc qwerty123456 secret Huawei@123 !@#$%^ changeme 1q2w3e 147258369 superman 147258 admin1 mnbvcxz admin welcome 225588 !qaz1QAZ 123 p0o9i8u7 apple aaa !QAZ2wsx administrator zzzzzz oracle qwerty china 0000 rootpass 7890pp letmein abcd1234 1122334455 raspberry abc1234 a1s2d3f4 rootroot P@ssw0rd qwert public adminpp 1q2w3e4r5t root 1234567890 qweasd guest asdfgh test123 zxcvbnm caonima - !QAZ@WSX 112233 147147 123654 q1w2e3r4t5 1234567 1q2w3e4r password1 root123 123456789 12345qwert qweasdzxc 110110 159357