Threaded banner scanner that is rather versatile and lightweight.
8265bf561570b0b737107a03fe3943d365b3ba56e5ee0416bf40453166ab473d
/*
- bannascanna.c v0.2.3 july 18, 2003 -
by intrusive (intrusive@portalofevil.com)
now threaded and can probe a single ip as
well as class a, b and c ranges.
compilation: gcc bannascanna-0.2.3.c -o bannascanna -lpthread
props to salvia and que from undernet for their invaluable help!
future improvements: support network specification on cmd line via netmasks,
grab banners on multiple ports and... can't remember other stuff i was going
to do right now...feel free to send comments/suggestions to aforementioned
email address
*/
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <ctype.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>
#include <netinet/in.h>
#include <pthread.h>
#include <fcntl.h>
#include <errno.h>
#include <arpa/inet.h>
struct targetnfo {
char *targname;
char *banstring;
char *exname;
char *logfile;
char class;
int port;
} target;
struct info {
struct sockaddr_in *us;
int socknum;
socklen_t socklen;
char ip[17];
};
FILE *fptr;
pthread_mutex_t filelock;
void usage(char *bin) {
fprintf(stderr, "usage: %s <-n network> <-p port> <-c class> [-s string] [-l logfile-name]\n\n", bin);
fprintf(stderr, "ex: %s -n 192.168.0.0 -p 22 -c B -s \"OpenSSH\" -l logdir/192.168log\n", bin);
fprintf(stderr, "class is the A, B, or C network class letter assignment. H is used for a single host\n\n");
exit(1);
}
void *tryconn(void *ptr) {
struct info *hostinfo = (struct info *)ptr;
struct timeval tv;
fd_set in;
char recvbuf[256];
int y, f, ret1, ret2;
y = 0;
f = fcntl(hostinfo->socknum, F_GETFL,0);
fcntl(hostinfo->socknum, F_SETFL, f | O_NONBLOCK);
ret1 = connect(hostinfo->socknum, (struct sockaddr *)hostinfo->us, hostinfo->socklen);
if((ret1 < 0) && (errno != EINPROGRESS)) {
close(hostinfo->socknum);
pthread_exit(NULL);
}
FD_ZERO(&in);
FD_SET(hostinfo->socknum, &in);
tv.tv_sec = 5;
tv.tv_usec = 0;
if((ret2 = select(hostinfo->socknum + 1, &in, NULL, NULL, &tv)) == 0) {
errno = ETIMEDOUT;
close(hostinfo->socknum);
pthread_exit(NULL);
}
if(FD_ISSET(hostinfo->socknum, &in)) {
if((y = recv(hostinfo->socknum, recvbuf, 255, 0)) > 0) {
if(target.banstring == NULL) {
printf("- %s:%d open -\nrecieved:\n%s\n-\n\n\n", hostinfo->ip, target.port, recvbuf);
if(fptr != NULL) {
pthread_mutex_lock(&filelock);
fprintf(fptr, "- %s:%d open -\nrecieved:\n%s\n-\n\n\n", hostinfo->ip, target.port, recvbuf);
pthread_mutex_unlock(&filelock);
}
}
else {
if(strstr(target.banstring, recvbuf) != NULL) {
printf("- found match at %s:%d open -\nrecieved:\n%s\n-\n\n\n", hostinfo->ip, target.port, recvbuf);
if(fptr != NULL) {
pthread_mutex_lock(&filelock);
fprintf(fptr, "found match at: %s:%d open -\nrecieved:\n%s\n-\n\n\n", hostinfo->ip, target.port, recvbuf);
pthread_mutex_unlock(&filelock);
}
}
}
}
}
if(fptr != NULL) {
pthread_mutex_lock(&filelock);
fflush(fptr);
pthread_mutex_unlock(&filelock);
}
close(hostinfo->socknum);
pthread_exit(NULL);
}
void startscan(long total) {
void *ptr;
int sock, x, y, z;
char buf[256];
struct sockaddr_in rem_host[256];
struct info hostinfo[256];
pthread_t tnum[256];
pthread_attr_t attr;
u_int32_t addy;
x = y = z = 0;
if(target.logfile != NULL) {
if((fptr = fopen(target.logfile, "a+")) == NULL)
fprintf(stderr, "no permission to open/create logfile in cwd\n");
}
else
fptr = NULL;
if(inet_aton(target.targname, &rem_host[x].sin_addr) == 0) {
fprintf(stderr, "invalid hostname\n");
usage(target.exname);
}
rem_host[x].sin_family = AF_INET;
rem_host[x].sin_port = htons(target.port);
addy = rem_host[x].sin_addr.s_addr;
if(total == 1) {
if((sock = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
fprintf(stderr, "error creating socket\n");
usage(target.exname);
}
if(connect(sock, (struct sockaddr *)&rem_host[x], sizeof(rem_host[x])) == -1) {
fprintf(stderr, "couldn't connect. port is closed or filtered\n");
return;
}
if((y = recv(sock, buf, 255, 0)) > 0) {
if(target.banstring == NULL) {
printf("%d open at: %s\nrecieved: %s\n", rem_host[x].sin_port, (char *)inet_ntoa(rem_host[x].sin_addr), buf);
if(fptr != NULL)
fprintf(fptr, "%d open at: %s\nrecieved: %s\n", rem_host[x].sin_port, (char *)inet_ntoa(rem_host[x].sin_addr), buf);
}
else {
if(strstr(buf, target.banstring)) {
printf("matched string at: %s:%d\nrecieved: %s\n", (char *)inet_ntoa(rem_host[x].sin_addr), rem_host[x].sin_port, buf);
if(fptr != NULL)
fprintf(fptr, "matched string at: %s:%d\nrecieved: %s\n", (char *)inet_ntoa(rem_host[x].sin_addr),
rem_host[x].sin_port, buf);
}
}
}
if(fptr != NULL)
fclose(fptr);
return;
}
pthread_attr_init(&attr);
pthread_mutex_init(&filelock, NULL);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
while(z < total) {
for(x = 0; x < 256; x++) {
if((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
fprintf(stderr, "error creating socket\n");
usage(target.exname);
}
memcpy(&rem_host[x], &rem_host[0], sizeof(rem_host[0]));
rem_host[x].sin_addr.s_addr = (addy + htonl(z));
if(x == 0)
printf("starting on %s...\n\n", (char *)inet_ntoa(rem_host[x].sin_addr));
strcpy(hostinfo[x].ip, (char *)inet_ntoa(rem_host[x].sin_addr));
hostinfo[x].socklen = sizeof(rem_host[x]);
hostinfo[x].socknum = sock;
hostinfo[x].us = &rem_host[x];
ptr = &hostinfo[x];
if(pthread_create(&tnum[x], &attr, tryconn, ptr) != 0) {
perror("system out of resources\n");
exit(1);
}
z++;
}
printf("wait a sec on threads to exit()\n");
sleep(6);
}
if(fptr != NULL)
fclose(fptr);
pthread_mutex_destroy(&filelock);
printf("\n\nscan complete\n");
pthread_exit(NULL);
}
int main(int argc, char **argv)
{
int op;
char c;
target.banstring = NULL;
target.port = 0;
fptr = NULL;
if((argc < 7) || (argc > 11)) {
fprintf(stderr, "invalid argument(s)\n");
usage(argv[0]);
}
while((op = getopt(argc, argv, "n:h:p:c:s:l:")) != EOF) {
switch(op) {
case 'n':
target.targname = malloc(strlen(optarg) + 1);
strncpy(target.targname, optarg, strlen(optarg));
break;
case 'h':
target.targname = malloc(strlen(optarg) + 1);
strncpy(target.targname, optarg, strlen(optarg));
break;
case 'p':
target.port = atoi(optarg);
break;
case 'c':
c = *optarg;
target.class = toupper(c);
break;
case 's':
target.banstring = malloc(strlen(optarg) + 1);
strncpy(target.banstring, optarg, strlen(optarg));
break;
case 'l':
target.logfile = malloc(strlen(optarg) + 1);
strncpy(target.logfile, optarg, strlen(optarg));
break;
default:
fprintf(stderr, "invalid argument(s)\n");
usage(argv[0]);
}
}
target.exname = malloc(strlen(argv[0]) + 1);
strncpy(target.exname, argv[0], strlen(argv[0]));
switch(target.class) {
case 'A':
startscan(16777216);
break;
case 'B':
startscan(65536);
break;
case 'C':
startscan(256);
break;
case 'H':
startscan(1);
break;
default:
fprintf(stderr, "invalid address class specified\n");
usage(argv[0]);
}
free(target.exname);
free(target.targname);
if(target.logfile != NULL)
free(target.logfile);
if(target.banstring != NULL)
free(target.banstring);
return 0;
}