#include #include #include #include #include #include /* Compilation against libplaton library: gcc -pedantic -L ../../platon/ -I ../../ -o md5scan md5scan.c -lplaton */ #define BUFSIZE 1000 #define MAX_PASSWORDS 200 #define compute_and_check(__buf) \ compute_md5(md5str, __buf); \ check_passwords(md5str, __buf); #define compute_md5(__md5, __buf) \ MD5Init(&context); \ MD5Update(&context, __buf, pw_len); \ MD5Final(__md5, &context); #define check_passwords(__md5, __plain) \ for (j = 0; j < pw_cnt; j++) { \ if (! memcmp(passwords[j], __md5, 16)) { \ printf("Found: MD5('%s') = '", __plain); \ for (k = 0; k < 16; k++) { \ printf("%02x", (unsigned char ) md5str[k]); \ } \ printf("', username: %s\n", usernames[j]); \ } \ } int main(int argc, char **argv) /* {{{ */ { MD5_CTX context; char usernames[MAX_PASSWORDS][32]; char passwords[MAX_PASSWORDS][16]; char buf[BUFSIZE], buf2[BUFSIZE]; char *ptr, md5str[16]; FILE *f; int pw_len, buf_base; register int i, j, k, pw_cnt, line, feature; long int cnt; int feature_have_some_uppercase; if (argc <= 2) { printf("Usage: %s ... \n", argv[0]); return 1; } if ((f = fopen(argv[1], "r")) == NULL) { printf("Cannot open password file '%s'.\n", argv[i]); return 2; } printf("[%02d/%02d] Loading passwords from '%s'...\n", 1, argc - 1, argv[1]); for (line = 0, pw_cnt = 0; fgets(buf, BUFSIZE - 1, f) != NULL; line++) { buf[BUFSIZE-1] = '\0'; str_trim(buf); if (strlen(buf) <= 0) { printf(" Skipping empty line %d, continuing on next...\n", line + 1); continue; } for (ptr = buf; ptr - buf != 32; ptr += 2) { if (! isxdigit(ptr[0]) || !isxdigit(ptr[1])) { printf("Bad input on line %d: %s\n", line + 1, buf); return 4; } sscanf(ptr, "%2x", md5str + (ptr - buf) / 2); } if (i >= MAX_PASSWORDS) { printf("Sorry MAX_PASSWORDS reached, cannot continue. Recompilation required.\n"); return 8; } str_trim(ptr); memcpy(passwords[pw_cnt], md5str, 16); memcpy(usernames[pw_cnt], ptr, 31); usernames[pw_cnt][31] = '\0'; pw_cnt++; } printf(" Loading passwords finished, %d passwords loaded from %d lines.\n", pw_cnt, line); if (pw_cnt == 0) { printf("No passwords in password file."); return 16; } for (i = 2; i < argc; i++) { printf("[%02d/%02d] Processing word list '%s'...\n", i, argc - 1, argv[i]); if ((f = fopen(argv[i], "r")) == NULL) { printf("Cannot open word list file '%s'. File skipped.\n", argv[i]); continue; } for (cnt = 0; fgets(buf, BUFSIZE - 1, f) != NULL; ) { pw_len = strlen(buf); if (pw_len >= BUFSIZE) { printf("WARNING: too long password on the input (%d)\n", pw_len); continue; } str_trim(buf); pw_len = strlen(buf); if (! pw_len) { continue; } cnt++; /* Features: * - plain * - reverse string * - lowercase * - lowercase capitalize first * - capitalize first * - append 1 digit * - append 1 digits */ for (feature_have_some_uppercase = 0, j = 0; j < pw_len; j++) { if (isupper(buf[j])) { feature_have_some_uppercase = 1; break; } } /* Feature: plain */ compute_and_check(buf); if (islower(buf[0])) { /* Feature: ucfirst */ k = buf[0]; buf[0] = toupper(buf[0]); compute_and_check(buf); buf[0] = k; } if (feature_have_some_uppercase) { /* Feature: lowercase */ strncpy(buf2, buf, BUFSIZE); strtolower(buf2); compute_and_check(buf2); if (islower(buf2[0])) { /* Feature: lowercase & ucfirst */ buf2[0] = toupper(buf2[0]); compute_and_check(buf2); } } /* Feature: reverse */ strncpy(buf2, buf, BUFSIZE); strrev(buf2); compute_and_check(buf2); if (islower(buf2[0])) { /* Feature: reverse & ucfirst */ k = buf2[0]; buf2[0] = toupper(buf2[0]); compute_and_check(buf2); buf2[0] = k; } if (feature_have_some_uppercase) { /* Feature: reverse & lowercase */ strtolower(buf2); compute_and_check(buf2); if (islower(buf2[0])) { /* Feature: reverse & lowercase & ucfirst */ buf2[0] = toupper(buf2[0]); compute_and_check(buf2); } } } printf(" %ld passwords checked.\n", cnt); fclose(f); } return 0; } /* }}} */ /* Modeline for ViM {{{ * vim: set ts=4: * vim600: fdm=marker fdl=0 fdc=3: * }}} */