We all know that bad actors often create accounts for repeat access when they gain access to your network. To make sure that we are aware of these situations we user PowerShell monitoring.
For security measures we monitor 3 types of user creation:
- All created domain users,
- All users added privileged groups(e.g. Domain Admins)
- All created local users.
- All (Temporary) users created that contain specific keywords.
Temporary users Monitoring:
The temporary users monitoring set is only used on active directory users, not local users. as we’re already monitoring all local user creation this would be redudant.
1
2
3
4
5
6
7
8
9
10
11
12
|
$ArrayOfNames = @("test", "tmp","skykick","mig", "migwiz","temp","-admin","supervisor")
foreach($name in $ArrayOfNames){
$filter = 'Name -like "*'+ $($name) + '*"'
$Users = Get-ADUser -Filter $filter
if($users -ne $null){
foreach($user in $users){
$TemporaryUser += "$($user.name) has been found, created at $($user.whencreated)`n"
}
}
}
if(!$TemporaryUser){$Userlist = "No Temporary Accounts Found" }
|
Created Domain Users
For domain users, we alert on all users created in the last 24 hours. after 24 hours this monitoring set goes back to a healthy state.
1
2
3
4
5
6
7
8
|
$When = ((Get-Date).AddDays(-1)).Date
$GetUsers = Get-ADUser -Filter {whenCreated -ge $When} -Properties whenCreated
foreach($user in $GetUsers){
$userchanges += "$($user.name) has been created at $($user.whencreated) `n"
}
if($UserChanges -eq $Null) { $UserChanges = "No Changes Detected"}
|
All created local users
Local users do not have a creation date, that makes it a little more difficult to monitor. To solve this we create a file with the results of get-localuser, We update that file every 24 hours. Then from there on, we compare the file to the most recent results of the output of get-localuser. We are alerted if the compare finds newer content, Meaning a user has been created or removed in the local user database.
1
2
3
4
5
6
7
8
9
10
|
$Outputfile = "C:\Windows\temp\LocalUsers.txt"
$Localusers = Get-LocalUser | Select-Object *
Test-Path $Outputfile | %{if($_ -eq $false){new-item $Outputfile} }
$OutPutFileContents = Get-Content $Outputfile | ConvertFrom-Json
If((get-item $Outputfile).LastWriteTime -lt (Get-Date).AddDays((-1))){ $Localusers | ConvertTo-Json |out-file $Outputfile }
$Compare = Compare-Object -DifferenceObject $OutPutFileContents.name -ReferenceObject $Localusers.name
if(!$Compare) { $Compare = "Healthy"}
|
Privileged Group Changes
We monitor the privileged groups by using Ashley McGlone’s script to get the changes. You can find that full script here.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
Function Get-PrivilegedGroupChanges {
Param(
$Server = "localhost",
$Hour = 24
)
$ProtectedGroups = Get-ADGroup -Filter 'AdminCount -eq 1' -Server $Server
$Members = @()
ForEach ($Group in $ProtectedGroups) {
$Members += Get-ADReplicationAttributeMetadata -Server $Server `
-Object $Group.DistinguishedName -ShowAllLinkedValues |
Where-Object {$_.IsLinkValue} |
Select-Object @{name='GroupDN';expression={$Group.DistinguishedName}}, `
@{name='GroupName';expression={$Group.Name}}, *
}
$Members |
Where-Object {$_.LastOriginatingChangeTime -gt (Get-Date).AddHours(-1 * $Hour)}
}
$ListOfChanges = Get-PrivilegedGroupChanges
if($ListOfChanges -eq $Null)
{
$GroupChanges = "No Changes Detected"
}
else {
foreach($item in $ListOfChanges){
$GroupChanges += "Group $($ListOfChanges.GroupName) has been changed - $($listofchanges.AttributeValue) has been added or removed"
}
}
if(!$groupChanges) { $GroupChanges = "No Changes Detected"}
|