May 06 2022 02:20 AM
Hello All,
I have PowerShell script which generates the data from each local server. This script tested and its working fine but the challenge is it trigger the alert on AD server as "user of computer logged on to this computer from the network" , but script is executing on any server not on AD. Why this is happening I am not able to find out it. Is the AD level security configured or hardening which is creating this problem.
Where I do find the exact cause of this. Can any one help me please.
I am attaching the script here for the reference.
############################Script#####################
$Computer = $env:ComputerName
$OutputDir = "c:\temp\"
$Name = ($OutputDir + $Computer + "_LocalUser.csv")
out-file -filepath $Name
$OutputFile = $Name
Add-Content -Path $OutPutFile -Value "ComputerName;OS;IP;UserID;FullName;SID;UserType;PasswordLastSet;Enabled;UserMayChangePassword;PasswordNeverExpires;InteractiveLogon;AccessDetails;LastLogOn;TimeZone"
$LocalUsers = Get-WmiObject -Class Win32_UserAccount -Filter "LocalAccount=True" | Select-Object -ExpandProperty Name
$localgroups = Get-WmiObject Win32_Group -Filter “LocalAccount=True” | Select-Object -ExpandProperty Name
$groupsOutput = $null
$IP = $(((ipconfig | findstr [0-9].\.)[0]).Split()[-1])
if($PSVersionTable.PSVersion.Major -gt 4){
foreach($localuser in $LocalUsers) {
$Name = $localuser
$FullName = Get-LocalUser -Name $localuser | Select-Object -ExpandProperty FullName
$SID = Get-LocalUser -Name $localuser | Select-Object -ExpandProperty SID
$UserType = Get-LocalUser -Name $localuser | Select-Object -ExpandProperty PrincipalSource
$PasswordLastSet = Get-LocalUser -Name $localuser | Select-Object -ExpandProperty PasswordLastSet
$Enabled = Get-LocalUser -Name $localuser | Select-Object -ExpandProperty Enabled
$UserMayChangePassword = Get-LocalUser -Name $localuser | Select-Object -ExpandProperty UserMayChangePassword
$PasswordNeverExpires = (Get-LocalUser -Name $localuser | Select-Object -ExpandProperty PasswordExpires) -eq $null
[Int]$i=0
$groupsOutput = ""
$groups = (Get-LocalGroup | Where-Object { (Get-LocalGroupMember $_).name -eq "$Computer\$Name" }).Name
foreach($group in $groups) {
$i++
if($i -le 1)
{
$groupsOutput = -join ("$groupsOutput", "$group")
}
else
{
$groupsOutput = -join ("$groupsOutput", " / " ,"$group")
}
}
$LastLogOn = Get-LocalUser -Name $localuser | Select-Object -ExpandProperty LastLogOn
$TimeZone = [regex]::Matches([System.TimeZoneInfo]::Local.DisplayName, '(?<=\()(.*)(?=\))').Value
Add-Content -Path $OutPutFile -Value "$Computer;Windows;$IP;$Name;$FullName;$SID;$UserType;$PasswordLastSet;$Enabled;$UserMayChangePassword;$PasswordNeverExpires;;$groupsOutput;$LastLogOn;$TimeZone"
}
}else{
foreach($localuser in $LocalUsers) {
$user = Get-WmiObject -query "SELECT * FROM Win32_UserAccount WHERE LocalAccount = 'True' and Name = ""$localuser"""
$Name = $localuser
$FullName = $user.FullName
$SID = $user.SID
$UserType = "Local"
$PasswordLastSet = $(net user $Name| findstr /B /C:"Password last set")
$PasswordLastSet = $PasswordLastSet.Substring(29)
$Enabled = -not $user.Disabled
$UserMayChangePassword = -not $user.PasswordChangeable
$PasswordNeverExpires = -not $user.PasswordExpires
$groupList = Get-CimInstance -ClassName Win32_UserAccount -Filter "Name='$name'" | Get-CimAssociatedInstance -Association Win32_GroupUser | Select-Object Name
$groups = ""
foreach($group in $groupList.Name){
$groups += $group + ","
}
$groups = $groups.Substring(0,$groups.Length-1)
$LastLogOn = $(net user $Name| findstr /B /C:"Last logon")
$LastLogOn = $LastLogOn.Substring(29)
$TimeZone = [regex]::Matches([System.TimeZoneInfo]::Local.DisplayName, '(?<=\()(.*)(?=\))').Value
$passwordNeverExpires = -not $user.passwordExpires
Add-Content -Path $OutPutFile -Value "$Computer;Windows;$IP;$Name;$FullName;$SID;$UserType;$PasswordLastSet;$Enabled;$UserMayChangePassword;$PasswordNeverExpires;;$groups;$LastLogOn;$TimeZone"
}
}
May 06 2022 02:59 AM
May 08 2022 10:01 PM - edited May 09 2022 12:20 AM
@Harm_Veenstra One thing I also understood that, The user who is executing the script is the local user not domain user. Its trying to collect the details from the target server but in backend some where its connecting to AD Server. And the error I am getting is like below. User and the error type.
Is the server level hardening to block the login or in the script which is trying to do get something from AD server instead of Target servers where the actual script is executing.
May 08 2022 11:32 PM
My expectation is that the NTLM event is coming from how the script is being called, not from the script itself.
Rather than focusing on the script content, focus on how it's being run, i.e. via something like psexec, Invoke-Command, a scheduled task, SCCM utility, etc., etc.
In theory, WMI can also be the source but the calls to Get-WmiObject and Get-CimInstance do not use such triggers (such as alternate credentials and/or impersonation levels) meaning that is irrelevant in this case. That only leaves how it's being launched.
While the script itself is not written very well, there's nothing in it that would trigger the events you're seeing.
Cheers,
Lain
May 08 2022 11:39 PM
May 09 2022 12:38 AM
It sounds like you can stop looking into the script and switch your focus onto engaging with the BMC instead.
You could perform a quick cross-check beforehand by distributing a much simpler one line script (below) via BMC TrueSight, in which case if you deploy it the exact same way as your original script above, I'd wager you'll see the exact same NTLM event reported by your security team.
Write-Host "Hello world!"
If it does indeed trigger the NTLM event then at least you can be sure the configuration issue lies within TrueSight.
The authentication package used can very much be chosen by the launcher (BMC TrueSight in this case) and it appears it's chosen NTLM.
One thought - and this is only a guess - is that within your TrueSight configuration, see if you can specify the "run as" account in RFC822 format - more simply known as e-mail format.
So, for example, if you specified the account within the TrueSight package in NT4 format like:
mydomain\myLaunchAccount
Then try the RFC822 format of:
myLaunchAccount@mydomain.com
It may or may not make a difference but I have seen software use NTLM when the NT4 format is used and Kerberos (which is what your security team probably wants you to use) when RFC822-style is used. And it should be a reasonably quick to test, so I'd give that a go before reaching out to BMC.
Cheers,
Lain
May 09 2022 01:04 AM
May 09 2022 01:47 AM - edited May 09 2022 01:52 AM
I'm not quite understanding what you tested manually. Do you mean you ran the script manually on the server - i.e. as a PS1 file - and it generated an NTLM event?
If so, were you running the PS1 as yourself or the TrueSight action account?
You might also want to look at the following two policies and configure them for auditing (if they're not already configured). I'd be looking to configure them locally on:
You can then runs some commands from the PowerShell console and see the impact in the event log at "Applications and Services Log\Microsoft\Windows\NTLM\Operational".
You can use a domain group policy to do this, but if neither policy is already set, then I'd simply use the local group policy editor during the testing phase (gpedit.msc) as it's easier/quicker to undo once testing is complete.
Read more about NTLM auditing policies here: NTLM Blocking and You: Application Analysis and Auditing Methodologies in Windows 7 - Microsoft Tech....
As an aside, the Windows Firewall won't feature in this in any way, shape or form - if that's the firewall you were referring to. It has zero per cent to do with authentication packages unless you're using Connection Security Rules, which I'd safely wager you're not using (and they're IPsec-based anyway, putting NTLM a long way out of reach.)
I'm also not familiar with any policy that forcibly degrades Kerberos to NTLM, so I wouldn't suspect hardening. Misconfiguration of something, maybe, but not hardening.
Cheers,
Lain
May 09 2022 02:07 AM - edited May 09 2022 02:08 AM
Reflecting on Ned's article (linked above) - he's such a good writer! - make sure BMC TrueSight is connecting to these servers by name and not IP address.
Connecting via IP address precludes the use of Kerberos, meaning NTLM is the only option.
It's so easy to forget basic requirements like this one.
Cheers,
Lain
May 09 2022 02:17 AM
May 09 2022 02:19 AM
May 09 2022 05:21 AM - edited May 09 2022 05:26 AM
I just ran a quick test of your first WMI statement and checked the NTLM/Operational log, and it does actually generate an NTLM audit event.
This is the relevant line:
Get-WmiObject -Class Win32_UserAccount -Filter "LocalAccount=True"
Edited: Just to add the second Win32_UserAccount statement also throws an audit result, so it seems to be something specific to querying the Win32_UserAccount instances, despite the filter being for local accounts.
Get-WmiObject -query "SELECT * FROM Win32_UserAccount WHERE LocalAccount = 'True' and Name = ""$localuser"""
The Win32_Group query does not trip the NTLM audit.
Cheers,
Lain
May 09 2022 07:46 AM - edited May 09 2022 07:47 AM
Here's a really, really quick re-write that doesn't trip the NTLM audit.
It uses the positively ancient ADSI WinNT provider, which takes me back to my late NT4/early Windows 2000 days, so a real blast from the past.
One "advantage" though is you don't need to have two code paths as you currently do to cater to different PowerShell versions as this will work on 5.1 and earlier just fine.
Personally, I'd write the script quite differently but I wanted to keep as much of your old one as possible while resolving the WMI oddity.
Give it a go and tweak what you need to, to get it to do what you need.
$Computer = $env:ComputerName
$OutputDir = "c:\temp\"
$Name = ($OutputDir + $Computer + "_LocalUser.csv")
out-file -filepath $Name
$OutputFile = $Name
Add-Content -Path $OutPutFile -Value "ComputerName;OS;IP;UserID;FullName;SID;UserType;PasswordLastSet;Enabled;UserMayChangePassword;PasswordNeverExpires;InteractiveLogon;AccessDetails;LastLogOn;TimeZone"
$LocalUsers = ([adsi]"WinNT://$($env:COMPUTERNAME),Computer").Children | Where-Object { $_.SchemaClassName -eq "User" };
$localgroups = ([adsi]"WinNT://$($env:COMPUTERNAME),Computer").Children | Where-Object { $_.SchemaClassName -eq "Group" };
$IP = (Get-NetIPAddress -PrefixOrigin Dhcp, Manual | Select-Object -Property IPAddress).IPAddress -join ", "
foreach($localuser in $LocalUsers)
{
$NameParts = $localuser.Path.Split("/");
$Name = $NameParts[-1];
$FullName = "$($NameParts[-2])\$($NameParts[-1])";
$SID = [System.Security.Principal.SecurityIdentifier]::new($localuser.objectSid[0], 0).Value;
$UserType = "Local";
$PasswordLastSet = [datetime]::Now.AddSeconds($localuser.PasswordAge.Value * -1);
$Enabled = ($localuser.UserFlags.Value -band 0x2) -eq 0;
$UserMayChangePassword = ($localuser.UserFlags.Value -band 0x40) -eq 0;
$PasswordNeverExpires = ($localuser.UserFlags.Value -band 0x10000) -ne 0;
$groupsOutput = ($localgroups | Where-Object { $_.IsMember($localuser.Path) }).Name -join " / ";
$LastLogOn = if ($localuser.Properties.Contains("LastLogin")) { $localuser.LastLogin.Value.ToString("u"); } else { "never"; };
$TimeZone = [regex]::Matches([System.TimeZoneInfo]::Local.DisplayName, '(?<=\()(.*)(?=\))').Value
Add-Content -Path $OutPutFile -Value "$Computer;Windows;$IP;$Name;$FullName;$SID;$UserType;$PasswordLastSet;$Enabled;$UserMayChangePassword;$PasswordNeverExpires;;$groupsOutput;$LastLogOn;$TimeZone"
}
Cheers,
Lain