Openwall GNU/*/Linux - a small security-enhanced Linux distro for servers
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Sat, 10 Dec 2011 00:23:18 +0100
From: Didier Arenzana <darenzana@...il.com>
To: john-dev@...ts.openwall.com
Subject: Re: cracking RADIUS shared secrets with john the ripper

On Fri, Dec 9, 2011 at 7:52 PM, jfoug <jfoug@....net> wrote:
> It has been posted as patch 0043-  the salt() function now does all of the
> work, including figuring out what salts are identical.  Dynamic returns 4
> byte or 8 byte 'salts' back to john, which will always be unique.  These 4
> or 8 bytes are simply the data contents of a pointer.

I have donwloaded and built the patch, and you will find attached a
patch on top of this one, that contains the following modifications:

It did not compile out of the box on macosx-x86-64. I added a line to
johnswap.h, where ARCH_WORD_32 was used without being #defined

I made some changes in valid() and ConvertFromHex(), so that salts
such as "HEX$abc" (note the odd number of chars) or "HEX$mysalt" are
considered valid, and taken litterally (not converted from base16). In
the current implementation, something like this would pass valid() and
be converted in salt() to an incorrect value. Note that I took the
verification code from my own version of valid(), which has a
different logic than yours, but should produce the same result : it
searches first for HEX$, validates the string after, and computes an
'expected' length, and then checks against this length.

>>I will stick on my rad2john perl script then; and have a related
>>question: what is the absolute maximum length for a salt in dynamic_n
>>format ? The attack on radius responses use a whole packet as salt, so
>>it can get pretty big, I want to check in the script if it does not
>>generate too big salts.
>
> This depends upon how you have written the format.  If you write them
> non-SSE, then any length salt 'should' work.  With the changes I have made,
> I can easily do this.  Prior code would have been hard, because we had to
> return max_length often, if we did not know, since many formats do not
> specify the max salt length.  There is still 'some' of that logic within
> john.  I think the max length at this moment (fully updated 1.7.9 up to
> patch 0043), I think is somewhere in this area:  #define SALT_SIZE
> (64*4+1+3+1)    NOTE, I have not validated this.  The format would HAVE to
> be written to handle this.   Keep in mind, that for x86 mode (i.e. anything
> other than MMX type builds), the buffers where you manipulate input data
> (and do the crypts from), is only 124 + 96 bytes, and I believe that on
> 'some' builds, those extra 96 bytes are used by the crypt code, as temp
> storage.  So it may be that the largest salt you can 'use' is password_len -
> 124.
>
> NOTE, for any MMX build, unless you switch the data into and out of x86 type
> buffers, the max salt you can use is 55-password_len bytes long.  This
> limitation is where most of the 'bullet proofing' of lengths within the
> built in types in the dynamic format come from.

I was not expecting such a long answer :) I will make it a variable in
the script so it's easy to change, and use a default value of 45.
Based on your explanation, it will give room for 10-characteres
password in the worst case.

> Jim.
>

diff -urpN john-1.7.9.orig/src/dynamic_fmt.c john-1.7.9/src/dynamic_fmt.c
--- john-1.7.9.orig/src/dynamic_fmt.c	2011-12-09 22:37:03.000000000 +0000
+++ john-1.7.9/src/dynamic_fmt.c	2011-12-09 22:23:54.000000000 +0000
@@ -597,7 +597,7 @@ static private_subformat_data curdat;
  *********************************************************************************/
 static int valid(char *ciphertext, struct fmt_main *pFmt)
 {
-	int i, cipherTextLen;
+	int i, cipherTextLen, expectedSize;
 	char *cp;
 	private_subformat_data *pPriv = pFmt->private.data;
 
@@ -669,48 +669,48 @@ static int valid(char *ciphertext, struc
 		return 0;
 	if (pPriv->dynamic_FIXED_SALT_SIZE && ciphertext[pPriv->dynamic_SALT_OFFSET-1] != '$')
 		return 0;
-	if (pPriv->dynamic_FIXED_SALT_SIZE > 0 && strlen(&ciphertext[pPriv->dynamic_SALT_OFFSET]) != pPriv->dynamic_FIXED_SALT_SIZE) {
+    if (pPriv->dynamic_FIXED_SALT_SIZE) {
+        // compute the real salt size if needed, which will be used in the next tests
+        cp = &ciphertext[pPriv->dynamic_SALT_OFFSET] ; //start of salt string
+        expectedSize =  ( pPriv->dynamic_FIXED_SALT_SIZE > 0) ?  pPriv->dynamic_FIXED_SALT_SIZE 
+                                                              : -pPriv->dynamic_FIXED_SALT_SIZE;
+        // check for HEX$ at start of salt, followed by valid hexadecimal chars
+        if (!strncmp(cp, "HEX$", 4)) {
+            cp+=4 ;
+            i=0 ;
+            while ( cp[i] && ( (('0' <= cp[i])&&(cp[i] <= '9')) ||
+                              (('a' <= cp[i])&&(cp[i] <= 'f')) ||
+                              (('A' <= cp[i])&&(cp[i] <= 'F'))    )
+                   ) ++i ;
+            
+            if (((i % 2) == 0) && 
+                ( (cp[i] == 0) || ( (cp[i]=='$') && 
+                                   (cp[i+1]=='$') && 
+                                   ((cp[i+2]=='2') || (cp[i+2]=='F') || (cp[i+2]=='U'))
+                                   ))) {                
+                // we have a valid HEX$ string,
+                //it will later be converted to binary, so let's take that into account  
+                expectedSize = 4 + 2*expectedSize;   
+            } 
+        }
+    }
+	if (pPriv->dynamic_FIXED_SALT_SIZE > 0 && strlen(&ciphertext[pPriv->dynamic_SALT_OFFSET]) != expectedSize) {
+        // salt length should be exactly pPriv->dynamic_FIXED_SALT_SIZE
 		// check if there is a 'salt-2' or 'username', etc  If that is the case, then this is still valid.
-		if (strncmp(&ciphertext[pPriv->dynamic_SALT_OFFSET+pPriv->dynamic_FIXED_SALT_SIZE], "$$", 2)) {
-			// do another check, just in case there is a HEX$ type salt.
-			if (strncmp(&ciphertext[pPriv->dynamic_SALT_OFFSET], "HEX$", 4) == 0) {
-				// Ok, we do have a HEX.  We now want to compute it's length.
-				if (strlen(&ciphertext[pPriv->dynamic_SALT_OFFSET+4]) == pPriv->dynamic_FIXED_SALT_SIZE*2) {
-					// Ok, check for salt-2, username, etc.
-				} else if (strncmp(&ciphertext[pPriv->dynamic_SALT_OFFSET+pPriv->dynamic_FIXED_SALT_SIZE*2+4], "$$", 2)) {
+		// aren't we 'out of bonds' with this check if the salt was too small ?
+        if (strncmp(&ciphertext[pPriv->dynamic_SALT_OFFSET+expectedSize], "$$", 2))
 			return 0;
 	}
-			} else
-				return 0;
-		}
-	}
-	else if (pPriv->dynamic_FIXED_SALT_SIZE < -1 && strlen(&ciphertext[pPriv->dynamic_SALT_OFFSET]) > -(pPriv->dynamic_FIXED_SALT_SIZE)) {
+	else if (pPriv->dynamic_FIXED_SALT_SIZE < -1 && strlen(&ciphertext[pPriv->dynamic_SALT_OFFSET]) > expectedSize) {
 		// check if there is a 'salt-2' or 'username', etc  If that is the case, then this is still 'valid'
-		char *cpX;
-		if (strncmp(&ciphertext[pPriv->dynamic_SALT_OFFSET], "HEX$", 4) == 0) {
-			if (strlen(&ciphertext[pPriv->dynamic_SALT_OFFSET+4]) <= -(pPriv->dynamic_FIXED_SALT_SIZE*2)) {
-				// ok  We are only 'overlength', due to HEX$hexsalt being longer due to be 2x+4 because 1 byte becomes 2.
-				// Once we convert FROM the external HEX$ format, to binary format, it will be <= the max salt size, and
-				// thus this salt is 'safe' for this format.
-			} else {
-				cpX = mem_alloc(-(pPriv->dynamic_FIXED_SALT_SIZE*2) + 3);
-				strnzcpy(cpX, &ciphertext[pPriv->dynamic_SALT_OFFSET], -(pPriv->dynamic_FIXED_SALT_SIZE*2) + 3);
-				if (!strstr(cpX, "$$")) {
-					MEM_FREE(cpX);
-					return 0;
-				}
-				MEM_FREE(cpX);
-			}
-		} else {
-			cpX = mem_alloc(-(pPriv->dynamic_FIXED_SALT_SIZE) + 3);
-		strnzcpy(cpX, &ciphertext[pPriv->dynamic_SALT_OFFSET], -(pPriv->dynamic_FIXED_SALT_SIZE) + 3);
+		char *cpX = mem_alloc(expectedSize + 3);
+		strnzcpy(cpX, &ciphertext[pPriv->dynamic_SALT_OFFSET], expectedSize + 3);
 		if (!strstr(cpX, "$$")) {
 			MEM_FREE(cpX);
 			return 0;
 		}
 		MEM_FREE(cpX);
 	}
-	}
 	if (pPriv->b2Salts==1 && !strstr(&ciphertext[pPriv->dynamic_SALT_OFFSET-1], "$$2"))
 		return 0;
 	if (pPriv->nUserName && !strstr(&ciphertext[pPriv->dynamic_SALT_OFFSET-1], "$$U"))
@@ -1645,8 +1645,12 @@ static unsigned char *HashSalt(unsigned 
 static int ConvertFromHex(unsigned char *p, int len) {
 	unsigned char *cp;
 	int i, x;
-	if (!p || memcmp(p, "HEX$", 4))
+	if (!p || memcmp(p, "HEX$", 4) || (len %2))
 		return len;
+    
+    for (cp=p+4, x=len-4; x; --x, ++cp) {
+        if ( atoi16[ARCH_INDEX(*cp)] == 0x7F ) return len ;
+    }
 	// Ok, do a convert, and return 'new' len.
 	len -= 4; 
 	len >>= 1;
diff -urpN john-1.7.9.orig/src/johnswap.h john-1.7.9/src/johnswap.h
--- john-1.7.9.orig/src/johnswap.h	2011-12-09 22:37:03.000000000 +0000
+++ john-1.7.9/src/johnswap.h	2011-12-09 19:30:17.000000000 +0000
@@ -12,6 +12,7 @@
 #	endif
 #	define JOHNSWAP(x)	_byteswap_ulong((x))
 #else
+#	include "common.h"
 #	define JOHNSWAP(x)	bswap_32((x))
 #	define JOHNSWAP(x)	bswap_32((x))
 #	define JOHNSWAP(x)	bswap_32((x))
 #	define ROTATE_LEFT(x, n) (x) = (((x)<<(n))|((ARCH_WORD_32)(x)>>(32-(n))))
 	static inline ARCH_WORD_32 bswap_32(ARCH_WORD_32 x)

Powered by blists - more mailing lists

Your e-mail address:

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