|
/* Namescan, DNS mapping system v1.2 Bloodmask 1998 */ #include <stdio.h> #include <unistd.h> #include <signal.h> #include <stdlib.h> #include <sys/wait.h> #include <sys/timeb.h> #include <sys/time.h> #include <sys/types.h> #include <sys/param.h> #include <sys/stat.h> #include <string.h> #include <fcntl.h> #include <setjmp.h> #define CHILD_NAME "namescan" #define ROOTTIMEOUT 120 #define USLEEP 100000 #define DEFTIMEOUT 15 #define DEFCONNECTIONS 5 #define FILENAME "%s.query" #define MERGENAME "%s.scan" #define DEEPNAME "deep" #define MAXSYSBUF 128 #define MAXFILEBUF 80 #define MAXDOMAINBUF 80 #define TEMPDIR "/var/tmp/" #define TEMPSIZE 8 #define OK 1 #define FAILED 0 #ifdef PASSWORD_PROTECTED #ifndef EXECPASSWORD #define EXECPASSWORD "ZFsZvwzEp7oBc" #endif #endif #define COASTCLEAR 120 int options; #define F_TIMEOUT 0x002 #define F_PARANOID 0x004 #define F_BACKGROUND 0x008 #define F_DEEPSCAN 0x010 #define F_HOSTNAMES 0x020 #define HASADDRESS "has address " int quite; int timeout; jmp_buf env; void handleargs(int argc, char **argv, char *hostname); int paranoid_coastclear(void); int paranoid_lookout(void); int findslot(int pid); void free_children(void); void sigchld_handler(int sig); void sigalrm_handler(int sig); void ignore_signals(void); char *Strip(char *String); int QueryDomain(char *Domain, char *Filename, int maxtimeout); int ElaborateSCAN(char *Filename, int argc, char **argv); long GetRandom(long Minimum, long Maximum); char *GetTemp(void); void Clean(char *String, int bytes); void usage(void); int Format(char *Filename_src, char *Filename_dst, int mode); #ifdef PASSWORD_PROTECTED int VerifyKEY(char *Accesskey); #endif void go_background(void); int Linkregions(int argc, char **argv); int addip(char *ip, char *Filename); struct regionlist { struct regionlist *next, *last; char *region; } *rootregion = NULL; struct tree_node { char *string; struct tree_node *left; struct tree_node *right; }; int dump_tree(struct tree_node *tree, FILE *dump); int insert_string(struct tree_node **tree, char *string); int free_tree(struct tree_node **tree); long jump; int *pids; int free_slots, connections; int paranoid_secs; int main(int argc, char **argv) { int Count; int option; int runloop; char *Sysbuf; char *Filename; char *password; char *Domainlist; FILE *Resultsfp; FILE *Domainlistfp; struct regionlist *loop_region; timeout = DEFTIMEOUT; connections = DEFCONNECTIONS; options = quite = runloop = jump = 0; #ifdef PASSWORD_PROTECTED password = getpass("Password: "); if(!VerifyKEY(password)) exit(0); #endif while( (option = getopt(argc, argv, "P:j:c:t:D:HMBQh")) != EOF) switch(option) { case 'H' : options |= F_HOSTNAMES; break; case 'j' : jump = atol(optarg); if(jump < 1) { fprintf(stderr, "Error: %s Invalid number of systems\n", optarg); exit(1); } break; case 't' : timeout = atoi(optarg); if(timeout < 1) { fprintf(stderr, "Error: %s invalid timeout\n", optarg); exit(1); } options |= F_TIMEOUT; break; case 'c' : connections = atoi(optarg); if(connections < 1) { fprintf(stderr, "Error: %s invalid connections\n", optarg); } break; case 'D' : Domainlist = (char *) malloc(strlen(optarg)+1); strcpy(Domainlist, optarg); options |= F_DEEPSCAN; break; case 'Q' : quite++; break; case 'B' : options |= F_BACKGROUND; break; case 'P' : options |= F_PARANOID; paranoid_secs = atoi(optarg); break; default : usage(); } if( options & F_BACKGROUND ) { go_background(); quite = 2; } Filename = (char *) malloc(MAXFILEBUF); if( options & F_DEEPSCAN ) { ElaborateSCAN(Domainlist, argc, argv); exit(0); } argc -= optind; argv += optind; if(argc < 1) usage(); Linkregions(argc, argv); argc += optind; argv -= optind; for(loop_region = rootregion; loop_region != NULL; loop_region = loop_region -> next) { sprintf(Filename, FILENAME, loop_region -> region); if(!QueryDomain(loop_region -> region, Filename, ROOTTIMEOUT)) { if( quite < 2 ) fprintf(stderr, "Error: Couldn't lookup root domain [%s]\n", loop_region -> region); continue; } else if( quite < 2 ) fprintf(stderr, "Successfully looked up root domain [%s]\n", loop_region -> region); if(!ElaborateSCAN(Filename, argc, argv)) continue; if( quite < 2 ) fprintf(stderr, "Finished querying root domain [%s]\n", loop_region -> region); } } int Linkregions(int argc, char **argv) { int Count; struct regionlist *loop_region; struct regionlist *tmpregion; for(Count = 0; Count<argc; Count++) { tmpregion = (struct regionlist *) malloc(sizeof(struct regionlist)); tmpregion -> region = (char *) malloc(MAXDOMAINBUF); strncpy(tmpregion -> region, argv[Count], MAXDOMAINBUF - 1); tmpregion -> next = rootregion; if(rootregion != NULL) rootregion -> last = tmpregion; tmpregion -> last = NULL; rootregion = tmpregion; } return OK; } char *Strip(char *String) { char *S_CH; if((S_CH = strchr(String, (int) '\r')) != NULL) *S_CH = '\0'; if((S_CH = strchr(String, (int) '\n')) != NULL) *S_CH = '\0'; return String; } long GetRandom(long Minimum, long Maximum) { long RandomNumber; struct timeb tp; ftime(&tp); srand(tp.millitm); RandomNumber = Minimum + (long) ( (float) (Maximum - Minimum) * random()/(RAND_MAX+1.0) ); return RandomNumber; } char *GetTemp(void) { int Count; char *Filename, *Directory; char *O_Ch, *D_Ch; Filename = (char *) malloc(80); bzero((char *)Filename, 80); sprintf(Filename, "%s", TEMPDIR); O_Ch = Filename + strlen(Filename); for( Count = 0; Count<TEMPSIZE; Count++) { usleep(GetRandom(10, 20) * 10); switch(GetRandom(1, 3)) { case 1 : *O_Ch = GetRandom( (int) 'a', (int) 'z' ); O_Ch++; break; case 2 : *O_Ch = GetRandom( (int) 'A', (int) 'Z' ); O_Ch++; break; case 3 : *O_Ch = GetRandom( (int) '0', (int) '9' ); O_Ch++; break; } } return Filename; } void Clean(char *String, int bytes) { bzero((char *)String, bytes); } int QueryDomain(char *Domain, char *Filename, int maxtimeout) { int pid, child_pid, child_status; char *Temp = GetTemp(); struct stat dummy; if(!(pid = fork())) { freopen(Temp, "w", stdout); freopen("/dev/null", "w", stderr); execl("/usr/bin/host", "/usr/bin/host", "-l", Domain, NULL); fclose(stdout); exit(1); } else if( pid != -1 ) { signal(SIGALRM, sigalrm_handler); alarm(maxtimeout); if(!setjmp(env)) { for(;;) { if(stat(Temp, &dummy) < 0) continue; if(dummy.st_size > 0) break; if((child_pid = waitpid(pid, &child_status, WNOHANG)) != -1 ) if( WIFEXITED(child_status) || WIFSIGNALED(child_status) ) break; usleep(USLEEP); } alarm(0); } else { unlink(Temp); kill(pid, 9); waitpid(pid, &child_status, 0); return FAILED; } waitpid(pid, &child_status, 0); Format(Temp, Filename, 1); unlink(Temp); free(Temp); return OK; } if(quite < 2) fprintf(stderr, "Error: Couldn't fork\n"); return FAILED; } void usage(void) { fprintf(stderr, "usage: namescan [-options] root-domain[s]\n" "Options:\n" "\t-Q\t\t\tQuite mode\n" "\t-B\t\t\tSnap into background\n" "\t-P paranoid_secs\t\tSet delay between paranoid lookouts\n" "\t-t timeout\t\tDNS Timeout\n" "\t-c connections\t\tConnections per batch\n" "\t-j entries\t\tNumber of entries to jump\n" "\t-D domain.scan\t\tScan previous results one level deeper\n"); exit(1); } void go_background(void) { if(fork()) exit(0); } int ElaborateSCAN(char *Filename, int argc, char **argv) { int i, ploop, Count; int pid, slot; long line_number; char *Domain, *Results, *F_CH; char *Mergename; FILE *Resultsfp; Mergename = (char *) malloc(MAXDOMAINBUF); Results = (char *) malloc(MAXDOMAINBUF); Domain = (char *) malloc(MAXDOMAINBUF); Domain[MAXDOMAINBUF - 1] = '\0'; pids = (int *) malloc(connections*sizeof(int)); for(i = 0; i<connections; i++) pids[i] = -1; free_slots = connections; if( !(Resultsfp = fopen(Filename, "rt")) ) { if( quite < 2 ) fprintf(stderr, "Error: unable to read from `%s'\n", Filename); return FAILED; } strcpy(Mergename, Filename); strcpy(Results, FILENAME); F_CH = strstr(Mergename, &Results[2]); if(F_CH != NULL) { strcpy(Results, MERGENAME); sprintf(F_CH, "%s", &Results[2]); } else strcat(Mergename, DEEPNAME); for(Count = 0; Count<jump; Count++) if( fgets(Domain, MAXDOMAINBUF - 1, Resultsfp) == NULL ) { fprintf(stderr, "Error: Jump parameters out of bounds\n"); exit(0); } ploop = line_number = 0; signal(SIGCHLD, sigchld_handler); while( fgets(Domain, MAXDOMAINBUF - 1, Resultsfp) != NULL ) { line_number++; Strip(Domain); #ifdef DEBUG fprintf(stderr, "DEBUG: Handling `%s' from domainlist\n", Domain); #endif if(inet_addr(Domain) != -1) { addip(Domain, Mergename); continue; } repeat: while( !free_slots ) { #ifdef DEBUG fprintf(stderr, "DEBUG: In the while loop, free_slots = %d\n", free_slots); #endif free_children(); usleep(USLEEP); if( options & F_PARANOID ) if(!(ploop = (ploop+1)%((paranoid_secs*1000000)/USLEEP))) { if(paranoid_lookout()) { line_number -= connections; rewind(Resultsfp); for(i = 0; i<line_number; i++) if(!fgets( Domain, MAXDOMAINBUF - 1, Resultsfp )) break; } } } if((slot = findslot(-1)) < 0) goto repeat; switch((pid = fork())) { case 0 : ignore_signals(); handleargs(argc, argv, Domain); if(!QueryDomain(Domain, Mergename, timeout) && quite < 1) fprintf(stderr, "Failed querying domain [%s]\n", Domain); else if(quite < 1) fprintf(stderr, "Successfully queried domain [%s]\n", Domain); exit(getpid() & 0xFF); default : free_slots--; pids[slot] = pid; #ifdef DEBUG fprintf(stderr, "DEBUG: new_proc, pid %d, domain %s\n", pid, Domain); #endif } } #ifdef DEBUG fprintf(stderr, "DEBUG: Finished extending domains\n"); #endif while( free_slots < connections ) { free_children(); sleep(USLEEP); if( options & F_PARANOID ) if(!(ploop = (ploop+1)%((paranoid_secs*1000000)/USLEEP))) paranoid_lookout(); } fclose(Resultsfp); Clean(Domain, MAXDOMAINBUF); free(Domain); Clean((char *)pids, sizeof(int) * connections); free(pids); unlink(Filename); Format(Mergename, Filename, 0); unlink(Mergename); return OK; } void free_children(void) { int slot, child_pid, child_status; for(slot = 0; slot<connections; slot++) { if(pids[slot] != -1) if((child_pid = waitpid(pids[slot], &child_status, WNOHANG)) != -1) if((WIFEXITED(child_status) && WEXITSTATUS(child_status) == (pids[slot] & 0xFF)) || (WIFSIGNALED(child_status) && WTERMSIG(child_status) == SIGKILL) ) { free_slots++; #ifdef DEBUG fprintf(stderr, "DEBUG: free_slots = %d\n", free_slots); fprintf(stderr, "DEBUG: free'd pid %d\n", pids[slot]); #endif pids[slot] = -1; } } } int Format(char *Filename_src, char *Filename_dst, int mode) { char *Line, *Address, *Pointer; FILE *SRC, *DST; struct tree_node *tree = NULL; Line = (char *) malloc(80); Address = (char *) malloc(80); bzero((char *)Address, sizeof(Address)); bzero((char *)Line, sizeof(Line)); if(!(SRC = fopen(Filename_src, "rt"))) return FAILED; if(!(DST = fopen(Filename_dst, "at"))) return FAILED; while( fgets(Line, 79, SRC) != NULL ) { if( mode && (Pointer = strstr(Line, HASADDRESS)) != NULL ) { Pointer += strlen(HASADDRESS); sscanf(Pointer, "%s", Address); } else sscanf(Line, "%s", Address); if(!mode) Strip(Address); insert_string(&tree, Address); } dump_tree(tree, DST); free_tree(&tree); free(Line); free(Address); fclose(DST); fclose(SRC); } int insert_string(struct tree_node **tree, char *string) { int rc; struct tree_node *tmp; if(*tree == NULL) { tmp = (struct tree_node *)malloc(sizeof(struct tree_node)); bzero((struct tree_node *)tmp, sizeof(struct tree_node)); tmp->string = (char *)malloc(strlen(string)+1); strcpy(tmp->string, string); *tree = tmp; return OK; } rc = strcmp(string, (*tree)->string); if(rc<0) insert_string(&((*tree)->left), string); else if(rc>0) insert_string(&((*tree)->right), string); return OK; } int dump_tree(struct tree_node *tree, FILE *WRITE) { if(tree != NULL ) { dump_tree(tree -> left, WRITE); fprintf(WRITE, "%s\n", tree -> string); dump_tree(tree -> right, WRITE); } return OK; } int free_tree(struct tree_node **tree) { if( *tree != NULL ) { free_tree(&(*tree)->left); free_tree(&(*tree)->right); free((*tree)->string); free(*tree); } } int addip(char *IP, char *Filename) { FILE *WRITE; if(!(WRITE = fopen(Filename, "at"))) return FAILED; fprintf(WRITE, "%s\n", IP); fclose(WRITE); return OK; } void sigalrm_handler(int sig) { signal(SIGALRM, SIG_IGN); alarm(0); longjmp(env, 1); } void sigchld_handler(int sig) { int slot, child_pid, child_status; if((child_pid = wait(&child_status)) != -1) { if( (WIFEXITED(child_status) && WEXITSTATUS(child_status) == (child_pid & 0xFF)) || (WIFSIGNALED(child_status) && WTERMSIG(child_status) == SIGKILL)) { waitpid(child_pid, &child_status, WNOHANG); if( (slot = findslot(child_pid)) != -1 ) { free_slots++; pids[slot] = -1; } #ifdef DEBUG fprintf(stderr, "DEBUG: caught sigchld from pid %d, free_slots = %d\n", child_pid, free_slots); #endif } } signal(SIGCHLD, sigchld_handler); } void ignore_signals(void) { int i; for( i = 1; i<=31; i++ ) signal(i, SIG_IGN); } int findslot(int pid) { int i; for(i = 0; i<connections; i++) if(pids[i] == pid) return i; return -1; } void handleargs(int argc, char **argv, char *Hostname) { int i = 1; if( !(options & F_PARANOID) ) sprintf(argv[0], "%s (%s)", CHILD_NAME, Hostname); else i = 0; for(; i<argc; i++) argv[i][0] = '\0'; } int paranoid_coastclear(void) { struct stat dummy; char *filename; const char *cpa, *cpb; const char tty[] = "/dev/tty"; const char pty[] = "pqrS"; const char order[] = "0123456789abcdef"; filename = alloca(strlen(tty) + 3); strcpy(filename, tty); filename[strlen(tty) + 1] = '\0'; /* check console terminals */ for(cpa = order; *cpa; cpa++) { filename[strlen(tty)] = *cpa; if( stat(filename, &dummy) < 0 ) break; if( (time(NULL) - dummy.st_atime) < COASTCLEAR ) return 0; } /* check non-consoles */ filename[strlen(tty) + 2] = '\0'; for(cpa = pty; *cpa; cpa++) { filename[strlen(tty)] = *cpa; for(cpb = order; *cpb; cpb++) { filename[strlen(tty) + 1] = *cpb; if( stat(filename, &dummy) < 0 ) break; if( (time(NULL) - dummy.st_atime) < COASTCLEAR ) return 0; } } return 1; } int paranoid_lookout(void) { int i; #ifdef DEBUG fprintf(stderr, "DEBUG: paranoid_lookout called\n"); #endif if(!paranoid_coastclear()) { #ifdef DEBUG fprintf(stderr, "DEBUG: PARANOID mode activated\n"); #endif for(i = 0; i<connections; i++) if(pids[i] != -1) kill(pids[i], SIGKILL); while(free_slots < connections) { usleep(USLEEP); free_children(); } sleep(COASTCLEAR); while( !paranoid_coastclear() ) { #ifdef DEBUG fprintf(stderr, "DEBUG: coastclear returned 0, staying stealthy\n"); #endif sleep(paranoid_secs); } #ifdef DEBUG fprintf(stderr, "DEBUG: PARANOID mode deactivated\n"); #endif DEBUG return 1; } return 0; } #ifdef PASSWORD_PROTECTED int VerifyKEY(char *Accesskey) { int rv; char *CryptKEY, *CryptCODE; char Salt[2]; CryptKEY = EXECPASSWORD; Salt[0] = CryptKEY[0]; Salt[1] = CryptKEY[1]; CryptCODE = crypt(Accesskey, Salt); rv = strncmp(CryptKEY, CryptCODE, 13); if( !rv ) return OK; return FAILED; } #endif