No właśnie ,sprawa na pozór błacha ,ale jak się okazuje jednak nie do końca.
Ostatnio w pewnym małym projekcie zachciało mi się manipulować zasada z polisy lokalnej (OS == Windows XP) ,a mianowicie :
Ustawienia zabezpieczeń lokalnych->Zasady konta->Zasady haseł->Hasło musi spełniać wymagania co do złożoności
Jeżeli ktoś jeszcze dziwi się dlaczego w ogóle poruszam ten temat to już wyjaśniam ,że jak najbardziej nie chodzi o ustawienie tej zasady w sposób „klikany” ;), tylko software’owy.
Idąc po najmniejsze lini oporu zacząłem od zapytania googli o klucz/wartość w rejestrze systemowym odpowiedzialny/ą za powyższa zasadę. Niestety nic konkretnego nie udało mi się ustalić ;/. Hymm , no trudno , pomyślałem i już pełen nadziei i optymizmu zacząłem szperać w sieci pod kątem WinApi , które dostarczyło by mi możliwości odczytywania jak i modyfikacji bieżącego stanu zasad polis lokalnych. Szukam, szukam i nic!!!o_O.
Trochę nie chciałem na początku dowierzać ,no ale po chwili do mnie dotarło ,że jednak błyskawicznego rozwiązania na swój „problem” nie znajdę;/.
Oczywiście jak mógłbym się poddać wcześniej nie doprowadzając sprawy do końca;).
Niestety żadna defaultowa windows’owa aplikacja nie przychodziła mi do głowy (prócz mmc.exe + przystawka secpol.msc,,,ale było by za dużo zabawy :P, a jakiej? o tym za chwilę),która pozwała by na modyfikacje polis, ale jako ,że w przeszłości zajmowałem się dobrą chwilę platformą serwerową Windows 2003 do głowy przyszedł mi Resorce Kit Tools.
No i bingo!!! Znajdujemy tam aplikację PASSPROP ,która jak najbardziej spełnia stawiane przeze mnie wymagania:
Passprop.exe /?
Displays or modifies domain policies for password complexity and
administrator lockout.
PASSPROP [/complex] [/simple] [/adminlockout] [/noadminlockout]
/complex Force passwords to be complex, requiring passwords
to be a mix of upper and lowercase letters and
numbers or symbols.
/simple Allow passwords to be simple.
/adminlockout Allow the Administrator account to be locked out.
The Administrator account can still log on
interactively on domain controllers.
/noadminlockout Don't allow the administrator account to be locked out.
Jako ,żę aplikacja ta jest „opensource”(no co ?tak mówi OllyDbg:P), to rzućmy okiem na kod i sprawdźmy wywołania jakich WinApi pojawiają się przy użyciu przełącznika
„/complex”.
Lista wygląda następująco:
ADVAPI32.LsaOpenPolicy
ADVAPI32.LsaQueryInformationPolicy
ADVAPI32.LsaClose
SAMLIB.SamConnect
SAMLIB.SamOpenDomain
SAMLIB.SamQueryInformationDomain
SAMLIB.SamSetInformationDomain
SAMLIB.SamCloseHandle
SAMLIB.SamFreeMemory
Ahh, czyli jednak istnieją api do modyfikacji polis,ajjj Icewall,, Icewall,, nie umiesz szukać :P.Odetchnąłem z ulgą ,że mam już swoje upragnione api i natentychmiast udałem się na strone MSDN ,żeby zbadać ich detale. Bez większego problemu można znaleźć dokumentacje dotyczącą trzech pierwszych api ale dla wszystkich importowanych z SAMLIB już nie;/:
No Results Found For: SamOpenDomain.
Dziwne prawda? Nie wiem jakie były intencje MS przy podjęciu decyzji nie udokumentowania tych api ,no ale cóż .
Po moim małym rozczarowaniu na MSDN ,wrzuciłem „SamOpenDomain” w google, ale niestety i google tym razem było mało pomocne. Jedynym kawałkiem kodu wykorzystującym niektóre z powyższych api jaki znalazłem był kod PwDump’a 2.Nie bawiąc się w dalsze poszukiwania brakujących wskazówek czy wrapper’ów na te api (możliwe ,że NETAPI32 dostarcza podobną funkcjonalność) przystąpiłem do tego co tygrysy lubią najbardziej;).
RE Passprop.exe.
Skupie się jedynie na api , których nie wykorzystuje PwDump2,czyli :
SAMLIB.SamQueryInformationDomain
SAMLIB.SamSetInformationDomain
Jak widać na powyższym screen’e SamQueryInformationDomain
przyjmuje 3 parametry:
SamQueryInformationDomain(HANDLE hDomain,DWORD kind, SamInfoStruct**);
,gdzie z dalszych moich obserwacji wynika ,że struktura SamInfoStruct ,najprawdopodobnie wygląda tak:
struct SamInfoStruct
{
DWORD unknow;
DWORD flag;
};
Interesująca nas tutaj polem jest flag:
„Hasło musi spełniać wymagania co do złożoności”
0 – off
1 – on
No to już mamy procke do ustalenia bieżącej wartości tej zasady teraz jeszcze modyfikacja:
Jak można było się domyśleć SamSetInformationDomain przedstawia się podobnie:
SamSetInformationDomain (HANDLE hDomain,DWORD dunno,SamInfoStruct*);
No i na koniec mały kod wyłaczający/włączający zasade złożoności hasła w lokalnej polisie.
(kod jest „troche” nie chlujny na szybkiego wyciąłem go z projektu i wprowadziłem drobne modyfikacje:P)
———————————–CUT———————————————–
#include #include #include //--------------------------------------------------------------------------- struct SamInfoStruct { DWORD unknow; DWORD flag; }; typedef NTSTATUS (WINAPI *SamConnect_t) (DWORD, HANDLE*, DWORD, LSA_OBJECT_ATTRIBUTES*); typedef NTSTATUS (WINAPI *SamOpenDomain_t) (HANDLE,DWORD,PSID,HANDLE*); typedef NTSTATUS (WINAPI *SamQueryInformationDomain_t)(HANDLE,DWORD,SamInfoStruct**); typedef NTSTATUS (WINAPI *SamSetInformationDomain_t)(HANDLE,DWORD,SamInfoStruct*); typedef NTSTATUS (WINAPI *SamCloseHandle_t) (HANDLE); typedef NTSTATUS (WINAPI *SamFreeMemory_t) (SamInfoStruct*); using namespace std; bool ComplexPassword(string inOperationType,bool inSet); int main(int argc, char** argv) { bool flag; if(argc<2) return 0; switch(argv[1][0]) { case '0': flag = false; break; case '1': flag = true; break; default: return 0; } cout<<"Haslo musi spelniac wymagania co do zlozonosci: " <<ComplexPassword("check",0) <<endl; //ustawienie flagi przy sprawdzaniu nie ma znaczenia //set flag ComplexPassword("set",flag); cout<<"Haslo musi spelniac wymagania co do zlozonosci: " <<ComplexPassword("check",0) <<endl; return 0; } bool ComplexPassword(string inOperationType,bool inSet) { LSA_HANDLE hPolicy = NULL; LSA_OBJECT_ATTRIBUTES objAttrib; POLICY_ACCOUNT_DOMAIN_INFO* pDomainInfo; SamInfoStruct *SamInfo = NULL; HANDLE hSam = 0; HANDLE hDomain = 0; SamConnect_t SamConnect; SamOpenDomain_t SamOpenDomain; SamQueryInformationDomain_t SamQueryInformationDomain; SamSetInformationDomain_t SamSetInformationDomain; SamCloseHandle_t SamCloseHandle; SamFreeMemory_t SamFreeMemory; HMODULE hLib = LoadLibrary("samlib.dll"); SamConnect = (SamConnect_t) GetProcAddress(hLib,"SamConnect"); SamOpenDomain = (SamOpenDomain_t) GetProcAddress(hLib,"SamOpenDomain"); SamQueryInformationDomain = (SamQueryInformationDomain_t) GetProcAddress(hLib,"SamQueryInformationDomain"); SamSetInformationDomain = (SamSetInformationDomain_t) GetProcAddress(hLib,"SamSetInformationDomain"); SamCloseHandle = (SamCloseHandle_t) GetProcAddress(hLib,"SamCloseHandle"); SamFreeMemory = (SamFreeMemory_t) GetProcAddress(hLib,"SamFreeMemory"); //tak tak tak ...zakładam ,że lib'a i wszystkie adresy usdało sie załadować pomyślnie memset(&objAttrib,0,sizeof(objAttrib)); objAttrib.Length = sizeof(objAttrib); if(LsaOpenPolicy(NULL,&objAttrib,POLICY_ALL_ACCESS,&hPolicy)!= 0) { cout<<"Password complexity check error: "<<GetLastError(); return false; } LsaQueryInformationPolicy(hPolicy, PolicyAccountDomainInformation, (void**)&pDomainInfo); LsaClose(hPolicy); if(SamConnect(0, &hSam, 0x20,&objAttrib)<0) { cout<<"SamConnect error: "<DomainSid,&hDomain)<0) { cout<<"SamOpenDomain error: "<<GetLastError(); goto bad_boy; } if(SamQueryInformationDomain(hDomain,0x1,&SamInfo)<0) { cout<<"SamQueryInformationDomain error: "<flag != 0x1) goto bad_boy; inSet = true; } else { SamInfo->flag = (DWORD)inSet; if(SamSetInformationDomain(hDomain,0x1,SamInfo)<0) { cout<<"SamSetInformationDomain error: "<<GetLastError(); goto bad_boy; } } SamCloseHandle(hDomain); SamCloseHandle(hSam); if(SamInfo!=0) SamFreeMemory(SamInfo); FreeLibrary(hLib); return inSet; bad_boy: if(hDomain !=0) SamCloseHandle(hDomain); SamCloseHandle(hSam); if(SamInfo!=0) SamFreeMemory(SamInfo); FreeLibrary(hLib); return false; }
———————————–CUT———————————————–
Przykładowa sesja:
pass.exe 1
Haslo musi spelniac wymagania co do zlozonosci: 0
Haslo musi spelniac wymagania co do zlozonosci: 1
I to by było na tyle:).
Jeżeli ktoś spotkał się z dokumentacją api z SAMLIB lub wrraperami z innego lib’a to będe wdzięczny za link.
bieżący nie bierzący 😀
pozdrawiam 🙂
Już poprawiłem 😉
Btw:thx za pierwszy komentarz:D