Skip Ribbon Commands
Skip to main content

Ondrej Sevecek's Blog

:

Engineering and troubleshooting by Directory Master!
Ondrej Sevecek's Blog > Posts > Účty, které si už dlouho nezměnily heslo aneb pwdLastSet atribut
leden 21
Účty, které si už dlouho nezměnily heslo aneb pwdLastSet atribut

O heslech v Active Direcotry (AD DS) jsem už psal třeba tady a tady a tady. Ale dnes jsem dostal mailem otázku, jak zjistím všechny účty, které si nezměnily svoje výchozí heslo.

Takový skript bude o něco složitější, takže můžeme začít nejprve jednoduše. Zjistíme všechny uživatelské účty, které si už dlouho nezměnili heslo. Déle v mém skriptu znamená déle než třicet dnů:

dsquery * domainRoot -filter "(&(objectCategory=person)(objectClass=user)(!userAccountControl:1.2.840.113556.1.4.803:=2)(pwdLastSet<=$(([DateTime]::Now.AddDays(-30) - [DateTime]::Parse('1601-01-01')).Ticks))(pwdLastSet>=1))" -attr sAMAccountName,userPrincipalName

Používám k tomu PowerShell a v něm utilitu dsquery, protože ActiveDirectory module každý nemá. Používám standardní LDAP search string. Uvnitř začínám s filterm na objectCategory=person, protože tohle je na všech verzích schematu indexované a tím pádem to bude maximálně rychlé. Vyhledají se tím user a inetOrgPerson účty a také contact objekty, které ale nechceme. Dále tedy potřebujeme filter na objectClass=user, abychom vyhodili kontakty.

Následně tam mám filter na userAccountControl, který nesmí obsahovat bit 2 - tedy účet nesmí být zakázaný (disabled), technickými slovy mít příznak ACCOUNTDISABLE. V tomhle filtříku se používá bitový AND (bitwise and) vyhledávací MS OID modifikátor 1.2.840.113556.1.4.803.

A dále už k tomu nejdůležitějšímu - tedy pwdLastSet. Atribut pwdLastSet obvykle obsahuje datum poslední modifikace hesla. Píšu obvykle, protože to není vždy. Pokud zaškrtnete na účtu, že si uživatel musí změnit heslo při příštím přihlášení (user must change password at next logon), tak to ve skutečnosti pouze vynuluje pwdLastSet atribut. Pokud tohle zaškrtávátko někdy později vypnete, tak do pwdLastSet nastaví natvrdo aktuální datum.

Takže tomuhle atributu je potřeba věřit jenom tak nějak opatrně :-) Proto testuju, jestli je sice starší, než 30 dnů, ale současně musí být hodnota větší než 0. V LDAP filterech nemůžete používat ostrou nerovnost, takže nezbývá než porovnávat na větší rovno 1.

Co tímhle vyhledávacím filtrem tedy najdete? Účty, které si už opravdu dlouho nezměnily heslo. Ale nenajdete účty, kterým bylo manipulováno s příznakem user must change password at next logon.

Ale už i tohle by mohlo někomu stačit.

Lepší vyhledání všech nezměněných hesel pomocí replikačních metadat

Možná vám nestačí nedokonalý atribut pwdLastSet. Máme jinou metodu? Ano. Musíme se podívat na vnitřní replikační metadata (replication metadata) každého jednotlivého uživatele a zjistit, kdy se naposledy skutečně změnilo heslo v atributu unicodePwd. Bez téhle informace nemůže fungovat replikace, takže to je naprosto přesná a jistá hodnota. Akorát to bude trvat déle, protože replikační metadata (přesněji řečeno žádný computed/constructed atribute) nelze vyhledat rovnou pomocí LDAP search.

Musíme si načíst každý účet, z něho vyndat constructed atribut msDS-ReplAttributeMetaData a z něho to vyčíst. Upozorňuji, že to funguje až od DC řadičích verze Windows 2003. Na řadičích Windows 2000 tento atribut nebyl k dispozici.

function Get-UnchangedPasswords ([int] $sincePastDays) 
{
  $root = [ADSI] 'LDAP://RootDSE'
  $searcher = [ADSISearcher] ([ADSI] ('LDAP://{0}' -f $root.defaultNamingContext.Value))
  $searcher.Filter = '(&(objectCategory=person)(objectClass=user))'
  $searcher.SearchScope = 'subTree'

  [Collections.ArrayList] $nonChangedPasswords = @()

  $pastDate = [DateTime]::Now.AddDays(- $sincePastDays)

  foreach ($oneResult in $searcher.FindAll()) { 

    $user = [ADSI] $oneResult.Path
    $user.RefreshCache('replPropertyMetadata')
    $user.RefreshCache('msDS-ReplAttributeMetaData')
    $replBin = $user.Get('replPropertyMetadata')
    $replBinText = [BitConverter]::ToString($replBin)
    $replTxt = $user.Get('msDS-ReplAttributeMetaData')

    $unicodePwdReplMeta = $replTxt | % { [xml] $_ } | ? { $_.DS_REPL_ATTR_META_DATA.pszAttributeName -eq 'unicodePwd' } | select -Expand DS_REPL_ATTR_META_DATA
 
    $theDate = [DateTime]::Parse($unicodePwdReplMeta.ftimeLastOriginatingChange)
    if ($theDate -le $pastDate) {

      $nonChangedPwd = New-Object PSCustomObject
      Add-Member -Input $nonChangedPwd -MemberType NoteProperty -Name sam -Value $user.sAMAccountName.Value
      Add-Member -Input $nonChangedPwd -MemberType NoteProperty -Name upn -Value $user.userPrincipalName.Value
      Add-Member -Input $nonChangedPwd -MemberType NoteProperty -Name lastPwdChange -Value $theDate
      Add-Member -Input $nonChangedPwd -MemberType NoteProperty -Name isDisabled -Value ((([int] $user.userAccountControl.Value) -band 2) -eq 2)
      Add-Member -Input $nonChangedPwd -MemberType NoteProperty -Name created -Value $user.whenCreated.Value
      [void] $nonChangedPasswords.Add($nonChangedPwd)
    }
  }

  return $nonChangedPasswords
}

No a to je celá věda :-) Další třídění a filtrování už zvládnete sami.

Comments

Re: Účty, které si už dlouho nezměnily heslo aneb pwdLastSet atribut

jen pro doplnění, atribut msDS-ReplAttributeMetaData je constructed/computed atribut, který zobrazuje v XML formě to stejné, co je od jakživa v binárním atributu replPropertyMetadata. Binárně se s tím blbě pracuje, takže raději použijeme XML formu msDS-ReplAttributeMetaData.

dále bych připomněl, že replication metadata je možné obvykle z příkazové řádky prohlížet jednodušeji pomocí:

repadmin /showobjmeta
ondass on 21.1.2016 13:46

Re: Účty, které si už dlouho nezměnily heslo aneb pwdLastSet atribut

Zaujimalo by ma ci je mozne detekovat ci si uzivatel pri zmene hesla toto naozaj zmenil? Uzivatelia ktori maju na domene urcite vyssie prava si dokazu vynutit zmenu hesla a v tomto kroku nastavit rovnake heslo ako mali predtym. Toto by som chcel zdetekovat, ale nedari sa mi prist na to ako. Idealne by bolo keby sa dalo aj zistit kedy si heslo realne zmenili, tj zmenila sa jeho hodnota.
Ludia ktori si heslo extenduju cez znamy trik s polickom user must change password on next logon sa daju odhalit pomocou skriptu uvedeneho vyssie ale skupina ktora si heslo meni na stale rovnaku hodnotu tu stale unika.

Dakujem
Marek on 19.2.2016 14:25

Re: Účty, které si už dlouho nezměnily heslo aneb pwdLastSet atribut

to není možné zjistit jen takto jednoduše. musela by se vyčíst historie hesel (password history), přesněji řečeno heší, a z té to posoudit, protože i reset hesla posouvá předchozí (stejnou) hash do historie.
ondass on 21.2.2016 10:00

Add Comment

Title


Pole Title nemusíte vyplňovat, doplní se to samo na stejnou hodnotu jako je nadpis článku.

Author *


Pole Author nesmí být stejné jako pole Title! Mám to tu jako ochranu proti spamu. Roboti to nevyplní dobře :-)

Body *


Type number two as digit *


Semhle vyplňte číslici dvě. Předchozí antispemové pole nefunguje úplně dokonale, zdá se, že jsou i spamery, které pochopily, že je občas potřeba vyplnit autora :-)

Email


Emailová adresa, pokud na ni chcete ode mě dostat odpověď. Nikdo jiný než já vaši emailovou adresu neuvidí.

Attachments