Greetings PEN-TESTers!

AngryPacket Security is proud to announce the release of mothra-v1.
mothra is a banner grabber that has some nice features including various
protocol negotiations (ie: telnet, ntp...), file logging, highly
configurable port ranges and lists, host range scanning (up to a class
C) and c0l0rized output. :)

Hopefully some will find it useful.

Please feel free to send comments, suggestions or patches.

Cheers,
-- 
Josha Bronson
[EMAIL PROTECTED]
AngryPacket Security
/* $Id: mothra.c,v 1.189 2002/02/27 23:58:40 dmuz Exp $ */

/* AngryPacket Security - http://sec.angrypacket.com */
/* mothra - a monstrous yet graceful banner graber */

/* this is mothra version 1 */

/* feel free to send any bugfixes, patches, comments, suggestions, etc */

/*
            o  o
      xo__  \__/  __ox
      \_  \ (__) /  _/
        \_-[xxxx]-_/
          \ -  - /
        _/ - -- - \_
      _/   { AP }   \_
     /----/\{  }/\----\
             \/
*/

/* by dmuz - [EMAIL PROTECTED] */
/* with massive amounts of leet code from methodic */
/* also some "pointers" by freek... heh */

/* mothra was developed on OpenBSD for *BSD. It's been tested on OpenBSD,
 * NetBSD and FreeBSD. It should work on most Linux distributions too. */

/* Add -DDEBUG for debug mode (not recommened) */

#include <stdio.h>

#include <ctype.h>
#include <errno.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/fcntl.h>
#include <unistd.h>

#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>

#define IPSIZE 17 /* enough to hold 12 digits, 4 dots, and a NULL */
#define MAX_BANNER_SIZE 512
#define MAX_PORTS       65535

#define FTP             21
#define TELNET  23
#define SMTP    25
#define TIME    37
#define HTTP    80
#define POP3PW  106
#define POP3    110
#define IDENT   113
#define IMAP4   143

#define RED             "\E[1;31;40m"
#define YELLOW  "\E[1;33;40m"
#define WHITE   "\E[0;38;40m"

#define ANGRYPACKET_OWNZ_YOU    1


/* global buffer to store data */
char buf[MAX_BANNER_SIZE+1];
/* keep track of connect state */
int state=0;
/* recv() timeout variable, default is 15 seconds */
int u_timeout=15;
/* verbose output variable */
int verbose=0;
extern int errno;

/* usage */ //XXX add EX: or example usages here
void usage(void) {
    fprintf(stderr,"\nUSAGE: mothra -H <host_range> -h <host> -p <ports> -r <ports>" 
                " -t <timeout> -f <logfile> -cv\n");
    fprintf(stderr,"\t-H\t\thost IP range to scan\n");
    fprintf(stderr,"\t-h\t\tsingle hostname to scan\n");
    fprintf(stderr,"\t-p\t\tcomma seperated ports to grab\n");
    fprintf(stderr,"\t-r\t\trange of ports (ex. 1-10)\n");
    fprintf(stderr,"\t-t\t\ttimeout in seconds for a connection to a port\n");
    fprintf(stderr,"\t-f\t\tlogfile to record banners in\n");
    fprintf(stderr,"\t-c\t\tprint banners in color\n");
        fprintf(stderr,"\t-v\t\tverbose output\n\n");
    exit(0);
}

/* omg... ph33r!!! */
void ph33r(int color_out) {
        if(color_out) {
                fprintf(stderr,
                RED "\nmothra by dmuz and methodic - AngryPacket Security\n\n" WHITE );
        } else {
                fprintf(stderr,"\nmothra by dmuz and methodic - AngryPacket 
Security\n\n");
        }
};

/* timer signal function */
void catchsignal() {
        state = 1;
        if(verbose)
                printf("timed out.\n");
}

int parse_banner(char *banner, const char *delim) {
        int len;
        char *buf_p, *banner_p, *p;

        len = strlen(delim);

        banner_p = (char *)malloc(strlen(banner)+1);
        bzero(banner_p, strlen(banner)+1);

        for(buf_p = strtok(banner, "\n"); buf_p != NULL;) {
                p = strstr(buf_p, delim);
                if(p) {
                        memmove(banner_p, (p+len), strlen(buf_p)-len);
                }
                buf_p = strtok(NULL, "\n");
        }
        if(banner_p) {
                strncpy(banner, banner_p, MAX_BANNER_SIZE);
        } else {
                strncpy(banner, "no banner available", MAX_BANNER_SIZE);
        }
        free(banner_p);

        return(0);
}

int do_port_hook(int port, int sock) {
        char *http_s = "HEAD / HTTP/1.0\n\n";
        char *identd_s = "VERSION\n";

        if(port == HTTP) {
                send(sock, http_s, strlen(http_s), 0);
        }

        if(port == IDENT) {
                send(sock, identd_s, strlen(identd_s), 0);
        }

        return(0);
}

/* preprocess data to port if we have a hook */
int process_port(int port, int sock) {
        int x, i=0, j=0, result=0;

        unsigned int y;
        unsigned long epoch = 2208988800ul;
        unsigned char tmpbuf[MAX_BANNER_SIZE+1], *p=NULL, obuf[4];
        time_t timedate;

        struct timeval timeout;
        fd_set fds;

        /* set timeout values for recv() */
        timeout.tv_sec = u_timeout;
        timeout.tv_usec = 0;
        FD_ZERO(&fds);
        FD_SET(sock, &fds);
        fcntl(sock, F_SETFL, O_NONBLOCK);
        select(sock+1, &fds, NULL, NULL, &timeout);

        if(port == FTP) {
                /* loop to strip out ftp "messages" */
                do {
                        bzero(tmpbuf, MAX_BANNER_SIZE+1);
                        result = recv(sock, tmpbuf, MAX_BANNER_SIZE, 0);
                        if( result == -1 ) {
                                if(verbose)
                                        printf("  * recv timed out for port %d, 
skipping\n", port);
                                return(result);
                        }
                }while(strstr(tmpbuf, "220-"));
                strncpy(buf, tmpbuf, MAX_BANNER_SIZE);
        }

        if(port == TELNET) {
                do {
                        sleep(1); /* i cant fscking believe we need this */
                        bzero(tmpbuf, MAX_BANNER_SIZE+1);
                        result = recv(sock, tmpbuf, MAX_BANNER_SIZE, 0);
                        if( result == -1 ) {
                                if(verbose)
                                        printf("  * recv timed out for port %d, 
skipping\n", port);
                                return(result);
                        }
                        for(i = 0; i < result; i++) {
                                /* we need to check every 3rd response, ie 0, 3, 9, 
12, etc */
                                if((i % 3) == 0 && i > 0) {
#if DEBUG
                                        printf("recv(%3u, %3u, %3u) [num=%2d] 
[seq=%2d]\n",
                                                                tmpbuf[i-3], 
tmpbuf[i-2], tmpbuf[i-1], ++j, i);
#endif
                                        if(tmpbuf[i-3] != 255) { /* not a telnet IAC */
                                                bzero(buf, MAX_BANNER_SIZE+1);
                                                i=0;
                                                for(j = 0; j < result; j++) {
#if DEBUG
                                                        printf("%u,", tmpbuf[j]);
#endif
                                                        /* skip any telnet commands we 
still may have in
                                                         * the buffer */
                                                        if(tmpbuf[j] == 255) {
                                                                j++; j++;
                                                        } else if(tmpbuf[j] != 0 && 
tmpbuf[j] != 13) {
                                                                buf[i] = tmpbuf[j];
                                                                i++;
                                                        }
                                                }
                                                buf[i] = '\0';
                                                return(strlen(buf));
                                        }
                                }
                        }
                        /* if we recieved a telnet command, respond to it */
                        /* most of code ripped from netcat */
                        p = tmpbuf;
                        x = strlen(tmpbuf);
                        while(x > 0) {
                                obuf[0] = 255;
                                p++; x--;
                                if( (*p == 251) || (*p == 252))
                                        y = 254;
                                if( (*p == 253) || (*p == 254))
                                        y = 252;
                                if(y) {
                                        obuf[1] = y;
                                        p++; x--;
                                        obuf[2] = *p;
                                        send(sock, obuf, 3, 0);
                                        y = 0;
                                }
                                p++; x--;
                        }
                }while(p != NULL);
#if DEBUG
                printf("telnet timed out.. cleaning up\n");
#endif
        }

        if(port == TIME) {
                bzero(tmpbuf, MAX_BANNER_SIZE+1);
                result = recv(sock, &timedate, sizeof(timedate), 0);
                if( result == -1 ) {
                        if(verbose)
                                printf("  * recv timed out for port %d, skipping\n", 
port);
                        return(result);
                }
                timedate = ntohl((u_long)timedate) - epoch;
                snprintf(buf, MAX_BANNER_SIZE, "%s", ctime(&timedate));
        }

        if(result == 0) {
                bzero(buf, MAX_BANNER_SIZE+1);
                result = recv(sock, buf, MAX_BANNER_SIZE, 0);
                if( result == -1 ) {
                        if(verbose)
                                printf("  * recv timed out for port %d, skipping\n", 
port);
                }
        }

        return result;
}


/* post process a banner if we want */
int post_process(int port, char *banner) {
        int i=1;
        char *banner_p;

        banner_p = (char *)malloc(strlen(banner)+1);
        bzero(banner_p, strlen(banner)+1);

        if(port == FTP) {
                if(strstr(banner, "220 "))
                        parse_banner(banner, "220 ");
        }

        if(port == SMTP) {
                parse_banner(banner, "220 ");
        }

        if(port == HTTP) {
                parse_banner(banner, "Server: ");
        }

        if(port == POP3PW) {
                parse_banner(banner, "200 ");
        }

        if(port == POP3) {
                parse_banner(banner, "+OK ");
        }

        if(port == IMAP4) {
                parse_banner(banner, "* OK ");
        }

        /* chop off any newline chars */
        i = (strlen(banner)) - 1 ;
        while(banner[i] == '\r' || banner[i] == '\n') {
                banner[i] = '\0';
                i--;
        }
        
        free(banner_p);

        return 0;
}

/* record open port banners to a file */
void log(int port, char *logfile, char *banner) {
        FILE *log_p;

        if ((log_p = fopen(logfile, "a+")) == NULL) {
                fprintf(stderr,"\ncould not open log file %s\n", logfile);
        } else {
                fprintf(log_p, "port %i: %s\n", port, banner);
                fclose(log_p);
        }
}

/* like, get some banners brah! most excellent! */
int main(int argc, char *argv[]) {
        /* network vars */
        int sock; 
        char *hostname=NULL, tmphost[IPSIZE];
        char *host_r[5];
        int start_addr=0, end_addr=0;
        int num_hosts=0;
        struct sockaddr_in s; /* inet socket address structure */
        struct hostent *host_ent; /* host info structure */
        /* var args */
        int ch;
        char *ap;
        int start_port=0;
        int ports[MAX_PORTS+1];
        int range[3];
        int i=0, nports =0;
        /* extra variables */
        int color_out=0;
        int result=0;
        /* connect() timeout struct */
        struct itimerval itv;
        /* signal structure */
        struct sigaction sig;
        /* file shit */
        FILE *log_p;
        char *logfile = NULL;

        bzero(ports, MAX_PORTS+1);
        /* args */
        while ((ch = getopt(argc, argv, "h:H:p:r:t:f:cv")) != -1) {
                switch (ch) {
                case 'H':
                        /* split the dotted quad */
                        ap = strtok(optarg, ".");
                        for(i = 0; i != 4; i++) {

                                if(ap == NULL) {
                                        fprintf(stderr,"\nSyntax error in host range 
argument.\n");
                                        usage();
                                }

                                host_r[i] = ap;
                                ap = strtok(NULL, ".");
                        }

                        /* split the range argument */
                        ap = strtok(host_r[3], "-");
                        for(i = 0; i != 2; i++) {
                                host_r[4] = ap;
                                if(ap == NULL) {
                                        fprintf(stderr,"\nSyntax error in host range 
argument.\n");
                                        usage();
                                }
                                ap = strtok(NULL, "-");
                        }

                        /* test each of member the dotted quad for correctness */
                        for(i = 0; i != 5; i++) {
                                if (atoi(host_r[3]) >= atoi(host_r[4])) {
                                        fprintf(stderr,"\nSyntax error in host range 
argument.\n");
                                        usage();
                                }
                                if (host_r[i] == NULL || atoi(host_r[i]) > 255 || 
atoi(host_r[i]) < 0) {
                                        fprintf(stderr,"\nSyntax error in host range 
argument.\n");
                                        usage();
                                }
                        }

                        start_addr = atoi(host_r[3]);
                        end_addr = atoi(host_r[4]);
                        num_hosts = end_addr - start_addr;

                        break;
                case 'h':
                        hostname = optarg;
                        break;
                case 'p':
                        ap = strtok(optarg, ",");

                        for(i = 0; ap; i++) {
                                ports[i] = atoi(ap);
                                if((ports[i] == 0) || (ports[i] > 65535) || (ports[i] 
< 0)) {
                                        fprintf(stderr,"\nSyntax error in port(s) list 
argument.\n");
                                        usage();
                                }
                                ap = strtok(NULL, ",");
                        }

                        nports = i; /* number of ports to check */
                        break;
                case 'r':
                        ap = strtok(optarg, "-");
                        for(i = 0; i != 2; i++) {
                                if(ap == NULL) {
                                        fprintf(stderr,"\nSyntax error in port range 
argument.\n");
                                        usage();
                                }
                                range[i] = atoi(ap);
                                if(range[i] == 0) {
                                        fprintf(stderr,"\nSyntax error in port range 
argument.\n");
                                        usage();
                                }
                                ap = strtok(NULL, "-");
                        }
                        if(range[0] >= range[1]) {
                                fprintf(stderr,"\nSyntax error in port range 
argument.\n");
                                usage();
                        }
                        start_port=range[0];
                        break;
                case 't':
                        u_timeout = atoi(optarg);
                        break;
                case 'f':
                        logfile = optarg;
                        break;
                case 'c':
                        color_out = 1;
                        break;
                case 'v':
                        verbose = 1;
                        break;
                default:
                        usage();
                }
        }
        argc -= optind;
        argv += optind;

        /* -p and -r can't both be specified */
        if(range[0] && nports) {
                printf("\n-p and -r are mutually exclusive dude\n");
                usage();
        } 

        /* build our ports[] array if we are using a range */
        if(range[0]) {
                for(i = range[0]; i < range[1]+1; i++) {
                        ports[i] = i; 
                }
                nports = i;
                start_port = range[0];
        } else {
                start_port = 0;
        }

        // if(!hostname || !nports) {
        if(!nports) {
                usage();
        }

        /* print out our mad greetz */
        ph33r(color_out);

        num_hosts++;

        while(num_hosts > 0) {
                if(start_addr && end_addr) {
                        /* build our hostname */
                        snprintf(tmphost, IPSIZE, "%s.%s.%s.%d", host_r[0], host_r[1], 
host_r[2], start_addr);
                        hostname = (char *)malloc(IPSIZE);
                        strncpy(hostname, tmphost, IPSIZE);
                        start_addr++;
                }

                /* attempt to open the logfile */
                if(logfile) {
                        if((log_p = fopen(logfile, "a+")) == NULL) {
                                fprintf(stderr, "could not open log file %s\n", 
logfile);
                        } else {
                                fprintf(log_p, "-- - banner scan for [%s] - --\n", 
hostname);
                                fclose(log_p);
                        }
                }
                printf("-> starting banner scan for %s\n", hostname);

                /* zero socket structure */
                bzero(&s, sizeof(s));

                if((host_ent = gethostbyname(hostname)) == NULL) {
                        fprintf(stderr, "  * unknown host: %s\n", hostname);
                        break;
                } else {
                        memcpy((char*)&s.sin_addr, host_ent->h_addr, 
host_ent->h_length);
                }


                if(start_port) {
                        i = start_port;
                } else {
                        i = 0;
                }
                for(; i < nports; i++) {
                        /* protocol and port information */
                        s.sin_family = AF_INET;
                        s.sin_port = htons(ports[i]);
                        /* setup the socket */
                        sock = socket(AF_INET, SOCK_STREAM, 0);

                        /* create timeout values for connect() */
                        itv.it_value.tv_sec = u_timeout;
                        itv.it_value.tv_usec = 0;
                        itv.it_interval = itv.it_value;
                        setitimer(ITIMER_REAL, &itv, NULL);

                        sig.sa_handler = catchsignal;
                        sigemptyset(&sig.sa_mask);
                        sig.sa_flags = 0;

                        sigaction(SIGALRM, &sig, 0);
                
                        if(verbose)
                                printf("-> connecting to port [%d] on %s.. ", 
ports[i], hostname);
                        fflush(stdout);

                        if(connect(sock, (struct sockaddr*)&s, sizeof(s)) == 0) {
                                itv.it_value.tv_sec=0;
                                itv.it_value.tv_usec=0;
                                itv.it_interval=itv.it_value;
                                setitimer(ITIMER_REAL,&itv,NULL);
                            if(verbose)
                                        printf("connected!\n");
                                do_port_hook(ports[i], sock);
                                if((result = process_port(ports[i], sock)) > 0){
                                        post_process(ports[i], buf);
                                        if(logfile) {
                                                log(ports[i], logfile, buf); 
                                        } else {
                                                if(color_out) {
                                                        printf(YELLOW "port %d: %s\n" 
WHITE, ports[i], buf);
                                                } else {
                                        printf("port %d: %s\n", ports[i], buf);
                                                }
                                        }
                                }
                        } else if (state == 1) {
                                /* timed out */
                                state=0;
                        } else {
                                /* couldn't connect */
                                if(verbose) {
                                        printf("connect failed.\n");
#if DEBUG
                                        printf("DEBUG ERROR: %d\n", errno);
#endif
                                }
                        }
                    close(sock);
                }

                if(logfile) {
                        if((log_p = fopen(logfile, "a+")) == NULL) {
                                fprintf(stderr, "could not open log file %s\n", 
logfile);
                        } else {
                                fprintf(log_p, "\n");
                                fclose(log_p);
                        }
                }

                printf("-> finished banner scan for %s\n", hostname);
                num_hosts--;

                if(start_addr && end_addr) {
                        free(hostname);
                }
        }
        printf("-> visit http://sec.angrypacket.com for security tools and info\n");
        return EX_OK;
}

----------------------------------------------------------------------------
This list is provided by the SecurityFocus Security Intelligence Alert (SIA)
Service. For more information on SecurityFocus' SIA service which
automatically alerts you to the latest security vulnerabilities please see:
https://alerts.securityfocus.com/

Reply via email to