Auditing Windows Permissions with Get-ACL

One of the new Microsoft PowerShell cmdlets that auditors should appreciate is the GET-ACL cmdlet. Now, through native PowerShell commands, an auditor can retrieve a list of all the permissions associated with a given Windows object. The output from this command can be used to create a permissions baseline if someone is trying to alert on permissions changes. Or this command could be used to generate a list of all the permissions associated with a given objects. Through a simple syntax, an auditor can dump a list of all the permissions associated with a given Microsoft Windows object.

The simple syntax to run the command against a file system object would be the following:

Get-Acl c:\tools\ | Format-List

However you can also run this command against a number of different Microsoft Windows objects, including registry keys, Active Directory objects, printers, or anything else with an access control list associated with it. For example, to perform a similar command against a registry hive, the following command would work:

Get-Acl HKCU:\Software\Microsoft\Windows | Format-list

In addition, when using the –AUDIT parameter, an auditor can dump a list of the System Access Control Lists (SACLs) that are associated with an object in order to determine the logging settings configured on an object. The following shows an example of how to perform the command:

get-Acl -audit c:\tools\ | Format-list

Finally Daniel Carrarini has posted an interesting script for dumping access that shows some of the full features of the command. Here is a link to his blog post as well:

http://carrarini.blogspot.com/2011/08/powershell-script-for-dumping-access.html

Script for Windows Firewall Baseline

Another baseline an auditor or system administrator might want to consider when assessing their systems is a baseline for the general configuration of the Microsoft Windows Firewall. Many organizations are starting to utilize the built in Microsoft Windows Firewall more and more when protecting even their internal systems. The use of a host based firewall should definitely be on the list of things to consider when evaluating the security of a system.

If the system that you are auditing is using a third party firewall product, then you will need to contact that vendor to see how best to automate collecting data about the firewall’s configuration. However if you are using the built in Windows Firewall, then the following script will help by gathering a baseline of the general configuration settings of the firewall:

$Global = (netsh advfirewall show global)
$Profiles = (netsh advfirewall show allprofiles)

$Global | Out-file firewall_config.txt
$Profiles | Out-file -append firewall_config.txt

It should be noted that this script will only work on systems running PowerShell – but you have probably already noticed that theme in our posts. But also please remember that this will only work on systems running the Windows Advanced Firewall that was released with Windows Vista and later systems. This will not work on the earlier, original firewall built into Windows XP.

Parsing Active Directory Groups

In a previous post we shared a PowerShell script that would allow an auditor to parse a list of groups and group members on a Microsoft Windows system as a part of a security assessment or baselining process. The question has come up though – what if someone wants to follow the same process but parse a list of Active Directory groups and their members instead?

It turns out that it is much easier to perform the task against Active Directory than it is to do it against a local Microsoft Windows local Security Accounts Manager (SAM) database. It seems that the native capabilities of the Active Directory PowerShell cmdlets is going to make it easier for us to accomplish this task.

The output requirement for this script will be the same as for the previous. The output should be in a CSV format that could be easily parsed by a spreadsheet program like Microsoft Excel. Also, like the previous script, empty groups should still be listed, but just without any group members listed along with them.

The code we used to parse a list of AD groups and their members is:

Get-ADGroup -Filter * | ForEach-Object { 
    $GroupName = $_.Name 
    $Members = Get-ADGroupMember $_.samaccountname -Recursive | foreach{$_.Name} 
        If ($Members.count -ge 1){
            $Out = $GroupName + "," + [String]::Join(",", $Members)
            $out | Out-File -append ad_group_members.txt
        }
        Else{
            $Out = $GroupName
            $out | Out-File -append ad_group_members.txt  
        }
    } 

Ideally an auditor would combine this script with our previous example and using PowerShell remoting run one script that would parse local and Active Directory groups at the same time and output the data as an easily readable file. But between the two examples, hopefully it will give you enough inspiration to make this usable for you in your audit efforts.

Parsing Local Windows Groups

One step that has become a staple part of any audit of Microsoft Windows systems is a listing of all the local groups on the system. Listing all the groups on a system with all the members of that group can help establish a baseline for the security configuration of a system. Certainly groups like the local Administrators group is a concern during a security audit. Ideally though auditors would have the ability to look at the members of each group on a system and validate that the list of members is appropriate for that system.

As with many of the scripts we have recommended, we decided to write a script using PowerShell to pull the information from a local system. We also wanted to make sure that when we pulled the information from a system that we could parse it easily once we were done. Therefore we wrote the script to allow us to pull all the local computer groups from a system, with the members of the group, and then save it as a CSV file for easier parsing with Excel.

Here is the code we used for the script:

$GroupList = Get-WmiObject Win32_Group | ForEach {$_.name}

$ComputerName = "."

ForEach ($GL in $GroupList)

{

    $Computer = [ADSI]("WinNT://" + $ComputerName + ",computer")

    $Group = $Computer.psbase.children.find($GL)

    $Members= $Group.psbase.invoke("Members") | %{$_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null)}

        If ($Members.count -ge 1){
            $Out = $GL + "," + [String]::Join(",", $Members)
            $out | Out-File -append local_group_members.csv
        }
        Else{
            $Out = $GL
            $out | Out-File -append local_group_members.csv
        }

}

We ran into a couple issues when writing the script. One was the formatting of the output to a CSV file. Normally we would use an EXPORT-CSV cmdlet to do that, but in this case since we had multiple data sources we had to do some custom formatting. Also since some of the groups were empty, we had to add the IF clause to make sure that even blank groups were reported in our output.

Once the concept of the script starts to make sense to you, it should be an easy next step to consider adding PowerShell remoting capabilities or a computer name list to the script to parse multiple systems at once. You might also consider saving the output from the script in a format (such as HTML) that is easier to read and include in your audit reports.

We hope the script is useful as you audit Microsoft Windows servers or establish security baselines for those systems.