2
Dump nt/lanman password hashes from a sam hive with Syskey enabled
4
Thank to Dmitry Andrianov for the program name ^_^
6
This program is free software; you can redistribute it and/or
7
modify it under the terms of the GNU General Public License
8
as published by the Free Software Foundation; either version 2
9
of the License, or (at your option) any later version.
11
This program is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
GNU General Public License for more details.
16
You should have received a copy of the GNU General Public License
17
along with this program; if not, write to the Free Software
18
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20
This program is released under the GPL with the additional exemption
21
that compiling, linking, and/or using OpenSSL is allowed.
23
Copyright (C) 2004-2006 Nicola Cuomo <ncuomo@studenti.unina.it>
24
Improvments and some bugs fixes by Objectif Securité
25
<http://www.objectif-securite.ch>
30
#include <openssl/rc4.h>
31
#include <openssl/md5.h>
32
#include <openssl/des.h>
33
#if defined(__linux__)
35
#elif defined(__FreeBSD__)
36
#include <machine/endian.h>
42
#if BYTE_ORDER == LITTLE_ENDIAN
43
#elif BYTE_ORDER == BIG_ENDIAN
46
#warning "Doesn't define a standard ENDIAN type"
49
#warning "Doesn't define BYTE_ORDER"
53
/* Cut&Paste from pwdump source code */
56
* Convert a 7 byte array into an 8 byte des key with odd parity.
59
void str_to_key(unsigned char *str,unsigned char *key)
61
// void des_set_odd_parity(des_cblock *);
65
key[1] = ((str[0]&0x01)<<6) | (str[1]>>2);
66
key[2] = ((str[1]&0x03)<<5) | (str[2]>>3);
67
key[3] = ((str[2]&0x07)<<4) | (str[3]>>4);
68
key[4] = ((str[3]&0x0F)<<3) | (str[4]>>5);
69
key[5] = ((str[4]&0x1F)<<2) | (str[5]>>6);
70
key[6] = ((str[5]&0x3F)<<1) | (str[6]>>7);
75
des_set_odd_parity((des_cblock *)key);
79
* Function to convert the RID to the first decrypt key.
82
void sid_to_key1(unsigned long sid,unsigned char deskey[8])
86
s[0] = (unsigned char)(sid & 0xFF);
87
s[1] = (unsigned char)((sid>>8) & 0xFF);
88
s[2] = (unsigned char)((sid>>16) & 0xFF);
89
s[3] = (unsigned char)((sid>>24) & 0xFF);
98
* Function to convert the RID to the second decrypt key.
101
void sid_to_key2(unsigned long sid,unsigned char deskey[8])
105
s[0] = (unsigned char)((sid>>24) & 0xFF);
106
s[1] = (unsigned char)(sid & 0xFF);
107
s[2] = (unsigned char)((sid>>8) & 0xFF);
108
s[3] = (unsigned char)((sid>>16) & 0xFF);
113
str_to_key(s,deskey);
118
int samdump2(char *sam, list_t *list, unsigned char *bootkey, char *error, int debug ) {
121
char *regaccountkey, *reguserskey;
122
unsigned char aqwerty[] = "!@#$%^&*()qwertyUIOPAzxcvbnmQQQQQQQQQQQQ)(*@&%";
123
unsigned char anum[] = "0123456789012345678901234567890123456789";
124
unsigned char antpassword[] = "NTPASSWORD";
125
unsigned char almpassword[] = "LMPASSWORD";
127
char *buff; int buff_len;
136
unsigned char *b = NULL;
138
unsigned char regkeyname[50];
142
/* md5 contex, hash, rc4 key, hashed bootkey */
144
unsigned char md5hash[0x10];
146
unsigned char hbootkey[0x20];
149
des_key_schedule ks1, ks2;
150
des_cblock deskey1, deskey2;
156
int usernameoffset, usernamelen;
157
int lm_hashesoffset, nt_hashesoffset;
158
int lm_size, nt_size;
160
unsigned char obfkey[0x10];
161
unsigned char fb[0x10];
163
/* Initialize registry access function */
167
if( _RegOpenHive(sam, &h ) ) {
168
sprintf( error, "Error opening sam hive or not valid file(\"%s\")\n", sam );
174
CMI-CreateHive{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx} for Vista */
175
if( _RegGetRootKey( &h, &root_key)) {
176
sprintf( error, "Error reading hive root key\n");
180
printf("Root Key : %s\n", root_key);
182
regaccountkey = (char *) malloc(strlen(root_key)+30);
183
reguserskey = (char *) malloc(strlen(root_key)+30);
185
sprintf(regaccountkey, "%s\\SAM\\Domains\\Account", root_key);
186
sprintf(reguserskey, "%s\\SAM\\Domains\\Account\\Users", root_key);
188
n = (nk_hdr*) malloc(sizeof(nk_hdr));
190
/* Open SAM\\SAM\\Domains\\Account key*/
191
if( _RegOpenKey( &h, regaccountkey, &n ) ) {
193
sprintf( error, "%s key!\n", regaccountkey );
197
if( _RegQueryValue( &h, "F", n, &b, &blen ) ) {
199
sprintf( error, "No F!\n" );
203
/* hash the bootkey */
205
MD5_Update( &md5c, &b[0x70], 0x10 );
206
MD5_Update( &md5c, aqwerty, 0x2f );
207
MD5_Update( &md5c, bootkey, 0x10 );
208
MD5_Update( &md5c, anum, 0x29 );
209
MD5_Final( md5hash, &md5c );
210
RC4_set_key( &rc4k, 0x10, md5hash );
211
RC4( &rc4k, 0x20, &b[0x80], hbootkey );
217
/* Open SAM\\SAM\\Domains\\Account\\Users */
218
if( _RegOpenKey( &h, reguserskey, &n ) ) {
220
sprintf( error, "No Users key!\n" );
224
regkeynamelen = sizeof( regkeyname );
226
j = _RegEnumKey( &h, n, j, (char*)regkeyname, ®keynamelen );
229
printf("******************** %d ********************\n", j);
232
if( !memcmp( regkeyname, "Names", regkeynamelen ) )
235
keyname = (char*) malloc( strlen( reguserskey ) + regkeynamelen + 2 );
237
/* Open SAM\\SAM\\Domains\\Account\\Users\\userrid */
238
strcpy( keyname, reguserskey );
239
strcat( keyname, "\\" ) ;
240
strcat( keyname, (char*)regkeyname ) ;
242
if( _RegOpenKey( &h, keyname, &n ) ) {
245
sprintf( error, "Asd -_- _RegEnumKey fail!\n" );
249
if( _RegQueryValue( &h, "V", n, &b, &blen ) ) {
252
sprintf( error, "No V value!\n" );
257
rid = strtoul( (char*)regkeyname, NULL, 16 );
259
/* get the username */
260
/* 0x10 username size 0xc username offset */
261
#if BYTE_ORDER == LITTLE_ENDIAN
262
usernamelen = *(int*)(b + 0x10) >> 1;
263
#elif BYTE_ORDER == BIG_ENDIAN
264
usernamelen = __bswap_32(*(int*)(b + 0x10) >> 1);
266
usernameoffset = b[0xc] + 0xcc;
269
printf("\nusername len=%d, off=%x\n", usernamelen, usernameoffset);
271
username = (char *) malloc( usernamelen + 1 );
273
// Quick hack for unicode -> ascii translation
274
for( z = 0; z < usernamelen; z++)
275
username[z] = b[usernameoffset + z*2];
277
username[ usernamelen ] = 0;
278
#if BYTE_ORDER == LITTLE_ENDIAN
279
lm_hashesoffset = *(int *)(b + 0x9c ) + 0xcc;
280
lm_size = *(int *)(b + 0xa0 );
281
nt_hashesoffset = *(int *)(b + 0xa8 ) + 0xcc;
282
nt_size = *(int *)(b + 0xac );
283
#elif BYTE_ORDER == BIG_ENDIAN
284
lm_hashesoffset = __bswap_32(*(int *)(b + 0x9c )) + 0xcc;
285
lm_size = __bswap_32(*(int *)(b + 0xa0 ));
286
nt_hashesoffset = __bswap_32(*(int *)(b + 0xa8 )) + 0xcc;
287
nt_size = __bswap_32(*(int *)(b + 0xac ));
291
printf("lm_hashoffset = %x, lm_size = %x\n", lm_hashesoffset, lm_size);
292
printf("nt_hashoffset = %x, nt_size = %x\n", nt_hashesoffset, nt_size);
295
buff = (char*)malloc(512);
296
/* Print the user hash */
297
buff_len = sprintf(buff, "%s:%d:", username, rid );
299
if( lm_size == 0x14 ) {
302
for( i = 0; i < 0x10; i++ )
303
printf( "%.2x", b[lm_hashesoffset+4+i] );
307
/* hash the hbootkey and decode lanman password hashes */
309
MD5_Update( &md5c, hbootkey, 0x10 );
310
#if BYTE_ORDER == LITTLE_ENDIAN
311
MD5_Update( &md5c, &rid, 0x4 );
312
#elif BYTE_ORDER == BIG_ENDIAN
313
rid = __bswap_32(rid);
314
MD5_Update( &md5c, &rid, 0x4 );
315
rid = __bswap_32(rid);
317
MD5_Update( &md5c, almpassword, 0xb );
318
MD5_Final( md5hash, &md5c );
320
RC4_set_key( &rc4k, 0x10, md5hash );
321
RC4( &rc4k, 0x10, &b[ lm_hashesoffset + 4 ], obfkey );
323
printf("\nobfkey: ");
324
for( i = 0; i < 0x10; i++ )
325
printf( "%.2x", (unsigned char)obfkey[i] );
332
/* Get the two decrpt keys. */
333
sid_to_key1(rid,(unsigned char *)deskey1);
334
des_set_key_checked((des_cblock *)deskey1,ks1);
335
sid_to_key2(rid,(unsigned char *)deskey2);
336
des_set_key_unchecked((des_cblock *)deskey2,ks2);
338
/* Decrypt the lanman password hash as two 8 byte blocks. */
339
des_ecb_encrypt((des_cblock *)obfkey,
340
(des_cblock *)fb, ks1, DES_DECRYPT);
341
des_ecb_encrypt((des_cblock *)(obfkey + 8),
342
(des_cblock *)&fb[8], ks2, DES_DECRYPT);
346
// sf25( obfkey, (int*)&rid, fb );
348
for( i = 0; i < 0x10; i++ ) {
349
sprintf(buff+buff_len, "%.2x", fb[i] );
353
sprintf(buff+buff_len, "aad3b435b51404eeaad3b435b51404ee" );
356
sprintf(buff+buff_len, ":" );
359
if( nt_size == 0x14 ) {
362
for( i = 0; i < 0x10; i++ )
363
printf( "%.2x", b[nt_hashesoffset+4+i] );
368
/* hash the hbootkey and decode the nt password hashes */
370
MD5_Update( &md5c, hbootkey, 0x10 );
371
#if BYTE_ORDER == LITTLE_ENDIAN
372
MD5_Update( &md5c, &rid, 0x4 );
373
#elif BYTE_ORDER == BIG_ENDIAN
374
rid = __bswap_32(rid);
375
MD5_Update( &md5c, &rid, 0x4 );
376
rid = __bswap_32(rid);
378
MD5_Update( &md5c, antpassword, 0xb );
379
MD5_Final( md5hash, &md5c );
381
RC4_set_key( &rc4k, 0x10, md5hash );
382
RC4( &rc4k, 0x10, &b[ nt_hashesoffset + 4], obfkey );
384
if (lm_size != 0x14) {
385
/* Get the two decrpt keys. */
386
sid_to_key1(rid,(unsigned char *)deskey1);
387
des_set_key((des_cblock *)deskey1,ks1);
388
sid_to_key2(rid,(unsigned char *)deskey2);
389
des_set_key((des_cblock *)deskey2,ks2);
392
/* Decrypt the NT md4 password hash as two 8 byte blocks. */
393
des_ecb_encrypt((des_cblock *)obfkey,
394
(des_cblock *)fb, ks1, DES_DECRYPT);
395
des_ecb_encrypt((des_cblock *)(obfkey + 8),
396
(des_cblock *)&fb[8], ks2, DES_DECRYPT);
398
/* sf27 wrap to sf25 */
399
//sf27( obfkey, (int*)&rid, fb );
401
for( i = 0; i < 0x10; i++ ) {
402
sprintf(buff+buff_len, "%.2x", fb[i] );
406
sprintf(buff+buff_len, "31d6cfe0d16ae931b73c59d7e0c089c0");
409
sprintf(buff+buff_len, ":::" );
412
/* add the hash to the list */
413
list_add_tail(list, buff);