u_char cisco_decrypt(void) { u_char retval; time_t start, stop; tty_init(); time(&start); /* check if the arg is a valid md5 cisco IOS password */ if (cisco_is_ios_md5crypt(usr_opt.decryptopt.cipher)) cipher_engine = cisco_ios_cipher; /* check if the arg is a valid md5 PIX password */ else if (cisco_is_pix_md5crypt(usr_opt.decryptopt.cipher)) cipher_engine = cisco_pix_cipher; else tty_error(ERR_USAGE, "neither a Cisco IOS nor a PIX password -- `%s'", usr_opt.decryptopt.cipher); retval = (usr_opt.action == decrypt_wl || usr_opt.action == resume_wl) ? wordlist() : bruteforce(); time(&stop); if (usr_opt.verbose) tty_message("scan time: %g second(s)\n\n", difftime(stop, start)); return retval; }
static void opt_check(int * opt_set) { /* *INDENT-OFF* */ /* error table (0 means `ok', 1 means `illegal option pair') */ static const char *opt_table[] = { /* csedypbwlDrLhqvV */ /* c */ "", /* crypt-ios */ /* s */ "0", /* salt */ /* e */ "01", /* egd */ /* d */ "011", /* dev-random */ /* y */ "0111", /* sys-rand */ /* p */ "11111", /* crypt-pix */ /* b */ "111111", /* bruteforce */ /* w */ "1111111", /* dictionary */ /* l */ "11111100", /* length */ /* D */ "111111000", /* daemonize */ /* r */ "1111111110", /* restore */ /* L */ "11111111111", /* license */ /* h */ "111111111111", /* help */ /* q */ "0000000001011", /* quiet */ /* v */ "00000000010111", /* verbose */ /* V */ "111111111111111" /* version */ }; /* *INDENT-ON* */ int row, col; for (row = 0; row < opt_last; row++) { /* the matrix `opt_table' is symmetric */ for (col = 0; col < row; col++) { if (*(opt_table[row] + col) == '1' && opt_set[row] && opt_set[col]) tty_error(ERR_USAGE, "`%s' and `%s' belong to different contexts", longopts[row].name, longopts[col].name); } } }
void tty_run() { // FIXME tty_cwd = malloc(sizeof(char) * MAX_PATH_LENGTH); tty_print_startup(); while (TRUE) { // XXX: how do we ensure, we do not read more than 1025 characters? char line[MAX_PATH_LENGTH + 1] = { '\0' }; char* tokens; char cmd[64]; int rc; BOOLEAN background = FALSE; // print prefix tty_print_prefix(); // read one line // TODO ([email protected]) read from serial device // this has to be a system call in the end since we move this to // a user mode application // rc = scanf("%1024[^\n]%*[^\n]", line); // rc = serial_getline(line, 1024); // print("command: "); rc = tty_getline(line, MAX_PATH_LENGTH); if (rc <= 1) { print("\r"); continue; } print("\r\n"); // print("your command: "); // // line[MAX_PATH_LENGTH] = 0; // print(line); // print("\r\n"); // if (rc == EOF) { // // TODO ([email protected]) line was already at EOF while trying to get // // the first character // } else if (rc == 0) { // // TODO ([email protected]) the user entered an empty line // } // TODO ([email protected]) getchar(), feof() and ferror() have to be // changed to use our serial device - I have no idea how to do that // in the end we need a system call to get this done since we need to // move the TTY to the user space //if (!feof(stdin) && !ferror(stdin)) getchar(); // split input string into tokens tokens = strtok(line, SPLIT_CHARS); strcpy(cmd, tokens); //cmd = tokens; //tokens = strtok(NULL, SPLIT_CHARS); // XXX: built in CMDs are for test only; later each built in CMD will get // an own binary file // // check for a built in command // if (strcmp(cmd, "cd") == 0) { // tty_cmd_cd(tokens); // // } else if (strcmp(cmd, "pwd") == 0) { // tty_cmd_pwd(); // // } else if (strcmp(cmd, "ls") == 0) { // tty_cmd_ls(tokens); // // } else if (strcmp(cmd, "cat") == 0) { // tty_cmd_cat(tokens); // // // finally, is there a application with the entered name? // } else // TODO if there is a & at the end of the command, the tty_find_binary returns false // run a new process if (cmd[strlen(cmd) - 1] == START_IN_BACKGROUND_SYSMBOL) { background = TRUE; cmd[strlen(cmd) -1] = '\0'; } if (!tty_find_binary(cmd)) { char* debug = malloc(sizeof(char) * 256); sprintf(debug, "%s command not found", line); tty_error(debug); free(debug); continue; } { char* tmp_cmd = NULL; tmp_cmd = malloc(sizeof(char) * (strlen(cmd) + strlen(BIN_DIRECTORY) + 1)); sprintf(tmp_cmd, "%s/%s", BIN_DIRECTORY, cmd); tty_start_process(tmp_cmd, tokens, background); free(tmp_cmd); } } }
static u_char bruteforce(void) { u_char salt[MD5_SALT_SIZE], *plaintext; #if defined(HAVE_TERMIOS_H) && defined(HAVE_DEV_TTY) char ch; #endif char **alphabet; int *chposi, *vsize, i, j; #if defined (HAVE_WORKING_FORK) FILE *fout; #endif /* initialize data */ strncpy((char *) salt, (char *) (usr_opt.decryptopt.cipher + MD5_MAGIC_SIZE), MD5_SALT_SIZE); plaintext = zmem_alloc(MAX_PLAIN_SIZE + 1); if (usr_opt.action != resume_bf) chpos = zmem_alloc(MAX_PLAIN_SIZE * sizeof(*chpos)); chpos_safe = zmem_alloc(MAX_PLAIN_SIZE * sizeof(*chpos_safe)); vsize = zmem_alloc(MAX_PLAIN_SIZE * sizeof(*vsize)); /* set the alphabet(s) used reading/parsing the relate argv */ alphabet = zmem_alloc(MAX_PLAIN_SIZE * sizeof(*alphabet)); /* option `-b' with no `regexpr' set */ if (!usr_opt.decryptopt.regexpr) usr_opt.decryptopt.regexpr = str_alloc_copy(ALPHABET_FULL); regex_explode(alphabet, usr_opt.decryptopt.regexpr, &usr_opt.decryptopt.fromlen, &usr_opt.decryptopt.tolen); if (usr_opt.action == resume_bf) { for (i = 0; i < usr_opt.decryptopt.tolen; i++) { vsize[i] = strlen(alphabet[i]); if (chpos[i] > vsize[i]) tty_error(ERR_INFO_RFILE, "illegal `chpos' value load from restore file"); } /* no errors in the restore file, so it can be safely removed here */ if (remove(usr_opt.decryptopt.restore_file) == -1) tty_warning("cannot remove the file `%s'", usr_opt.decryptopt.restore_file); } else { actual_len = usr_opt.decryptopt.fromlen; for (i = 0; i < usr_opt.decryptopt.tolen; i++) { chpos[i] = chpos_safe[i] = 0; vsize[i] = strlen(alphabet[i]); } } if (usr_opt.verbose) { /* some infos, just to let the user check the input entered */ tty_message("trying to crack : \"%s\"\n" "method used : bruteforce\n" "password scheme : ", usr_opt.decryptopt.cipher); tty_message("%s %s\n", usr_opt.decryptopt.regexpr, !strcmp(usr_opt.decryptopt.regexpr, ALPHABET_FULL) ? "(full search)" : ""); if (usr_opt.verbose > 2) { tty_message("expanded password scheme :\n"); i = 0; while (i < usr_opt.decryptopt.tolen) { for (j = i + 1; j < usr_opt.decryptopt.tolen && alphabet[j] == alphabet[i]; j++); if (j - 1 > i) { tty_message(" p[%d..%d] = \"%s\"\n", i, j - 1, alphabet[i]); i = j; } else { tty_message(" p[%d] = \"%s\"\n", i, alphabet[i]); i++; } } } tty_message("length of strings : "); if (usr_opt.decryptopt.fromlen != usr_opt.decryptopt.tolen) tty_message("[%d..%d]\n", usr_opt.decryptopt.fromlen, usr_opt.decryptopt.tolen); else tty_message("%d\n", usr_opt.decryptopt.fromlen); if (usr_opt.action == resume_bf) tty_message("\nrestoring session stopped on %s\n", usr_opt.decryptopt.saved_date); tty_message("\nplease wait... "); #if defined(HAVE_TERMIOS_H) && defined(HAVE_DEV_TTY) tty_message("\n[type <ENTER> to display the current plaintext] "); #endif } /* initialize the first plaintext to be used */ for (i = 0; i < actual_len; i++) plaintext[i] = alphabet[i][chpos[i]]; while (1) { #if defined(HAVE_TERMIOS_H) && defined(HAVE_DEV_TTY) if (read(tty_fd, &ch, 1) > 0 && usr_opt.verbose) tty_message("%s", plaintext); #endif #if 0 /* begin of DEBUG CODE */ fprintf(stderr, "\n%s\n", plaintext); for (i = 0; i < usr_opt.decryptopt.tolen; i++) fprintf(stderr, "chpos[%d] = %d\n", i, chpos[i]); fflush(stderr); /* end of DEBUG CODE */ #endif if (!strcmp((cipher_engine == cisco_ios_cipher ? cisco_ios_crypt(plaintext, salt) : cisco_pix_crypt(plaintext)) + MD5_PREAMBLE_SIZE, (char *) (usr_opt.decryptopt.cipher + MD5_PREAMBLE_SIZE))) { #if defined(HAVE_WORKING_FORK) if (usr_opt.daemonize) { if ((fout = fopen(SCORE_FILE, "a"))) { fprintf(fout, "** FOUND: \"%s\" (%s)\n", plaintext, usr_opt.decryptopt.cipher); fclose(fout); } } else #endif tty_message(usr_opt.verbose ? "\n** FOUND: \"%s\"\n" : "%s\n", plaintext); i = 0; while (i < actual_len) { mem_free(alphabet[i++]); /* skip the duplicates alphabets */ while (alphabet[i] == alphabet[i - 1]) i++; } return SUCCESS; } /* if `++chpos[i] % vsize[i]' is zero then all the letters of * `alphabet[i]' has been checked, so skip to the previous * letter (`i--') of `plaintext' */ i = 0; memcpy(chpos_safe, chpos, MAX_PLAIN_SIZE * sizeof(*chpos_safe)); do { chposi = chpos + i; *chposi = ++(*chposi) % vsize[i]; plaintext[i] = alphabet[i][*chposi]; } while (++i != actual_len && !*chposi); if (i == actual_len && !chpos[actual_len - 1]) { if (actual_len++ == usr_opt.decryptopt.tolen) { #if defined (HAVE_WORKING_FORK) if (usr_opt.daemonize) { if ((fout = fopen(SCORE_FILE, "a"))) { fprintf(fout, "** FAILURE: (%s)\n" " password scheme : %s\n" " length of strings : [%d..%d]\n", usr_opt.decryptopt.cipher, usr_opt.decryptopt.regexpr, usr_opt.decryptopt.fromlen, usr_opt.decryptopt.tolen); fclose(fout); } } else #endif tty_message("\n** FAILURE: the cipher string doesn't " "match the password scheme you set\n"); i = 0; while (i < actual_len) { mem_free(alphabet[i++]); /* skip the duplicates alphabets */ while (alphabet[i] == alphabet[i - 1]) i++; } return FAILURE; } tty_message("\n** NOTE: switching to lenght `%ld', " "please wait... ", actual_len); plaintext[actual_len - 1] = alphabet[actual_len - 1][0]; } } }
static u_char wordlist(void) { FILE *wfile; #if defined (HAVE_WORKING_FORK) FILE *fout; #endif u_char salt[MD5_SALT_SIZE], len; #if defined(HAVE_TERMIOS_H) && defined(HAVE_DEV_TTY) char ch; #endif bool seekpoint_found = false; if ((wfile = fopen(usr_opt.decryptopt.wordlist, "rt")) == NULL) tty_error(ERR_IO_FILE, "error opening `%s' : %s", usr_opt.decryptopt.wordlist, strerror(errno)); strncpy((char *) salt, (char *) (usr_opt.decryptopt.cipher + MD5_MAGIC_SIZE), MD5_SALT_SIZE); if (usr_opt.action != resume_wl) { if (!usr_opt.decryptopt.fromlen) /* not set by the user */ usr_opt.decryptopt.fromlen++; if (!usr_opt.decryptopt.tolen) /* not set by the user */ usr_opt.decryptopt.tolen = MAX_PLAIN_SIZE; } if (usr_opt.verbose) { /* some infos, just to let the user check the input entered */ tty_message("trying to crack : \"%s\"\n" "method used : dictionary\n" "wordlist : %s\n", usr_opt.decryptopt.cipher, usr_opt.decryptopt.wordlist); tty_message("length of strings : "); if (usr_opt.decryptopt.fromlen != usr_opt.decryptopt.tolen) tty_message("[%d..%d]\n", usr_opt.decryptopt.fromlen, usr_opt.decryptopt.tolen); else tty_message("%d\n", usr_opt.decryptopt.fromlen); if (usr_opt.action == resume_wl) tty_message("\nrestoring session stopped on %s\n", usr_opt.decryptopt.saved_date); tty_message("\nplease wait ... "); #if defined(HAVE_TERMIOS_H) && defined(HAVE_DEV_TTY) tty_message("\n[type <ENTER> to dispay the current plaintext used] "); #endif } while (fgets(wbuf, FLINE_BUFSIZE, wfile) != NULL) { /* strip the trail character `\n' */ if (wbuf[(len = strlen(wbuf)) - 1] == '\n') wbuf[--len] = '\0'; /* switch to `seekpoint', if the action is `restore_wf' */ if (!seekpoint_found && (usr_opt.action == resume_wl) && strcmp(seekpoint, wbuf)) continue; else seekpoint_found = true; if (len < usr_opt.decryptopt.fromlen || len > usr_opt.decryptopt.tolen) continue; /* wrong range for length */ #if defined(HAVE_TERMIOS_H) && defined(HAVE_DEV_TTY) if (read(tty_fd, &ch, 1) > 0 && usr_opt.verbose) tty_message("%s", wbuf); #endif if (!strcmp((cipher_engine == cisco_ios_cipher ? cisco_ios_crypt((u_char *) wbuf, salt) : cisco_pix_crypt((u_char *) wbuf)) + MD5_PREAMBLE_SIZE, (char *) (usr_opt.decryptopt.cipher + MD5_PREAMBLE_SIZE))) { #if defined (HAVE_WORKING_FORK) if (usr_opt.daemonize) { if ((fout = fopen(SCORE_FILE, "a"))) { fprintf(fout, "** FOUND: \"%s\" (%s)\n", wbuf, usr_opt.decryptopt.cipher); fclose(fout); } } else #endif tty_message(usr_opt.verbose ? "\n\n** FOUND: \"%s\"\n" : "%s\n", wbuf); return SUCCESS; } } fclose(wfile); #if defined (HAVE_WORKING_FORK) if (usr_opt.daemonize) { if ((fout = fopen(SCORE_FILE, "a"))) { fprintf(fout, "** FAILURE: (%s)\n" " dictionary used : %s\n" " length of strings : [%d..%d]\n", usr_opt.decryptopt.cipher, usr_opt.decryptopt.wordlist, usr_opt.decryptopt.fromlen, usr_opt.decryptopt.tolen); fclose(fout); } } else #endif tty_message("\n\n" "** FAILURE: no match found in the dictionary selected\n" "please, use another dictionary or choose the " "bruteforce attack.\n"); return FAILURE; }
int main(int argc, char **argv) { int i, retval = SUCCESS; #if defined (HAVE_WORKING_FORK) pid_t cpid; FILE *fscore; #endif #if defined (HAVE_ASSERT_H) && defined (SHORT_PASSWORDS) assert(MAX_PLAIN_SIZE < 16); #endif /* set the default values for `usr_opt' */ memset(&usr_opt, 0, sizeof(usr_opt)); usr_opt.verbose = 1; #if defined (DEV_RANDOM_SUPPORT) usr_opt.cryptopt.get_entropy = get_dev_entropy; #elif defined (EGD_SUPPORT) usr_opt.cryptopt.get_entropy = get_egd_entropy; #else usr_opt.cryptopt.get_entropy = get_sys_entropy; #endif opt_parse(argc, argv, &usr_opt); #if defined (HAVE_UMASK) /* set umask for security reasons */ umask(0077); #endif switch (usr_opt.action) { case crypt_ios: case crypt_pix: if (argc != optind + 1) tty_error(ERR_USAGE, "no string to crypt"); usr_opt.cryptopt.plain = (u_char *) str_alloc_copy(argv[optind]); retval = (usr_opt.action == crypt_ios) ? crypt_ios_fe(usr_opt.cryptopt.plain, usr_opt.cryptopt.salt) : crypt_pix_fe(usr_opt.cryptopt.plain); break; case decrypt_bf: case decrypt_wl: if (argc != optind + 1) tty_error(ERR_USAGE, "no password to decrypt"); usr_opt.decryptopt.cipher = (u_char *) str_alloc_copy(argv[optind]); /* no break here! */ case resume: /* if `decrypt_bf', `decrypt_wl', `resume_bf', `resume_wl', * create the restore file in case of an abort event */ save_session_if_signal_abort = true; if (usr_opt.action == resume) { if (argc != optind) tty_error(ERR_USAGE, "bad argument found `%s'", argv[optind]); session_load(usr_opt.decryptopt.restore_file); /* `usr_opt.decryptopt.regexpr' can be NULL, * so we must check `usr_opt.decryptopt.wordlist' */ usr_opt.action = usr_opt.decryptopt.wordlist ? resume_wl: resume_bf; } #if defined (HAVE_WORKING_FORK) if (usr_opt.daemonize) { cpid = fork(); if (cpid == (pid_t) 0) { /* child process */ /* checks the SCORE_FILE format */ fcheck(SCORE_FILE, HEAD_SCORE_TEXT); /* add the line `HEAD_SCORE_TEXT"\n"' at the begin, * if the file do not exists */ if (!(fscore = fopen(SCORE_FILE, "r"))) { fscore = fopen(SCORE_FILE, "w"); fprintf(fscore, HEAD_SCORE_TEXT"\n"); } fclose(fscore); tty_message ("%s -- running in daemon mode" #if defined (HAVE_GETPID) " [pid: %d]" #endif "...\n** WARNING: " "sensible data could be written in the file `%s'!\n", *argv, #if defined (HAVE_GETPID) (int) getpid(), #endif SCORE_FILE); /* point stdin/stdout/stderr to /dev/null */ for (i = 0; i < 3; i++) close(i); i = open(NULL_DEV, O_RDWR); if (i >= 0) { dup2(i, 0); dup2(i, 1); dup2(i, 2); if (i > 2) close(i); } retval = cisco_decrypt(); return retval; } else if (cpid < (pid_t) 0) tty_error(ERR_FORKING, "cannot run in daemon mode : %s", strerror(errno)); else return SUCCESS; /* parent process */ } else #endif retval = cisco_decrypt(); break; default: /* not enought paramethers entered */ tty_error(ERR_USAGE, "nothing to do (?)"); } mem_free_all(); return retval; }
static void opt_parse(int argc, char **argv, t_options *opt) { int argval, n, opt_set[opt_last]; /* initialize `opt_set' with the value 0 (option not used) */ for (n = 0; n < opt_last; n++) opt_set[n] = opt_unset; /* process the options */ opterr = 0; while (1) { argval = getopt_long(argc, argv, optstring, longopts, NULL); if (argval == -1) break; switch (argval) { case 0: break; case 'c': opt_set[opt_c]++; opt->action = crypt_ios; break; case 's': /* set the salt string (4 character long) */ opt_set[opt_s]++; opt->action = crypt_ios; if (strlen(optarg) != MD5_SALT_SIZE) tty_error(ERR_USAGE, "bad length (not %d bytes) for salt `%s'", MD5_SALT_SIZE, optarg); opt->cryptopt.salt = (u_char *) str_alloc_copy(optarg); break; #ifdef EGD_SUPPORT case 'e': opt_set[opt_e]++; opt->cryptopt.get_entropy = get_egd_entropy; if (optarg) opt->cryptopt.egd_path = str_alloc_copy(optarg); break; #endif #ifdef DEV_RANDOM_SUPPORT case 'd': opt_set[opt_d]++; opt->cryptopt.get_entropy = get_dev_entropy; break; #endif #if defined (EGD_SUPPORT) || defined (DEV_RANDOM_SUPPORT) case 'y': opt_set[opt_y]++; opt->cryptopt.get_entropy = get_sys_entropy; break; #endif case 'p': opt_set[opt_p]++; opt->action = crypt_pix; break; case 'l': opt_set[opt_l]++; n = sscanf(optarg, "%d:%d", &opt->decryptopt.fromlen, &opt->decryptopt.tolen); switch (n) { case 0: /* option --length used with no values */ usage(ERR_USAGE); break; case 1: /* only 'fromlen' set */ opt->decryptopt.tolen = opt->decryptopt.fromlen; case 2: if (opt->decryptopt.fromlen > opt->decryptopt.tolen) tty_error(ERR_USAGE, "bad order for `--length' limits"); if (opt->decryptopt.fromlen < 1) tty_error(ERR_USAGE, "illegal downlimit for `--length'"); if (opt->decryptopt.tolen > MAX_PLAIN_SIZE) tty_error(ERR_USAGE, "the `--length' upperlimit exceed `%d'", MAX_PLAIN_SIZE); } break; case 'b': /* try the brute-force attack */ opt_set[opt_b]++; opt->action = decrypt_bf; if (optarg) opt->decryptopt.regexpr = str_alloc_copy(optarg); break; case 'w': /* try the vocabulary attack */ opt_set[opt_w]++; opt->action = decrypt_wl; opt->decryptopt.wordlist = str_alloc_copy(optarg); break; #if defined (HAVE_WORKING_FORK) case 'D': opt_set[opt_D]++; opt->daemonize = 1; break; #endif case 'r': opt_set[opt_r]++; opt->action = resume; /* default rescue file is `RESTORE_FILE' */ opt->decryptopt.restore_file = optarg ? str_alloc_copy(optarg) : str_alloc_copy(RESTORE_FILE); break; case 'q': /* minimize the program output */ opt_set[opt_q]++; opt->verbose = 0; break; case 'h': /* help */ #if 0 opt_set[opt_h]++; #endif usage(SUCCESS); break; case 'v': /* verbose mode */ opt_set[opt_v]++; opt->verbose++; break; case 'L': #if 0 opt_set[opt_L]++; #endif license(); /* GPL license message */ exit(SUCCESS); break; case 'V': /* program name, version, etc. */ #if 0 opt_set[opt_V]++; #endif version(); exit(SUCCESS); break; case '?': tty_error(ERR_USAGE, "ambiguous match or extraneous parameter `%s'", argv[optind - 1]); break; default: /* should catch nothing (?) */ tty_error(ERR_USAGE, "illegal command line argument"); } } /* check for option inconsistences */ opt_check(opt_set); }