Monitoring a file hash using SCOM


 

I had an interesting customer request recently – to monitor for a specific system file, and make SURE it is not a modified/threat file.

 

You can use this as a simple example of a two-state timed script monitor (using vbscript) which demonstrates script arguments, logging, alerting, propertybag outputs, etc.

 

In this case – there is a file located at %windir%\system32\sethc.exe

This is the “Sticky Keys” UI that pops up when you press shift key 5 times.  There are several articles out there on how to create a “back door” to change this file out with cmd.exe, and open a command prompt without logging into a system, if you have access to the console.

In this case – the customer wanted to monitor for any changes to this file. 

I started by writing a script using VBScript, so it will work on Server 2003, 2008, 2008R2, 2012, and 2012R2.  The script calls CertUtil.exe, which will generate the hash for any file.  Then the scripts compares this file hash to a list of “known good” hashes.

The script accepts two arguments, the filepath location, and the comma separated list of known good hashes.

 

' ' File Hash monitoring script ' Kevin Holman ' 5/2016 ' Option Explicit dim oArgs, filepath, paramHashes, oAPI, oBag, strCommand, oShell dim strHashCmd, strHashLine, strHashOut, strHash, HashesArray, Hash, strMatch 'Accept arguments for the file path, and known good hashes in comma delimited format Set oArgs=wscript.arguments filepath = oArgs(0) paramHashes = oArgs(1) 'Load MOMScript API and PropertyBag function Set oAPI = CreateObject("MOM.ScriptAPI") Set oBag = oAPI.CreatePropertyBag() 'Log script event that we are starting task Call oAPI.LogScriptEvent("filehashcheck.vbs", 3322, 0, "Starting hashfile script with filepath: " & filepath & " with known good hashes: " & paramHashes) 'build the command to run for CertUtil strCommand = "%windir%\system32\certutil.exe -hashfile " & filepath 'Create the Wscript Shell object and execute the command Set oShell = WScript.CreateObject("WScript.Shell") Set strHashCmd = oShell.Exec(strCommand) 'Parse the output of CertUtil and output only on the line with the hash Do While Not strHashCmd.StdOut.AtEndOfStream strHashLine = strHashCmd.StdOut.ReadLine() If Instr(strHashLine, "SHA") Then 'skip ElseIf Instr(strHashLine, "CertUtil") Then 'skip Else strHashOut = strHashLine End If Loop 'Remove spaces from the hash strHash = Replace(strHashOut, " ", "") 'Split the comma seperated hashlist parameter into an array HashesArray = split(paramHashes,",") 'Loop through the array and see if our file hash matches any known good hash For Each Hash in HashesArray 'wscript.echo Hash If strHash = Hash Then 'wscript.echo "Match found" Call oAPI.LogScriptEvent("filehashcheck.vbs", 3323, 0, "Good match found. The file " & filepath & " was found to have hash " & strHash & " which was found in the supplied known good hashes: " & paramHashes) Call oBag.AddValue("Match","GoodHashFound") Call oBag.AddValue("CurrentFileHash",strHash) Call oBag.AddValue("FilePath",filepath) Call oBag.AddValue("GoodHashList",paramHashes) oAPI.Return(oBag) wscript.quit Else 'wscript.echo "Match not found" strMatch = "missing" End If Next 'If we get to this part of the script a hash was not found. Output a bad propertybag If strMatch = "missing" Then Call oAPI.LogScriptEvent("filehashcheck.vbs", 3324, 2, "This file " & filepath & " does not match any known good hashes. It was found to have hash " & strHash & " which was NOT found in the supplied known good hashes: " & paramHashes) Call oBag.AddValue("Match","HashNotFound") Call oBag.AddValue("CurrentFileHash",strHash) Call oBag.AddValue("FilePath",filepath) Call oBag.AddValue("GoodHashList",paramHashes) oAPI.Return(oBag) End If wscript.quit

 

I then put this script into a two-state monitor targeting Windows Server OperatingSystem, so every monitored server will run it once a day, and check to see if the supplied file is correct, or if a vulnerability might exist.

 

Here is the Monitor example:

 

<UnitMonitor ID="Custom.HashFile.CompareHash.Monitor" Accessibility="Public" Enabled="true" Target="Windows!Microsoft.Windows.Server.OperatingSystem" ParentMonitorID="Health!System.Health.SecurityState" Remotable="true" Priority="Normal" TypeID="Windows!Microsoft.Windows.TimedScript.TwoStateMonitorType" ConfirmDelivery="false"> <Category>SecurityHealth</Category> <AlertSettings AlertMessage="Custom.HashFile.CompareHash.Monitor.AlertMessage"> <AlertOnState>Warning</AlertOnState> <AutoResolve>true</AutoResolve> <AlertPriority>Normal</AlertPriority> <AlertSeverity>Warning</AlertSeverity> <AlertParameters> <AlertParameter1>$Target/Host/Property[Type="Windows!Microsoft.Windows.Computer"]/NetworkName$</AlertParameter1> <AlertParameter2>$Data/Context/Property[@Name='FilePath']$</AlertParameter2> <AlertParameter3>$Data/Context/Property[@Name='CurrentFileHash']$</AlertParameter3> <AlertParameter4>$Data/Context/Property[@Name='GoodHashList']$</AlertParameter4> </AlertParameters> </AlertSettings> <OperationalStates> <OperationalState ID="GoodHashFound" MonitorTypeStateID="Success" HealthState="Success" /> <OperationalState ID="HashNotFound" MonitorTypeStateID="Error" HealthState="Warning" /> </OperationalStates> <Configuration> <IntervalSeconds>86321</IntervalSeconds> <SyncTime /> <ScriptName>FileHashCheck.vbs</ScriptName> <Arguments>filepath hashlist</Arguments> <ScriptBody><![CDATA[' ' File Hash monitoring script ' Kevin Holman ' 5/2016 ' Option Explicit dim oArgs, filepath, paramHashes, oAPI, oBag, strCommand, oShell dim strHashCmd, strHashLine, strHashOut, strHash, HashesArray, Hash, strMatch 'Accept arguments for the file path, and known good hashes in comma delimited format Set oArgs=wscript.arguments filepath = oArgs(0) paramHashes = oArgs(1) 'Load MOMScript API and PropertyBag function Set oAPI = CreateObject("MOM.ScriptAPI") Set oBag = oAPI.CreatePropertyBag() 'Log script event that we are starting task Call oAPI.LogScriptEvent("filehashcheck.vbs", 3322, 0, "Starting hashfile script with filepath: " & filepath & " with known good hashes: " & paramHashes) 'build the command to run for CertUtil strCommand = "%windir%\system32\certutil.exe -hashfile " & filepath 'Create the Wscript Shell object and execute the command Set oShell = WScript.CreateObject("WScript.Shell") Set strHashCmd = oShell.Exec(strCommand) 'Parse the output of CertUtil and output only on the line with the hash Do While Not strHashCmd.StdOut.AtEndOfStream strHashLine = strHashCmd.StdOut.ReadLine() If Instr(strHashLine, "SHA") Then 'skip ElseIf Instr(strHashLine, "CertUtil") Then 'skip Else strHashOut = strHashLine End If Loop 'Remove spaces from the hash strHash = Replace(strHashOut, " ", "") 'Split the comma seperated hashlist parameter into an array HashesArray = split(paramHashes,",") 'Loop through the array and see if our file hash matches any known good hash For Each Hash in HashesArray 'wscript.echo Hash If strHash = Hash Then 'wscript.echo "Match found" Call oAPI.LogScriptEvent("filehashcheck.vbs", 3323, 0, "Good match found. The file " & filepath & " was found to have hash " & strHash & " which was found in the supplied known good hashes: " & paramHashes) Call oBag.AddValue("Match","GoodHashFound") Call oBag.AddValue("CurrentFileHash",strHash) Call oBag.AddValue("FilePath",filepath) Call oBag.AddValue("GoodHashList",paramHashes) oAPI.Return(oBag) wscript.quit Else 'wscript.echo "Match not found" strMatch = "missing" End If Next 'If we get to this part of the script a hash was not found. Output a bad propertybag If strMatch = "missing" Then Call oAPI.LogScriptEvent("filehashcheck.vbs", 3324, 2, "This file " & filepath & " does not match any known good hashes. It was found to have hash " & strHash & " which was NOT found in the supplied known good hashes: " & paramHashes) Call oBag.AddValue("Match","HashNotFound") Call oBag.AddValue("CurrentFileHash",strHash) Call oBag.AddValue("FilePath",filepath) Call oBag.AddValue("GoodHashList",paramHashes) oAPI.Return(oBag) End If wscript.quit]]></ScriptBody> <TimeoutSeconds>60</TimeoutSeconds> <ErrorExpression> <SimpleExpression> <ValueExpression> <XPathQuery Type="String">Property[@Name='Match']</XPathQuery> </ValueExpression> <Operator>Equal</Operator> <ValueExpression> <Value Type="String">HashNotFound</Value> </ValueExpression> </SimpleExpression> </ErrorExpression> <SuccessExpression> <SimpleExpression> <ValueExpression> <XPathQuery Type="String">Property[@Name='Match']</XPathQuery> </ValueExpression> <Operator>Equal</Operator> <ValueExpression> <Value Type="String">GoodHashFound</Value> </ValueExpression> </SimpleExpression> </SuccessExpression> </Configuration> </UnitMonitor>

 

Lastly – I create an override for the monitor – which allows you to specify the file, and the known good hash list, which appears like this:

 

image

 

When a bad hash is detected – we generate an alert:

 

image

 

And Health Explorer provides good context:

 

image

 

We also do logging for the script when it starts, and the output:

 

Log Name:      Operations Manager
Source:        Health Service Script
Date:          5/26/2016 11:45:55 AM
Event ID:      3324
Task Category: None
Level:         Warning
Keywords:      Classic
User:          N/A
Computer:      WINS2008R2.opsmgr.net
Description:
filehashcheck.vbs : This file C:\Windows\system32\sethc.exe does not match any known good hashes.  It was found to have hash 0f3c4ff28f354aede202d54e9d1c5529a3bf87d8 which was NOT found in the supplied known good hashes: 167891d5ef9a442cce490e7e317bfd24a623ee12,81de6ab557b31b8c34800c3a4150be6740ef445a

 

 

The download of the complete management pack is available at:

https://gallery.technet.microsoft.com/Management-Pack-to-Monitor-153d8cfa


Comments (0)

Skip to main content