/* $Id: dirbx.c,v 1.49 2002/12/16 04:29:04 methodic Exp $ */

/*
dirbx - brute force executable directory lister
by dmuz and methodic.. ph33r the 31336++ c0d3z
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>

/* global chars */
char alphabet[]="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.";
unsigned int start=4, end=10, log=0, recursive=0, verbose=0;
char *logfile;

/* function protoypes */
void brute_dir(char *dir);

void calc_elapsed_time(char *path, time_t start_time, time_t finish_time) {
	long elapsed;
	unsigned int minutes, seconds;

	elapsed = difftime(finish_time, start_time);
	if(verbose) {
		if(elapsed > 59) {
			minutes = (elapsed / 60);
			seconds = (elapsed - (minutes * 60));
			printf("+ [%s] brute-force took %d minutes and %d seconds\n", path, minutes, seconds);
		} else {
			printf("+ [%s] brute-force took %ld seconds\n", path, elapsed);
		}
	}
}

/* write a message to the logfile */
void write_log(char *outfile, char *message) {
	FILE *log_p;

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

void does_exist(char *dir, char *path) {
	size_t pathlen;
	char *fullpath;
	char *msg;

	/* XXX perhaps there is a better way to do this? hehe */
	if( (path[0] == '.' && path[1] == '\0') ||
		(path[0] == '.' && path[1] == '.' && path[2] == '\0') ) {
			return;
	}

	/* malloc enough for dir + / + path + NULL */
	pathlen = (strlen(dir) + strlen(path) + 2);
	fullpath = (char *)malloc(pathlen);
	/* craft the full path name */
	snprintf(fullpath, pathlen, "%s/%s", dir, path);
	/* test to see if the file exists */
	if(access(fullpath, F_OK) == 0) {
		if(log) {
			msg = (char *)malloc(strlen(fullpath) + 9);
			snprintf(msg, (strlen(fullpath) + 9), "FOUND: %s\n", fullpath);
			write_log(logfile, msg);
			free(msg);
		} else {
			printf("FOUND: %s\n", fullpath);
		}
		if(recursive) {
			/* make sure what we found is a directory and not a file */
			if(verify_dir(fullpath)) {
				brute_dir(fullpath);
			}
		}
	}
	/* a lean program is a happy program */
	free(fullpath);
}

void brute_dir(char *dir) {
	int i; /* counter */
	int index; /* the current index we are at */
	char *curpath, *pos; /* the current pathname, and a position pointer */
	time_t start_brute, finish_brute;

	time(&start_brute);
	for(i = start; i < (end + 1); i++) {
		/* allocate enough memory to hold curpath and NULL*/
		curpath = (char *)malloc((sizeof(char) * i) + 1);
		/* fill curpath with all a's */
		memset(curpath, 'a', (sizeof(char) * i));
		/* make sure curpath is NULL terminated */
		curpath[(sizeof(char) * i)] = '\0';
		/* get the number of indexes of curpath (ie: length) */
		index = (i - 1);
		if(verbose) {
			printf("+ brute-forcing [%s, %d chars]\n", dir, i);
		}
		while(1) {
			/* check to see if the path exists */
			does_exist(dir, curpath);
			/* check to see if the current index of curpath doesnt equal
			 * the last character of our alphabet */
			if(curpath[index] != alphabet[strlen(alphabet)-1]) {
				/* increase the character at our current index */
				pos = strchr(alphabet, curpath[index]);
				curpath[index] = alphabet[(pos - alphabet)+1];
			} else {
				/* rewind our index as long as the current index matches
				 * the last character of our alphabet */
				while(curpath[index] == alphabet[strlen(alphabet)-1]) {
					index--;
				}
				/* we reached the last index for this path, break out of loop */
				if(index == -1) {
					break;
				}
				/* increase the character at our current index */
				pos = strchr(alphabet, curpath[index]);
				curpath[index] = alphabet[(pos - alphabet)+1];
				/* move our index forward, replacing each index with the
				 * first character of our alphabet */
				while(index < (strlen(curpath) - 1)) {
					index++;
					curpath[index] = alphabet[0];
				}
			}
		}
		free(curpath);
	}
	time(&finish_brute);
	/* calculate how long the brute force took */
	calc_elapsed_time(dir, start_brute, finish_brute);
}

int verify_dir(char *dir) {
	struct stat sbuf;

	if(verbose) {
		printf("+ directory verify for '%s'..", dir);
	}
	if(stat(dir, &sbuf) == -1) {
		/* XXX im guessing if you cant stat something, its not there */
		if(verbose) {
			printf(" doesn't exist\n");
		}
		return 0;
	}
	if(S_ISDIR(sbuf.st_mode)) {
		if(verbose) {
			printf(" ok\n");
		}
		return 1;
	} else {
		if(verbose) {
			printf(" not a directory\n");
		}
		return 0;
	}
}

void usage(char *progname) {
	printf("usage: %s [ -d <directory> OR -i <infile> ]\n"
		"\t-s <start value> -e <end value> -l <logfile>\n"
		"\t-r (recursive brute force)\n", progname);
	exit(-1);
}

/* parse the input file */
void parse_infile(char *infile) {
	FILE *file_p;
	char dir[256];

	if ((file_p = fopen(infile, "r")) == NULL) {
		fprintf(stderr, "\ncould not open input file %s\n", infile);
		return;
	} else {
		while(1) {
			if(fgets(dir, 256, file_p) == NULL) {
				/* we weren't able to get any more input.. break */
				break;
			} else {
				/* clean up cruft */
				while(dir[strlen(dir)-1] == '\n' || dir[strlen(dir)-1] == '/') {
					dir[strlen(dir)-1] = '\0';
				}
				/* if directory exists, brute force it */
				if(verify_dir(dir)) {
					brute_dir(dir);
				}
			}
		}
	}
}


int main(int argc, char *argv[]) {

	char ch;
	char *dir=NULL;
	char *infile=NULL;

	if(argc < 2)
		usage(argv[0]);

	while((ch = getopt(argc, argv, "d:s:e:l:i:rv")) != -1) {
		switch(ch) {
			case 'd':
				dir = optarg;
				break;
			case 's':
				start = atoi(optarg);
				if(start <= 0 || start > 255) {
					fprintf(stderr, "invalid start value.. exiting\n");
					exit(-1);
				}
				break;
			case 'e':
				end = atoi(optarg);
				if(end < start || end <= 0 || end > 255) {
					fprintf(stderr, "invalid end value.. exiting\n");
					exit(-1);
				}
				break;
			case 'i':
				infile = optarg;
				break;
			case 'l':
				logfile = optarg;
				log = 1;
				break;
			case 'r':
				recursive = 1;
				break;
			case 'v':
				verbose = 1;
				break;
		}
	}
	argc -= optind;
	argv += optind;

	printf("\ndirbx -- by dmuz and methodic -- AngryPacket Security\n\n");

	if(dir && infile) {
		fprintf(stderr, "don't you think its foolish to supply both a directory and infile?\n");
		exit(-1);
	}

	if(infile) {
		parse_infile(infile);
	} else {
		if(dir == NULL) {
			fprintf(stderr, "no directory specified to brute-force.. exiting\n");
			exit(-1);
		} else {
			/* clean up cruft */
			while(dir[strlen(dir)-1] == '\n' || dir[strlen(dir)-1] == '/') {
				dir[strlen(dir)-1] = '\0';
			}
			if(verify_dir(dir)) {
				brute_dir(dir);
			}
		}
	}

	printf("\ndirbx finished -- visit http://sec.angrypacket.com for more l33tness\n");

	return(0);

}
