Openwall GNU/*/Linux - a small security-enhanced Linux distro for servers
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Wed, 2 Sep 2009 19:58:32 +0400
From: Solar Designer <solar@...nwall.com>
To: john-users@...ts.openwall.com
Subject: Re: "No password hashes loaded" on Ubuntu 9.04

On Wed, Sep 02, 2009 at 04:48:28AM -0500, Christopher Lemire wrote:
> Has the issue been resolved or close to being resolved?

Not in the proper way yet, and I am likely to work on other things first
(not JtR related even, sorry), but you may try the attached patch, which
I've just put together.

This patch implements generic crypt(3) support.  That is, if the
Unix-like system you run JtR on supports your desired crypt(3) hash type
natively, then JtR with this patch applied will also support that hash
type (albeit non-optimally).

Right now, the switch statement in salt() is missing proper checks/code
for the "SHA-crypt" flavors, which means that JtR won't detect matching
salts for this hash type (and won't take advantage of them for faster
processing).  (BTW, a related idea is to auto-detect the salt size -
slow but possible.)  Yet JtR with this patch applied should be able to
crack weak "SHA-crypt" hashed passwords when running on a proper system.
Please test.

So far, I've only tested this code on an Owl system, with a mix of
traditional DES-based, extended BSDI-style DES-based, MD5-based, and
Blowfish-based ("bcrypt") crypt(3) hashes in the same passwd file - it
worked fine, although indeed slowly (compared to JtR's optimized code
for these hash types).

When there are different hash types in the same passwd file, JtR's speed
(in terms of candidate passwords tried per second) may be mostly limited
by the slowest of the hash types, which may result in JtR effectively
"missing" some weak passwords hashed with the faster hashes (it won't
approach the corresponding candidate passwords soon enough because of
the slow hashes also having been loaded).  For this reason, I recommend
that you don't mix different hash types on the same JtR instance, even
though this code supports that.

> I plan to
> write a guide on my blog (see signature), and setup john the ripper
> clusters. It won the poll on my site for next topic, and I haven't
> been able to supply what's in high demand right now. Things involving
> security seem to be the highest in demand.

I recommend that you primarily use better-supported hash types for
demoing this.  You don't have to run JtR against hashes from your
specific Ubuntu system, although now you should be able to.  It is a
little bit weird to run, say, a cluster of 4 machines (or CPU cores or
whatever) when the same performance could be achieved with 1 machine
once proper code is written for JtR.

> http://linuxinnovations.blogspot.com/

(Offtopic: your blog feels overloaded with slow JavaScript and images.)

You write:

"The problem is that since the md5 hash exploit code has been released.
Most or all of Linux quit using md5 hashes to store their passwords.
They now use SHA256."

This is largely misinformation (I counted four factual errors), based on
rumors that are only partially based on fact.  I suggest that you learn
the subject matter before you write about it.  If you don't know and
don't have time to figure something out for real, you could want to word
your comments accordingly.  For example:

"The problem is that JtR does not yet support the newer hash type being
used by my Ubuntu 9.04 system.  You can read more about the problem here."

(with the same hyperlink that you currently have).  Yes, this is less
info, but at least it's correct.  If you really wanted to write what you
did, then you could use words such as "apparently" or "I've heard that".

Please treat this as constructive criticism.

Thanks,

Alexander

diff -urpN john-1.7.3.1/src/Makefile john-1.7.3.1-gencrypt/src/Makefile
--- john-1.7.3.1/src/Makefile	2008-07-18 01:28:55 +0000
+++ john-1.7.3.1-gencrypt/src/Makefile	2009-09-02 11:50:28 +0000
@@ -17,7 +17,7 @@ NULL = /dev/null
 CPPFLAGS = -E
 CFLAGS = -c -Wall -O2 -fomit-frame-pointer
 ASFLAGS = -c
-LDFLAGS = -s
+LDFLAGS = -s -lcrypt
 OPT_NORMAL = -funroll-loops
 OPT_INLINE = -finline-functions
 
@@ -28,6 +28,7 @@ JOHN_OBJS_MINIMAL = \
 	BF_fmt.o BF_std.o \
 	AFS_fmt.o \
 	LM_fmt.o \
+	crypt_fmt.o \
 	batch.o bench.o charset.o common.o compiler.o config.o cracker.o \
 	crc32.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 \
diff -urpN john-1.7.3.1/src/crypt_fmt.c john-1.7.3.1-gencrypt/src/crypt_fmt.c
--- john-1.7.3.1/src/crypt_fmt.c	1970-01-01 00:00:00 +0000
+++ john-1.7.3.1-gencrypt/src/crypt_fmt.c	2009-09-02 13:01:34 +0000
@@ -0,0 +1,216 @@
+/* public domain proof-of-concept code by Solar Designer */
+
+#define _XOPEN_SOURCE /* for crypt(3) */
+#include <string.h>
+#include <unistd.h>
+
+#include "arch.h"
+#include "params.h"
+#include "formats.h"
+
+#define FORMAT_LABEL			"crypt"
+#define FORMAT_NAME			"generic crypt(3)"
+#define ALGORITHM_NAME			"?/" ARCH_BITS_STR
+
+#define BENCHMARK_COMMENT		""
+#define BENCHMARK_LENGTH		0
+
+#define PLAINTEXT_LENGTH		72
+
+#define BINARY_SIZE			128
+#define SALT_SIZE			BINARY_SIZE
+
+#define MIN_KEYS_PER_CRYPT		1
+#define MAX_KEYS_PER_CRYPT		1
+
+static struct fmt_tests tests[] = {
+	{"CCNf8Sbh3HDfQ", "U*U*U*U*"},
+	{"CCX.K.MFy4Ois", "U*U***U"},
+	{"CC4rMpbg9AMZ.", "U*U***U*"},
+	{"XXxzOu6maQKqQ", "*U*U*U*U"},
+	{"SDbsugeBiC58A", ""},
+	{NULL}
+};
+
+static char saved_key[PLAINTEXT_LENGTH + 1];
+static char saved_salt[SALT_SIZE];
+static char *crypt_out;
+
+static int valid(char *ciphertext)
+{
+#if 1
+	int l = strlen(ciphertext);
+	return l >= 13 && l < BINARY_SIZE;
+#else
+/* Poor load time, but more effective at rejecting bad/unsupported hashes */
+	char *r = crypt("", ciphertext);
+	int l = strlen(r);
+	return
+	    !strncmp(r, ciphertext, 2) &&
+	    l == strlen(ciphertext) &&
+	    l >= 13 && l < BINARY_SIZE;
+#endif
+}
+
+static void *binary(char *ciphertext)
+{
+	static char out[BINARY_SIZE];
+	strncpy(out, ciphertext, sizeof(out)); /* NUL padding is required */
+	return out;
+}
+
+static void *salt(char *ciphertext)
+{
+	static char out[SALT_SIZE];
+	int cut = sizeof(out);
+
+#if 1
+/* This piece is optional, but matching salts are not detected without it */
+	switch (strlen(ciphertext)) {
+	case 13:
+	case 24:
+		cut = 2;
+		break;
+
+	case 20:
+		if (ciphertext[0] == '_') cut = 9;
+		break;
+
+	case 34:
+		if (!strncmp(ciphertext, "$1$", 3)) {
+			char *p = strchr(ciphertext + 3, '$');
+			if (p) cut = p - ciphertext;
+		}
+		break;
+
+	case 59:
+		if (!strncmp(ciphertext, "$2$", 3)) cut = 28;
+		break;
+
+	case 60:
+		if (!strncmp(ciphertext, "$2a$", 4)) cut = 29;
+		break;
+	}
+#endif
+
+	/* NUL padding is required */
+	memset(out, 0, sizeof(out));
+	memcpy(out, ciphertext, cut);
+
+	return out;
+}
+
+static int binary_hash_0(void *binary)
+{
+	return ((unsigned char *)binary)[12] & 0xF;
+}
+
+static int binary_hash_1(void *binary)
+{
+	return ((unsigned char *)binary)[12] & 0xFF;
+}
+
+static int binary_hash_2(void *binary)
+{
+	return
+	    (((unsigned char *)binary)[12] & 0xFF) |
+	    ((int)(((unsigned char *)binary)[11] & 0xF) << 8);
+}
+
+static int get_hash_0(int index)
+{
+	return (unsigned char)crypt_out[12] & 0xF;
+}
+
+static int get_hash_1(int index)
+{
+	return (unsigned char)crypt_out[12] & 0xFF;
+}
+
+static int get_hash_2(int index)
+{
+	return
+	    ((unsigned char)crypt_out[12] & 0xFF) |
+	    ((int)((unsigned char)crypt_out[11] & 0xF) << 8);
+}
+
+static int salt_hash(void *salt)
+{
+	int pos = strlen((char *)salt) - 2;
+
+	return
+	    (((unsigned char *)salt)[pos] & 0xFF) |
+	    ((int)(((unsigned char *)salt)[pos + 1] & 3) << 8);
+}
+
+static void set_salt(void *salt)
+{
+	strcpy(saved_salt, salt);
+}
+
+static void set_key(char *key, int index)
+{
+	strcpy(saved_key, key);
+}
+
+static char *get_key(int index)
+{
+	return saved_key;
+}
+
+static void crypt_all(int count)
+{
+	crypt_out = crypt(saved_key, saved_salt);
+}
+
+static int cmp_all(void *binary, int count)
+{
+	return !strcmp((char *)binary, crypt_out);
+}
+
+static int cmp_exact(char *source, int index)
+{
+	return 1;
+}
+
+struct fmt_main fmt_crypt = {
+	{
+		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,
+		tests
+	}, {
+		fmt_default_init,
+		valid,
+		fmt_default_split,
+		binary,
+		salt,
+		{
+			binary_hash_0,
+			binary_hash_1,
+			binary_hash_2
+		},
+		salt_hash,
+		set_salt,
+		set_key,
+		get_key,
+		fmt_default_clear_keys,
+		crypt_all,
+		{
+			get_hash_0,
+			get_hash_1,
+			get_hash_2
+		},
+		cmp_all,
+		cmp_all,
+		cmp_exact
+	}
+};
diff -urpN john-1.7.3.1/src/john.c john-1.7.3.1-gencrypt/src/john.c
--- john-1.7.3.1/src/john.c	2006-05-08 14:49:28 +0000
+++ john-1.7.3.1-gencrypt/src/john.c	2009-09-02 11:50:11 +0000
@@ -38,6 +38,7 @@ extern int CPU_detect(void);
 
 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_crypt;
 
 extern int unshadow(int argc, char **argv);
 extern int unafs(int argc, char **argv);
@@ -64,6 +65,7 @@ static void john_register_all(void)
 	john_register_one(&fmt_BF);
 	john_register_one(&fmt_AFS);
 	john_register_one(&fmt_LM);
+	john_register_one(&fmt_crypt);
 
 	if (!fmt_list) {
 		fprintf(stderr, "Unknown ciphertext format name requested\n");


Powered by blists - more mailing lists

Your e-mail address:

Powered by Openwall GNU/*/Linux - Powered by OpenVZ