/* Offline cracker for PPTP MSCHAP v2 software VPN. Hacked together during * October of 2012 by Dhiru Kholia . * * This software is Copyright (c) 2012, Dhiru Kholia , * and it is hereby released to the general public under the following terms: * Redistribution and use in source and binary forms, with or without modification, * are permitted. * * Input Format : username:$pptp$type$challenge$response$username */ #include "sha.h" #include #include #include "arch.h" #include "misc.h" #include "common.h" #include "formats.h" #include "params.h" #include "options.h" #ifdef _OPENMP static int omp_t = 1; #include #define OMP_SCALE 64 #endif #ifndef uchar #define uchar unsigned char #endif #define FORMAT_LABEL "pptp" #define FORMAT_NAME "PPTP MSCHAPv2 MD4 DES" #define ALGORITHM_NAME "32/" ARCH_BITS_STR #define BENCHMARK_COMMENT "" #define BENCHMARK_LENGTH -1 #define PLAINTEXT_LENGTH 32 #define BINARY_SIZE 24 #define PARTIAL_BINARY_SIZE 8 #define SALT_SIZE 16+2 #define MIN_KEYS_PER_CRYPT 1 #define MAX_KEYS_PER_CRYPT 1 static struct fmt_tests pptp_tests[] = { {"$pptp$1$e3a5d0775370bda51e16219a06b0278f$84c4b33e00d9231645598acf91c384800000000000000000565fe2492fd5fb88edaec934c00d282c046227406c31609b00$scott", "turquoise"}, /* Ettercap generated test vectors below */ {"$pptp$1$E3A5D0775370BDA51E16219A06B0278F$84C4B33E00D9231645598ACF91C384800000000000000000565FE2492FD5FB88EDAEC934C00D282C046227406C31609B00$scott", "turquoise"}, {"$pptp$0$7C00A1A403CA7DF5$565FE2492FD5FB88EDAEC934C00D282C046227406C31609B$scott", "turquoise"}, {NULL} }; static uchar (*saved_plain)[PLAINTEXT_LENGTH + 1]; static int (*saved_len); static uchar (*saved_key)[21]; static uchar (*output)[PARTIAL_BINARY_SIZE]; static uchar *challenge; static int keys_prepared; #include "unicode.h" static void init(struct fmt_main *self) { #ifdef _OPENMP omp_t = omp_get_max_threads(); self->params.min_keys_per_crypt *= omp_t; omp_t *= OMP_SCALE; self->params.max_keys_per_crypt *= omp_t; #endif saved_plain = mem_calloc_tiny(sizeof(*saved_plain) * self->params.max_keys_per_crypt, MEM_ALIGN_NONE); saved_len = mem_calloc_tiny(sizeof(*saved_len) * self->params.max_keys_per_crypt, MEM_ALIGN_WORD); saved_key = mem_calloc_tiny(sizeof(*saved_key) * self->params.max_keys_per_crypt, MEM_ALIGN_NONE); output = mem_alloc_tiny(sizeof(*output) * self->params.max_keys_per_crypt, MEM_ALIGN_WORD); } static int valid(char *ciphertext, struct fmt_main *self) { return !strncmp(ciphertext, "$pptp$", 6); } static inline void setup_des_key(unsigned char key_56[], DES_key_schedule *ks) { DES_cblock key; key[0] = key_56[0]; key[1] = (key_56[0] << 7) | (key_56[1] >> 1); key[2] = (key_56[1] << 6) | (key_56[2] >> 2); key[3] = (key_56[2] << 5) | (key_56[3] >> 3); key[4] = (key_56[3] << 4) | (key_56[4] >> 4); key[5] = (key_56[4] << 3) | (key_56[5] >> 5); key[6] = (key_56[5] << 2) | (key_56[6] >> 6); key[7] = (key_56[6] << 1); DES_set_key(&key, ks); } int gethashlast2(unsigned char* challenge, unsigned char* response, unsigned char*lasthash) { int i; unsigned char zpwhash[7] = { 0, 0, 0, 0, 0, 0, 0 }; unsigned char cipher[8]; DES_key_schedule ks; for (i = 0; i <= 0xffff; i++) { zpwhash[0] = i >> 8; zpwhash[1] = i & 0xff; setup_des_key(zpwhash, &ks); DES_ecb_encrypt((DES_cblock*)challenge, (DES_cblock*)cipher, &ks, DES_ENCRYPT); if (memcmp(cipher, response + 16, 8) == 0) { /* Success in calculating the last 2 of the hash */ lasthash[0]= zpwhash[0]; lasthash[1]= zpwhash[1]; return 0; } } return (1); } static void *get_salt(char *ciphertext) { SHA_CTX ctx; static unsigned char binary_salt[16 + 2]; unsigned char auth_challenge[16]; unsigned char peer_challenge[16]; unsigned char response[24]; int type; char *ctcopy = strdup(ciphertext); char *keeptr = ctcopy; char *p; int i; ctcopy += 6; /* skip over "$pptp$" */ p = strtok(ctcopy, "$"); type = atoi(p); p = strtok(NULL, "$"); if(type == 1) { /* user has given us raw packet values */ for (i = 0; i < 16; i++) auth_challenge[i] = atoi16[ARCH_INDEX(p[i * 2])] * 16 + atoi16[ARCH_INDEX(p[i * 2 + 1])]; p = strtok(NULL, "$"); for (i = 0; i < 16; i++) peer_challenge[i] = atoi16[ARCH_INDEX(p[i * 2])] * 16 + atoi16[ARCH_INDEX(p[i * 2 + 1])]; } else { /* user has given us processed values */ for (i = 0; i < 8; i++) auth_challenge[i] = atoi16[ARCH_INDEX(p[i * 2])] * 16 + atoi16[ARCH_INDEX(p[i * 2 + 1])]; } if(type == 1) { /* user has given us raw packet values */ p = strrchr(ciphertext, '$') + 1; /* get username */ SHA1_Init(&ctx); SHA1_Update(&ctx, peer_challenge, 16); SHA1_Update(&ctx, auth_challenge, 16); SHA1_Update(&ctx, p, strlen(p)); SHA1_Final(binary_salt, &ctx); p = ciphertext + 6 + 2 + 32 + 1 + 48; for (i = 0; i < BINARY_SIZE; i++) response[i] = atoi16[ARCH_INDEX(p[i * 2])] * 16 + atoi16[ARCH_INDEX(p[i * 2 + 1])]; } else { p = strtok(NULL, "$"); for (i = 0; i < BINARY_SIZE; i++) response[i] = atoi16[ARCH_INDEX(p[i * 2])] * 16 + atoi16[ARCH_INDEX(p[i * 2 + 1])]; } MEM_FREE(keeptr); /* Attempting to recover last 2 of hash */ if(gethashlast2(binary_salt, response, &binary_salt[16])) printf("\tCould not recover last 2 bytes of hash from the challenge/response. Sorry it didn't work out for %s\n", ciphertext); return (void *)binary_salt; } static void *get_binary(char *ciphertext) { static union { unsigned char c[BINARY_SIZE]; ARCH_WORD dummy; } buf; unsigned char *out = buf.c; char *p; int i; int type; char *ctcopy = strdup(ciphertext); char *keeptr = ctcopy; ctcopy += 6; /* skip over "$pptp$" */ p = strtok(ctcopy, "$"); type = atoi(p); if (type == 1) p = ciphertext + 6 + 2 + 32 + 1 + 48; else p = ciphertext + 6 + 2 + 16 + 1; for (i = 0; i < BINARY_SIZE; i++) out[i] = atoi16[ARCH_INDEX(p[i * 2])] * 16 + atoi16[ARCH_INDEX(p[i * 2 + 1])]; MEM_FREE(keeptr); return out; } static int binary_hash_0(void *binary) { return *(ARCH_WORD_32 *)binary & 0xF; } static int binary_hash_1(void *binary) { return *(ARCH_WORD_32 *)binary & 0xFF; } static int binary_hash_2(void *binary) { return *(ARCH_WORD_32 *)binary & 0xFFF; } static int binary_hash_3(void *binary) { return *(ARCH_WORD_32 *)binary & 0xFFFF; } static int binary_hash_4(void *binary) { return *(ARCH_WORD_32 *)binary & 0xFFFFF; } static int get_hash_0(int index) { return *(ARCH_WORD_32 *)output[index] & 0xF; } static int get_hash_1(int index) { return *(ARCH_WORD_32 *)output[index] & 0xFF; } static int get_hash_2(int index) { return *(ARCH_WORD_32 *)output[index] & 0xFFF; } static int get_hash_3(int index) { return *(ARCH_WORD_32 *)output[index] & 0xFFFF; } static int get_hash_4(int index) { return *(ARCH_WORD_32 *)output[index] & 0xFFFFF; } static void set_salt(void *salt) { challenge = salt; } static void crypt_all(int count) { DES_key_schedule ks; int i; if (!keys_prepared) { #ifdef _OPENMP #pragma omp parallel for #endif for(i=0; i 9 DEFAULT_ALIGN, #endif SALT_SIZE, #if FMT_MAIN_VERSION > 9 DEFAULT_ALIGN, #endif MIN_KEYS_PER_CRYPT, MAX_KEYS_PER_CRYPT, FMT_CASE | FMT_8_BIT | FMT_SPLIT_UNIFIES_CASE | FMT_OMP | FMT_UNICODE | FMT_UTF8, pptp_tests }, { init, fmt_default_prepare, valid, fmt_default_split, get_binary, get_salt, #if FMT_MAIN_VERSION > 9 fmt_default_source, #endif { binary_hash_0, binary_hash_1, binary_hash_2, binary_hash_3, binary_hash_4 }, fmt_default_salt_hash, set_salt, pptp_set_key, get_key, fmt_default_clear_keys, crypt_all, { get_hash_0, get_hash_1, get_hash_2, get_hash_3, get_hash_4 }, cmp_all, cmp_one, cmp_exact } };