Home | Chi sono | Contattami
 

Progr. lineare

Delphi
 
Componenti
  Database
 
Miei articoli

Windows

Miei articoli 

 

Intercettare le modifiche alle password utente, eseguirne una convalida e creare un log di utenze e password


In questo articolo voglio esporre una tecnica che consente di rilevare tutte le modifiche effettuate sulle password degli account di sistema e registrare ogni valore in un file di log. Il tutto verrà effettuato sfruttando un protocollo già previsto da Windows e che viene usato ad esempio per convalidare le nuove password in base a svariati criteri come ad esempio impedire la definizione di password sotto una certa lunghezza.

1. Eccoci quà

In Windows 2000/XP/2003, tutte le volte che viene modificata la password di una utenza, il sistema guarda nel registro se è stata definita una dll che faccia da filtro per le password: in caso affermativo va a chiamare i metodi previsti dall' architettura del protocollo di modifica password così come sono stati implementati nella dll in questione. In pratica il concetto è analogo a quello di funzione callback o agli stessi eventi che si hanno nei componenti Delphi: per poter consentire a chi usa un tuo componente di eseguire determinate operazioni nel contesto di una determinata procedura, si fornisce un evento che non è altro che una proprietà di tipo procedura la quale può essere implementata da chi usa il componente e quindi, essendo chiamata dai metodi del componente, consente la personalizzazione del metodo in questione. Naturalmente chi sviluppa il componente Delphi definisce il tipo di procedura (argomenti, tipo in output, etc..); allo stesso modo anche la dll di filtraggio password cui si fa riferimento sopra dovrà prevedere l' implementazioni di procedure il cui nome e la cui tipologia sono stati definiti da Microsoft: quando viene richiesto il cambiamento di una password (tramite le normali applet nel Pannello di Controllo per la gestione delle utenze), Windows controlla nel registro se è stata impostata una dll che faccia da filtro password e, in caso affermativo, chiama le procedure prestabilite passandogli l' utenza e la nuova password; l' implementazione di tali procedure nella dll di filtraggio password determina il comportamento che il sistema assume di fronte al cambio password: se ad esempio l' implementazione delle procedure consiste in un controllo sulla lunghezza della password e la password inserita non rispetta la lunghezza imposta, allora Windows comunica un messaggio di errore. Per essere più precisi la parte di Windows che si occupa di queste operazioni è LSA (Local Security Authority). LSA è implementata nell' eseguibile lsass.exe; se si utilizza ProcessExplorer (da www.sysinternals.com) e si esegue un "Find -> Find dll...", specificando la dll usata come filtro, si vede appunto che tale dll rientra tra le dll caricate dall' eseguibile lsass.exe. Ad ogni avvio lsass.exe, tra le tante cose, cerca in una apposita chiave del registro se esistono dll per il filtraggio password ed in caso affermativo le carica in memoria.

La chiave di registro in cui deve essere scritto il nome della propria dll per il filtraggio delle password è la seguente:

HKLM\System\CurrentControlSet\Control\Lsa

il valore i cui dati contengono il nome della dll (e di tutte le altre dll che fanno da filtro per le password utente) è il seguente:

Notification Packages

è di tipo REG_MULTI_SZ (se si è in Windows 2000 lo si può gestire con regedt32.exe mentra per quanto riguarda Windows XP/2003 non c' è nessun problema a gestirlo direttamente con regedit.exe)

bisogna scrivere il nome della dll rigorosamente senza l' estensione .dll. Dovendo scrivere solo il nome senza il percorso è chiaro che tale dll va copiata nella cartella di sistema (c:\windows\system32 per Windows xp/2003, c:\winnt\system32 per Windows 2000)

Le procedure che verranno chiamate da Windows (e che quindi devono essere implementate nella dll) sono le seguenti (in ordine di chiamata):

1) InitializeChangeNotify
2) PasswordFilter
3) PasswordChangeNotify

andiamole ad analizzare una ad una

2. InitializeChangeNotify

function InitializeChangeNotify: BOOL; stdcall;

InitializeChangeNotify viene chiamata per verificare che la dll sia caricata ed inizializzata: la sua implementazione consiste in genere nella definizione delle varie variabili che saranno poi usate nel contesto della procedura di validazione vera e propria e cioè PasswordFilter (di seguito): ad esempio vi si può definire la lunghezza della password, i caratteri richiesti, etc... LSA chiama questa funzione subito dopo aver caricato la dll in memoria all' avvio del sistema.

3. PasswordFilter

function PasswordFilter(Nome_Utente: PUnicode_String, Nome_Completo: PUnicode_String, Password: PUnicode_String; SetOperation: Boolean): Boolean; stdcall;

PasswordFilter si esegue il controllo della password: se la funzione restituisce true allora il sistema accetta la nuova password, in caso contrario viene inviato un messaggio di errore. E' da osservare che possono essere definite più di una dll per il filtro password (come dimostra anche la tipologia REG_MULTI_SZ del valore di registro "Notification Packages" che raccoglie appunto i nomi di tutte le dll in questione), quindi per essere precisi, in caso di successo con il filtro in questione, poi dovranno essere verificate anche le condizioni imposte da tutti gli altri filtri.

PUnicode_String è definito nel seguente modo

type TUnicode_string = record Length: Word; MaximumLength: Word; Buffer: PWideChar; end; PUnicode_String = ^TUnicode_String;

SetOperation è TRUE se viene impostata una password (l' utente non ha password e gliene viene assegnata una), mentre è FALSE se viene cambiata una password.

4. PasswordChangeNotify

function PasswordChangeNotify(Nome_Utente: PUnicode_String; RelativeId: Cardinal; NewPassword: PUnicodeString ): Cardinal; stdcall;

Questa funzione è chiamata dopo che PasswordFilter è stata chiamata con successo (ha restituito TRUE) e la nuova password è stata effettivamente salvata. Deve restituire 0 se tutto OK. Questa funzione può essere usata ad esempio per raccogliere in un file, utenza e password ogni volta che viene modificata una password.

5. Condizioni sulle password in Windows

In windows 2000/XP/2003 esiste, nel contesto dei "Criteri di protezione locale", la possibilità di imporre un filtro sulle password inserite:

Criteri account -->Criterio password --> Le password devono essere conformi ai requisiti di complessità

e anche

Criteri account --> Criterio password --> Lunghezza minima password

In particolare i requisiti di complessità consistono in:

1) La password non deve contenere il NOME UTENTE o ogni parte del NOME COMPLETO
2) La password deve essere lunga almeno 6
3) La password deve contenere elementi da 3 dei seguenti 4 tipi di carattere



6. Creiamoci la nostra dll di filtro

Passiamo quindi alla creazione di una dll per il filtro delle password ed anche il log delle medesime assieme all' utenza corrispondente, ogni volta che vengono cambiate:

library PwdFilter; uses Windows, SysUtils; type TUnicode_string = record Length: Word; MaximumLength: Word; Buffer: PWideChar; end; PUnicode_String = ^TUnicode_String; function GetStringTypeW( dwInfoType: DWORD; lpSrcStr: PWideChar; cchSrc: Integer; lpCharType: PWord ): BOOL; stdcall; external kernel32 name 'GetStringTypeW'; var //elenco condizioni da verificare sulla password che //si vuole impostare LunghezzaPassword: integer; //lunghezza minima della password LettereMaiuscole: boolean; //presenza di lettere maiuscole LettereMinuscole: boolean; //presenza di lettere minuscole Cifre: boolean; //presenza di cifre (0-9) function InitializeChangeNotify: BOOL; stdcall; begin //definizione delle condizioni sulla password LunghezzaPassword := 10; LettereMaiuscole := True; LettereMinuscole := True; Cifre := True; //la password deve quindi essere lunga almeno 10 caratteri, //contenere sia lettere maiuscole sia minuscole e contenere cifre. Result := True; end; function PasswordFilter( Nome_Utente, Nome_Completo, Password: PUnicode_String; SetOperation: BOOL ): BOOL; stdcall; type TWordArray = array [0..(MaxInt div SizeOf(Word)) - 1] of Word; PWordArray = ^TWordArray; var LunghezzaPasswordInserita: integer; ContieneLettereMaiuscole: boolean; //presenza di lettere maiuscole ContieneLettereMinuscole: boolean; //presenza di lettere minuscole ContieneCifre: boolean; //presenza di cifre (0-9) CharType: PWordArray; i: integer; begin Result := True; CharType := HeapAlloc(GetProcessHeap, 0, Password^.Length); try LunghezzaPasswordInserita := Password^.Length div SizeOf(WideChar); if GetStringTypeW( CT_CTYPE1, Password^.Buffer, LunghezzaPasswordInserita, PWord(CharType) ) then begin ContieneLettereMaiuscole := False; ContieneLettereMinuscole := False; ContieneCifre := False; for i := 0 to LunghezzaPasswordInserita - 1 do begin if (CharType^[i] and C1_UPPER) = C1_UPPER then begin ContieneLettereMaiuscole := True; Continue; end; if (CharType^[i] and C1_LOWER) = C1_LOWER then begin ContieneLettereMinuscole := True; Continue; end; if (CharType^[i] and C1_DIGIT) = C1_DIGIT then begin ContieneCifre := True; Continue; end; end; Result := (LunghezzaPasswordInserita >= LunghezzaPassword) and (ContieneLettereMaiuscole and LettereMaiuscole) = LettereMaiuscole) and ((ContieneLettereMinuscole and LettereMinuscole) = LettereMinuscole) and ((ContieneCifre and Cifre) = Cifre); end; finally ZeroMemory(CharType, Password^.Length); HeapFree(GetProcessHeap, 0, CharType); end; end; function PasswordChangeNotify( Nome_Utente: PUnicode_String; RelativeId: ULONG; NewPassword: PUnicode_String ): Longint; stdcall; var pwdFile : TextFile; str : string; FileHandle: integer; begin //salviamo sul file c:\pwd.txt la nuova password: //data_ora --- Utenza --- Nuova_Password str := DateTimeToStr(Now) + '---' + Nome_Utente^.Buffer + '---' + NewPassword^.Buffer + #13#10; if not FileExists('c:\pwd.txt') then begin FileHandle := FileCreate('c:\pwd.txt'); FileClose(FileHandle); end; AssignFile(pwdFile, 'c:\pwd.txt'); Append(pwdFile); WriteLn(pwdFile, str); CloseFile(pwdFile); Result := 0; end; exports PasswordChangeNotify, InitializeChangeNotify, PasswordFilter; end.

7. Gli ultimi passaggi

A questo punto si copia la dll ottenuta nella cartella system32, si apre regedit (regedt32 su Windows 2000), si va sulla chiave

HKLM\System\CurrentControlSet\Control\Lsa

si edita il valore

Notification Packages

e si aggiunge il nome della dll (rigorosamente senza estensione .dll)

 



 

 


 

 
 
Your Ad Here