Check Windows File Integrity with sfc and powershell

Objective

Use file integrity checking tools to ensure that critical system files (including sensitive system and application executables, libraries, and configurations) have not been altered.
Critical Security Control #3: Secure Configurations for Hardware and Software – System 3.5

SFC and Powershell

Windows contains a build-in utility called sfc to verify and fix Windows File Integrity issues.
Lets have a quick look what this utility and some powershell can do for us.
The flags differ on older versions of Windows so check it’s options before running the commands below.

Windows 2008, 2012R2, 7, 8 and 10:

PS C:\WINDOWS\system32> sfc /?

Microsoft (R) Windows (R) Resource Checker Version 6.0
Copyright (C) Microsoft Corporation. All rights reserved.

Scans the integrity of all protected system files and replaces incorrect versions with
correct Microsoft versions.

SFC [/SCANNOW] [/VERIFYONLY] [/SCANFILE=] [/VERIFYFILE=]
    [/OFFWINDIR= /OFFBOOTDIR=]

/SCANNOW        Scans integrity of all protected system files and repairs files with
                problems when possible.
/VERIFYONLY     Scans integrity of all protected system files. No repair operation is
                performed.
/SCANFILE       Scans integrity of the referenced file, repairs file if problems are
                identified. Specify full path 
/VERIFYFILE     Verifies the integrity of the file with full path .  No repair
                operation is performed.
/OFFBOOTDIR     For offline repair specify the location of the offline boot directory
/OFFWINDIR      For offline repair specify the location of the offline windows directory

e.g.

        sfc /SCANNOW
        sfc /VERIFYFILE=c:\windows\system32\kernel32.dll
        sfc /SCANFILE=d:\windows\system32\kernel32.dll /OFFBOOTDIR=d:\ /OFFWINDIR=d:\windows
        sfc /VERIFYONLY

Windows 2003

C:\Documents and Settings\Administrator>sfc /?

Microsoft (R) Windows (R) File Checker Version 5.2
Copyright (c) Microsoft Corporation. All rights reserved.

Scans all protected system files and replaces incorrect versions with correct Mi
crosoft versions.

SFC [/SCANNOW] [/SCANONCE] [/SCANBOOT] [/REVERT] [/PURGECACHE] [/CACHESIZE=x]


/SCANNOW        Scans all protected system files immediately.
/SCANONCE       Scans all protected system files once at the next boot.
/SCANBOOT       Scans all protected system files at every boot.
/REVERT         Return scan to default setting.
/PURGECACHE     Purges the file cache.
/CACHESIZE=x    Sets the file cache size.

Verify File Integrity

Verification of all Windows protected files can be performed with the /VERIFYONLY switch.

PS C:\Users\Administrator> sfc /verifyonly

Beginning system scan.  This process will take some time.

Beginning verification phase of system scan.
Verification 100% complete.

Windows Resource Protection did not find any integrity violations.

The last line of the output shows the high level results.
The detailed results are logged in %windir%\Logs\CBS\CBS.log

Analyzing the logfile

To test if the %windir%\Logs\CBS\CBS.log contains sfc log entries:

C:\WINDOWS\system32> if (get-content $env:systemroot\Logs\CBS\CBS.log | 
Where-Object {$_ -match "\[SR\]"} | 
Select -first 1) {"TRUE"} else {"FALSE"}

Run the following command to view only the File Integrity Scan lines :

C:\Users\Administrator> findstr /c:"[SR]" C:\Windows\Logs\CBS\CBS.log
2016-01-05 07:34:47, Info                  CSI    0000000a [SR] Verifying 100 (0x0000000000000064) components
2016-01-05 07:34:47, Info                  CSI    0000000b [SR] Beginning Verify and Repair transaction
2016-01-05 07:34:49, Info                  CSI    0000000c [SR] Verify complete
2016-01-05 07:34:49, Info                  CSI    0000000d [SR] Verifying 100 (0x0000000000000064) components
2016-01-05 07:34:49, Info                  CSI    0000000e [SR] Beginning Verify and Repair transaction
2016-01-05 07:34:52, Info                  CSI    0000000f [SR] Verify complete
<cut...>

To filter out the known good lines and get only the interesting lines:

C:\Windows\system32> get-content c:\windows\logs\CBS\CBS.log | 
select-string -simplematch "[SR]" | 
select-string -notmatch "Verify complete","Verifying", "Beginning Verify and Repair"
 
2016-01-05 06:58:37, Info                  CSI    000002bc [SR] Repairing corrupted file [ml:520{260},l:56{28}]"\??\C:\Windows\Help\mui\0409"\[l:22{11}]"diskmgt.CHM" from store

To get the last date the sfc utility has run:

C:\Windows\system32> get-content c:\windows\Logs\CBS\CBS.log | where {$_.Contains("[SR]") } | Select-object -Property @{Name="LastCheckDate"; Expression = {$_.substring(0,10)}} -last 1
 
LastCheckDate
-------------
2016-01-05

Run the following command to get the number of days ago sfc has run

C:\Windows\system32> $sr = get-content c:\windows\Logs\CBS\CBS.log | 
where {$_.Contains("[SR]")} | 
Select-object -Property @{Name="LastCheckDate"; Expression = {$_.substring(0,10)}} -last 1 ; New-TimeSpan -start $sr.LastCheckDate -end (get-date) | 
select days
 
Days
----
0

sfc will append its output to the CBS.log so to view only the results of the last sfc scan we combine the last check date with the previous command:

C:\Windows\system32> $sr = get-content c:\windows\Logs\CBS\CBS.log | 
where {$_.Contains("[SR]")} | 
Select-object -Property @{Name="LastCheckDate"; Expression = {$_.substring(0,10)}} -last 1
 
PS C:\Windows\system32> get-content c:\windows\Logs\CBS\CBS.log | 
where-object {$_.Contains("[SR]") -and $_.Contains($sr.lastcheckdate)} | 
Select-String -notmatch "Verify complete","Verifying","Beginning Verify and Repair"

Nessus Auditfile

Now that we have the commands we put those in a Nessus auditfile:

<check_type: "Windows" version:"2">
<group_policy: "MS Windows Server">
 
<if>
<condition type: "AND">
 
<custom_item>
 type: AUDIT_POWERSHELL
 description: "Check if %SystemRoot%\Logs\CBS\CBS.log contains [SR] log entries"
 value_type: POLICY_TEXT
 value_data: 'TRUE'
 powershell_args: "if (get-content c:\windows\Logs\CBS\CBS.log | where {$_ -match '\[SR\]'} | Select-object -last 1) {'TRUE'} else {'FALSE'}"
 check_type: CHECK_EQUAL
</custom_item>
 
</condition>
 
<then>
<custom_item>
 type: AUDIT_POWERSHELL
 description: "System file checking should be performed within the last 30 days"
 value_type: POLICY_TEXT
 value_data: '[0-30]'
 powershell_args: "$sr = get-content c:\windows\Logs\CBS\CBS.log | where {$_ -match '\[SR\]'} | Select-object -Property @{Name='LastCheckDate'; Expression = {$_.substring(0,10)}} -last 1 ; New-TimeSpan -start $sr.LastCheckDate -end (get-date) | select days | Format-Table -HideTableHeaders"
 check_type: CHECK_REGEX
</custom_item>
 
<custom_item>
 type: AUDIT_POWERSHELL
 description: "List File Integrity errors from last scan in %SystemRoot%\Logs\CBS\CBS.log"
 value_type: POLICY_TEXT
 value_data: ''
 powershell_args: "$sr = get-content c:\windows\Logs\CBS\CBS.log | where {$_ -match '\[SR\]'} | Select-object -Property @{Name='LastCheckDate'; Expression = {$_.substring(0,10)}} -last 1 ; get-content c:\windows\Logs\CBS\CBS.log | where-object {$_.Contains('\[SR\]') -and $_.Contains($sr.lastcheckdate)} | select-string -notmatch 'Verify complete','Verifying', 'Beginning Verify and Repair'"
 check_type: CHECK_EQUAL
 powershell_option: CAN_BE_NULL
</custom_item>
 
</then>
 
<else>
<report type: "FAILED">
 description: "%SystemRoot%\Logs\CBS\CBS.log does not exists or does not contain SFC log entries "
</report>
 
</else>
 
</if>
 
</group_policy>
</check_type>

Running Nessus script with the new auditfile

 
bash _new_check.sh 


Windows Compliance Checks, version 1.164

Which file contains your security policy : SMB login : stty: standard input: Inappropriate ioctl for device
SMB password : stty: standard input: Inappropriate ioctl for device

SMB domain (optional) : 

"System file checking should be performed within the last 30 days": [PASSED]

Remote value: '1'
Policy value: '[0-30]'

"List File Integrity errors from last scan in %SystemRoot%\Logs\CBS\CBS.log": [PASSED]

Remote value: ''
Policy value: ''

Results from Nessus Scan

sfc1

sfc2