Tak to se roztrhl pytel. Za poslední dva roky jsem řešil už tři konkrétní případy, kdy nějaký naštvaný/vyhozený zaměstnanec způsoboval firmě poměrně zásadní problém. A přitom mu to nedokážete a navíc to jde hodně špatně omezit.
Scénář pro lidi, co chtějí pičovat
Jste zaměstnanci. Někdo vás naštve a případně i vyhodí. Jste z povahy pičingeři. Co uděláte?
Buď s tím počítáte už dopředu, nebo to ještě stihnete připravit, než vám seberou přístup. Jediné co potřebujete je zjistit seznam všech loginů. Seznam všech doménových loginů může ve výchozím stavu získat libovolný ověřený uživatel. Stačí úplně obyčejný účet. Dokonce stačí, když máte lokální účet na nějakém doménovém počítači. Různé metody zjištění seznamu účtů ze stanice následují. Tohle externista neudělá, musí to být útočník s interním přístupem:
gwmi -query ('SELECT * FROM Win32_UserAccount WHERE Domain <> "{0}"' -f [Environment]::MachineName)
A tohle funguje i v případě, že jste pouhými lokálními uživateli na libovolném doménovém počítači:
function global:Get-PrimaryDomainSID ()
{
# Note: this script obtains SID of the primary AD domain for the local computer. It works both
# if the local computer is a domain member (DomainRole = 1 or DomainRole = 3)
# or if the local computer is a domain controller (DomainRole = 4 or DomainRole = 4).
# The code works even under local user account and does not require calling user
# to be domain account. This should also work on any AD domain regardless of language
# mutation because, hopefully, the krbtgt account has always the same name
[string] $domainSID = $null
[int] $domainRole = gwmi Win32_ComputerSystem | Select -Expand DomainRole
[bool] $isDomainMember = ($domainRole -ne 0) -and ($domainRole -ne 2)
if ($isDomainMember) {
[string] $domain = gwmi Win32_ComputerSystem | Select -Expand Domain
[string] $krbtgtSID = (New-Object Security.Principal.NTAccount $domain\krbtgt).Translate([Security.Principal.SecurityIdentifier]).Value
$domainSID = $krbtgtSID.SubString(0, $krbtgtSID.LastIndexOf('-'))
}
return $domainSID
}
$domainSID = Get-PrimaryDomainSID
(500..10000) | % {
$user = New-Object Security.Principal.SecurityIdentifier $domainSID-$_
$errorActionPreference = 'SilentlyContinue'
$user.Translate([Type]::GetType('System.Security.Principal.NTAccount')).Value
$errorActionPreference = 'Continue'
}
Pokud ten parchant získal seznam všech loginů z Active Directory, může začít otravovat.
Nejhorší metoda je pozamykat všechny AD účty z internetu
Představte si, že si udělá skript, který spustí na svém počítači někde v internetu. Samozřejmě to udělá někde v KFC, nebo v kavárně a podobně. Pokaždé na jiné, totálně anonymní IP adrese. A bude to dělat jednou za čas, když si ta svině někdy vzpomene, jakou mu kdo v bývalé práci udělal bolístku.
Skript se pokusí připojit na nějakou vaši službu s venkovním přístupem. Například VPN, nebo podstatně hůře nějaký web - SharePoint, nebo KDC proxy, nebo Exchange, nebo RD Gateway (viz. například můj nedávný článeček). To všechno vyžaduje AD ověření. A prostě vyzkouší několik náhodných hesel pro každý účet. Ne moc. Stačí tolik, aby se ten účet zamknul. Není vůbec cílem ta hesla prolomit.
Proti tomu skoro není obrana. Když se to stane poprvé, všechny účty odemknete a zakážete tu jednu IP adresu. A za pár dnů to máte znovu z jiné IP adresy. A pak zase. Můžete také změnit lidem loginy :-( A útočník se směje, protože taková akce bude trvat pár sekund i vůči tisícům účtů.
Nejhorší je, že to funguje na všechny účty, i když tu VPN má povoleno jen několik lidí. Protože ověřit uživatele musíte dříve, než se zjistí, že se na VPN nedostane. Takže ty pokusy o přihlášení se v každém případě proženou do AD na každý zkoušený účet. Takže všechny účty, a když říkám všechny, tak samozřejmě myslím i účty servisní a účty správců - kromě built-in administrator účtu (ten co má SID koncovku -500).
Hrůza.
Řešení pomocí přihlašování certifikátem, ideálně čipovou kartou
Optimální řešení je samozřejmě mít veškerá vnější připojení pomocí certifikátu, ještě lépe rovnou používat čipové karty (smart card). Útočník certifikát nefejkne.
Jenže kdo to má, že přátelé?
Částečné řešení pro RRAS VPN
Pokud máte RRAS (Remote Access Services) VPN a váš NPS server běží alespoň na Windows 2008 nebo je novější, můžete použít NPS account lockout. O co jde? V podstatě na NPS RADIUS serveru nastavíte zamykání účtů po menším počtu pokusů, než je nastaveno na Active Directory. Dělá se to pomocí registrového klíče:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\RemoteAccess\Parameters\AccountLockout
a registrových hodnot MaxDenials a ResetTime (mins) - viz. ten článek v odkazu.
Výsledek je, že útočník sice pozamyká všechny účty pro přístup přes VPN, ale už je nezamkne v AD. Ne že by to bylo moc velká úleva, ale pořád vám budou lidi pracovat alespoň vevnitř.
Těžko řešitelné webové služby
Podstatně větší problém je v případě, že máte Basic, nebo Windows Authentication na webovém serveru vystrčeném do internetu. Tam nevím o ničem, co by umělo takovýto snížený práh (threshold) zamykání udělat samo o sobě. To není případ jen normálního IIS web serveru, jako je SharePoint nebo Exchange. Takto se ověřujete také do RD Gateway, nebo i DirectAccess při KDC proxy bez certifikátů při čistém IPv6.
Navíc naskriptovat webového klienta s ověřením jsou tři řádky v PowerShell.
Jediné jednodušší řešení pro webové služby je WAP (Web Application Proxy) a AD FS 3.0, které máte na Windows 2012 R2. WAP je reverse HTTPS proxy (HTTPS publishing), která umí ověřovat uživatele ještě před vstupem na vnitřní web server. Ověřuje je pomocí AD FS (Active Directory Federation Services, ADFS).
A právě AD FS 3.0 dorazilo s novinkou zvanou AD FS Extranet Lockout. Je to stejné, jako v případě toho NPS account lockout. Pomocí cmdlet Set-AdfsProperties a tří parametrů EnableExtranetLockout, ExtranetLockoutThreshold a ExtranetObservationWindow nastavíte vcelku intuitivní hodnoty. Samozřejmě menší práh, než máte na Active Directory.
Jiné řešení mě napadlo vystrčit k danému webovému serveru do DMZ jenom jeho vlastní RODC. RODC samo také zamyká účty, i když je totálně odpojené. Sice nemůže mít vlastní nastavení jiného počtu špatných pokusů, ale můžete ho dopojit. Pokud je odpojené od zbytku zapisovatelných DC, tak se účet zamkne jenom lokálně na RODC samotném a už se to ale zpět nikdy nereplikuje. Máte taky možnost určit, které účty na něm vůbec budou.
Tzn. například jen jednou za den RODC připojujete do vnitřní sítě na několik minutek, aby se zreplikovalo. Po většinu dne je odpojené a slouží jenom jako ověřovací server, například pro RD Gateway. To se zvládne malinkým naplánovaným skriptíkem, který přenastavuje Windows Firewall na RODC pomocí NETSH a vyvolává AD replikaci pomocí REPADMIN. A přítom může mít nastavení takové, že se na RODC dostanete zevnitř, kvůli vzdálené správě.
Někde jsem četl, že někdo doporučoval k omezení tohoto typu útoku pro IIS novinku Windows 2012 zvanou Dynamic IP restrictions, ale to je v případě, že útočník je/byl internistou a má seznam všech skutečně existujících loginů, úplně k nepotřebě.
Závěr
Prostě nic příjemného. Pokud máte vnější přístup, ideálně používejte k ověřování certifikáty hned od začátku a zamyslete se nad tímto nepříjemným problémem.
Kurz na zabezpečení vzdáleného přístupu mám i v GOPASu jako GOC167.