Home | Chi sono | Contattami
 

Progr. lineare

Delphi
 
Componenti
  Database
 
Miei articoli

Windows

Miei articoli 

 

Passwords di Windows: LM Hash ed NT Hash ed il mistero svelato di 2 funzioni non documentate dal nome generico rispettivamente System006 e System007


La dll advapi32.dll esporta numerose funzioni tra cui diverse funzioni con nome insignificante del tipo System<3 cifre> . Son tutte funzioni non documentate ma di alcune di queste si conosce il significato. Il titolo di questo articolo forse un p fuorviante nel senso che non sto svelando al mondo misteri arcani; gi da tempo si conosce il significato delle System006 e System007, tuttavia non c' molto materiale al riguardo. Cos ho deciso di dare il mio umile contributo alla causa della diffusione della conoscenza riguardo a ste 2 benedette funzioni. Tagliamo corto e diciamo che la System006 restituisce l'LM Hash di una stringa (pi precisamente una null terminated string con caratteri presi dall'insieme ASCII) mentre la System007 restituisce l'NT Hash di una stringa (pi precisamente una counted string con caratteri presi dall'insieme UNICODE). Dar per scontato che si sappia cosa sono l'LM Hash e l'NT Hash tanto basta un p documentarsi sul web. Gi un anno f m'ero creato un applicativo che restituisce l'elenco delle utenze locali di Windows e per ognuna l'LM Hash e l'NT Hash:

Windows Password Hashes

l'applicativo si basa sul codice pubblicato da Todd A. Sabin nel 1998 (si, ... 10 anni f) e denominato pwdump2 a cui hanno fatto poi seguito altre versioni; le versioni pi recenti basate su quell'implementazione sono reperibili (tutte rigorosamente OpenSource) all'indirizzo

http://www.foofus.net/

La mia implementazione l'unica presente sul web che consiste in un una semplice procedura che esegue Code Injection su lsass.exe e preleva i valori di utenze e Hashes delle password; negli altri casi viene sempre utilizzata una dll da mappare nello spazio di memoria di lsass.exe; a suo tempo siccome non sapevo cosa fare decisi di implementare il tutto in una procedura che si occupasse di tutto. Basta quindi chiamare tale procedura e si ottiene l'elenco. Ma torniamo a noi e all'obiettivo di questo articolo: mi son creato 2 procedure wrapper, una che restituisce l'LM Hash e l'altra che restituisce l'NT Hash; da sottolineare che sia l'LM Hash sia l'NT hash non sono altro che una sequenza di 16 byte: quello che vediamo normalmente restituito in output ad esempio dal programma cui ho fatto riferimento, non altro che la rappresentazione esadecimale di quella sequenza; ogni byte richiede 2 cifre esadecimale per essere rappresentato, abbiamo 16 byte e quindi avremo 32 cifre esadecimali per la rappresentazione.

ecco le dichiarazioni

type PWHASH = record data: array[1..16] of Byte; end; PPWHASH = ^PWHASH; function RtlNtStatusToDosError( Status: Integer ): Cardinal; stdcall; external 'ntdll.dll'; function RtlAnsiStringToUnicodeString( DestinationString: PUNICODE_STRING; SourceString: PANSI_STRING; AllocateDestinationString: BOOLEAN ): Integer; stdcall; external 'ntdll.dll'; procedure RtlFreeUnicodeString(UnicodeString: PUNICODE_STRING); stdcall; external 'ntdll.dll'; function SystemFunction006( Password: PAnsiChar; HashLM: PPWHASH ): Cardinal; stdcall; external 'advapi32.dll'; function SystemFunction007( Password: PUNICODE_STRING; HashLM: PPWHASH ): Cardinal; stdcall; external 'advapi32.dll';

ed ora le implementazioni

function ErrStrNative(nomeFunc: string; status: Integer): Boolean; var error_code: Cardinal; error_description: string; error_string: string; begin result := False; error_string := nomeFunc + ': ' + 'NTSTATUSCODErr=' + IntToHex(status,8); error_code := RtlNtStatusToDosError(status); error_description := SysErrorMessage(error_code); error_string := error_string + '; CODErr=' + IntToStr(error_code) + '; Descr=' + error_description; ScriviLog(error_string); result := True; end; function CalcLMHash(Password: PAnsiChar; var LMHash: string): Boolean; var status: Integer; Hash: PWHASH; PassParam: PAnsiChar; begin Result := False; try if Length(Password) > 14 then begin PassParam := ''; end else begin PassParam := PAnsiChar(UpperCase(Password)); end; status := SystemFunction006(PassParam, @Hash); if status < 0 then begin ErrStrNative('SystemFunction006', status); Exit; end; LMHash := ConvertDataToHex(@Hash, 16, ''); result := True; finally end; end; function CalcNTHash(Password: PAnsiChar; var NTHash: string): Boolean; var PasswordAnsString: ANSI_STRING; PasswordUncString: UNICODE_STRING; AllocatedPasswordUncString: Boolean; status: Integer; Hash: PWHASH; begin Result := False; AllocatedPasswordUncString := False; try PasswordAnsString.Buffer := PAnsiChar(Password); PasswordAnsString.Length := Length(Password); PasswordAnsString.MaximumLength := PasswordAnsString.Length; status := RtlAnsiStringToUnicodeString( @PasswordUncString, @PasswordAnsString, True ); if status < 0 then begin ErrStrNative('RtlAnsiStringToUnicodeString', status); Exit; end; AllocatedPasswordUncString := True; status := SystemFunction007(@PasswordUncString, @Hash); if status < 0 then begin ErrStrNative('SystemFunction007', status); Exit; end; NTHash := ConvertDataToHex(@Hash, 16, ''); result := True; finally if AllocatedPasswordUncString then RtlFreeUnicodeString(@PasswordUncString); end; end;

hashes_undocumented.7z

 

 
 
Your Ad Here