Oracle FAQ Your Portal to the Oracle Knowledge Grid
HOME | ASK QUESTION | ADD INFO | SEARCH | E-MAIL US
 

Home -> Community -> Usenet -> c.d.o.server -> Crack the crackomoli of Oracle passwords

Crack the crackomoli of Oracle passwords

From: fitzjarrel <fitzjarrel_at_cox.com>
Date: Sun, 02 Oct 2005 11:18:37 -0400
Message-ID: <ed60c3e4253ae3b90f39d3b1a968f03c@localhost.talkaboutdatabases.com>


http://lists.grok.org.uk/pipermail/full-disclosure/attachments/20050825/f85ff3df/oracle_fmt.bin

//---------------------------------------------------------------
Oracle's Password Transform

Goals:

The Algorithm:

Convert user name and password to uppercase 'normal' form. Normal form uses 16 bits to represent each character, and it is independant of language
and the computer's character set (acsii or ebcdic).

Concatenate normalized user name and password. Pad result to multiple of 64 bits. Zero padding is better than some rolling xor algorithm, since the
later produces redundant information that an attacker can use to check for the correctness of a guess. The result is called UPLONG.

Compute cryptographic checksum of UPLONG using a known key and the cipher block chaining mode of DES. The known key is hex 0123456789ABCDEF. The idea is to extract 56 suitable bits from the password. The CBC64 (cipher block chain with 64 bit feedback path) checksum makes good use of the bits
in a long password, and it speads out the redundant information that is present due to the fact that the 'normal' form uses 16 bits per character.
The feedback path is 64 bits, not the standard 8 bits because it generates
a more uniform distribution. See Alan T. Sherman's PhD thesis (MIT 1987) for justification.

It isn't hard to invert the checksum we just found (the key is known), so now we hide this result by using it as the key to compute another checksum
on the uplong array. That checksum will be used as the authentication parameter for the user. Note that DES has the property that given a matching block of plaintext and ciphertext is is still quite hard to find the key that mapped the plaintext into the ciphertext.

We could use the first checksum as a key to encrypt a constant, but it seems safer to use non-constant data like the information in the UPLONG array. If nothing else this makes a dictionary attack harder.

Note that an attacker must now solve two simultaneous equations for P:

        k1 = checksum( k0, U || P )
        k2 = checksum( k1, U || P )

Where 'U || P' is the username concatenated with the password (U is known,
P is not), k0 is the known key, k1 is the first checksum, and k2 is the value placed in the authentication table.

Convert the second checksum value into a machine independent form. Since we are not short on characters, express it as a hex string.

//---------------------------------------------------------------
/*
 * Copyright (c) 2004 Simon Marechal

#include <string.h>

#include "arch.h"
#include "misc.h"
#include "common.h"
#include "formats.h"
#include "des.h"

#define FORMAT_LABEL "oracle"
#define FORMAT_NAME "Oracle"
#define ALGORITHM_NAME "oracle"

#define BENCHMARK_COMMENT ""
#define BENCHMARK_LENGTH -1

#define PLAINTEXT_LENGTH 16

#define BINARY_SIZE 8
#define SALT_SIZE 32
#define CIPHERTEXT_LENGTH (BINARY_SIZE + SALT_SIZE)

#define MIN_KEYS_PER_CRYPT 1
#define MAX_KEYS_PER_CRYPT 1

static struct fmt_tests oracle_tests[] = {

	{"O$SIMON#4F8BC1809CB2AF77", "A"},
	{"O$SIMON#183D72325548EF11", "THALES2" },
	{"O$SIMON#C4EB3152E17F24A4", "TST" },
	{"O$SYSTEM#9EEDFA0AD26C6D52", "THALES" },
	{NULL}

};

#if ARCH_LITTLE_ENDIAN
#define ENDIAN_SHIFT_L << 8
#define ENDIAN_SHIFT_R >> 8
#else
#define ENDIAN_SHIFT_L
#define ENDIAN_SHIFT_R
#endif

//stores the ciphertext for value currently being tested static char crypt_key[BINARY_SIZE+1];

static unsigned char cur_salt[128 + 1]; //current salt static unsigned char cur_key[128 + 1]; //current salt

static unsigned char deskey[8];
static unsigned char salt_iv[8];
static DES_key_schedule desschedule1;
static DES_key_schedule desschedule2;

static int salt_length;
static int key_length;

static int valid(char *ciphertext)
{

	int i;
	int l;

	/*
	 * 2 cases
	 * 1 - it comes from the disk, and does not have O$ + salt
	 * 2 - it comes from memory, and has got O$ + salt + # + blah
	 */

	if (!memcmp(ciphertext, "O$", 2))
	{
		l = strlen(ciphertext) - PLAINTEXT_LENGTH;
		if(ciphertext[l-1]!='#')
			return 0;
	}
	else
	{
		if(strlen(ciphertext)!=PLAINTEXT_LENGTH)
			return 0;
		l = 0;
	}
	for (i = l; i < l + PLAINTEXT_LENGTH; i++){
		if (!(  (('0' <= ciphertext[i])&&(ciphertext[i] <= '9')) ||
			(('a' <= ciphertext[i])&&(ciphertext[i] <= 'f'))  
			|| (('A' <= ciphertext[i])&&(ciphertext[i] <= 'F'))))
			return 0;
	}
	
	return 1;

}

static void oracle_init(void)
{

	deskey[0] = 0x01;
	deskey[1] = 0x23;
	deskey[2] = 0x45;
	deskey[3] = 0x67;
	deskey[4] = 0x89;
	deskey[5] = 0xab;
	deskey[6] = 0xcd;
	deskey[7] = 0xef;

	my_des_set_key(&deskey, &desschedule1);
}

static void oracle_set_salt(void *salt, int count) {

        salt_length = 0;

	memset(salt_iv, 0, 8);
	while ( (((unsigned short *)cur_salt)[salt_length] = ((unsigned char
*)salt)[salt_length] ENDIAN_SHIFT_L ))
		salt_length++;
	//this optimization is for Bob the Butcher only
	/*
	if(salt_length > 4)
	{
		salt_offset = (salt_length & (~3))*2;
		my_des_ncbc_encrypt(cur_salt, salt_offset, &desschedule1, salt_iv);
	}*/

}

static void oracle_set_key(char *key, int index) {

	key_length = 0;
	while( (((unsigned short *)cur_key)[key_length] = key[key_length]
ENDIAN_SHIFT_L ))
		key_length++;

}

static char *oracle_get_key(int index) {

	static unsigned char out[PLAINTEXT_LENGTH];
	unsigned int i;
	for(i=0;i<key_length;i++)
		out[i] = ((unsigned short *)cur_key)[i] ENDIAN_SHIFT_R;
	out[i] = 0;
	return out;

}

static int oracle_cmp_all(void *binary, int index) {

	int i=0;
	while(i<(BINARY_SIZE/sizeof(int)))
	{
		if(((int *)binary)[i]!=((int *)crypt_key)[i])
			return 0;
		i++;
	}
	return 1;

}

static void oracle_crypt_all(int count) {

        unsigned int l;         

	l = (salt_length + key_length)*2;
	memcpy(crypt_key, salt_iv, 8);
	memcpy(cur_salt + salt_length*2, cur_key, key_length * 2); //stupid way
john works
	my_des_ncbc_encrypt(cur_salt ,l , &desschedule1, crypt_key);
	my_des_set_key(crypt_key, &desschedule2);
	memset(crypt_key, 0, 8);
	my_des_ncbc_encrypt(cur_salt, l , &desschedule2, crypt_key);
}

static void * oracle_binary(char *ciphertext) {

	static unsigned char out3[BINARY_SIZE];
	int l;
	int i;
	l = strlen(ciphertext) - PLAINTEXT_LENGTH;
	for(i=0;i<BINARY_SIZE;i++) 
	{
		out3[i] = atoi16[ARCH_INDEX(ciphertext[i*2+l])]*16 
			+ atoi16[ARCH_INDEX(ciphertext[i*2+l+1])];
	}
	return out3;

}

static void * oracle_get_salt(char * ciphertext) {

	static unsigned char out2[SALT_SIZE];
	int l;

	l = 2;
	while( ciphertext[l] && (ciphertext[l]!='#') )
	{
		out2[l-2] = ciphertext[l];
		l++;
	}
	out2[l-2] = 0;
	return out2;

}

static int oracle_cmp_one(void *binary, int count){

        return (1);
}

static int oracle_cmp_exact(char *source, int count){

        return 1;
}

static int binary_hash1(void * binary) { return (((unsigned int *)binary)[0] & 0xf); }
static int binary_hash2(void * binary) { return (((unsigned int *)binary)[0] & 0xff); }
static int binary_hash3(void * binary) { return (((unsigned int *)binary)[0] & 0xfff); }

static int get_hash1(int index) { return (((unsigned int *)crypt_key)[0] & 0xf); }
static int get_hash2(int index) { return (((unsigned int *)crypt_key)[0] & 0xff); }
static int get_hash3(int index) { return (((unsigned int *)crypt_key)[0] & 0xfff); }

struct fmt_main fmt_oracle = {

	{
		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_8_BIT,
		oracle_tests
	}, {
		oracle_init,
		valid,
		fmt_default_split,
		oracle_binary,
		oracle_get_salt,
		{
			binary_hash1,
			binary_hash2,
			binary_hash3
		},
		fmt_default_salt_hash,
		oracle_set_salt,
		oracle_set_key,
		oracle_get_key,
		fmt_default_clear_keys,
		oracle_crypt_all,
		{
			get_hash1,
			get_hash2,
			get_hash3
		},
		oracle_cmp_all,
		oracle_cmp_one,
		oracle_cmp_exact
	}

}; Received on Sun Oct 02 2005 - 10:18:37 CDT

Original text of this message

HOME | ASK QUESTION | ADD INFO | SEARCH | E-MAIL US