SMBv1 - Logging Active Connections

With the more recent vulnerabilities identified with SMBv1 and the urgent recommendation by Microsoft to disable the 30 year old protocol. There have been a slew are articles out there on how to disable the SMBv1 protocol. There is also some good information out there on auditing however I did not have much luck with the built in functionality to audit as I needed this information from all of the infrastructure and I needed it to be centralized.

After looking at the tools that were given to us out of the box by Microsoft I came up with something that could grab the data and store it somewhere that could be reviewed centrally for all devices using SMBv1 to make connections. This data would include Server Name, Share Name, User Name, Credentials, and the Dialect (Version of SMB).

The CMDLet Get-SmbConnection will gather the SMB connection information for the device it is run on.

While Get-SmbConnection is great to pull this information. However there are methods we can use to compliment it.

  1. It only pulls active connection information.
  2. There is no historical information on these connections being stored any where.
  3. There is no straight forward method to store the data from multiple devices where it can be reviewed centrally.

Requirements:

  • Identify users connecting to shares using a version of SMB less than 2
  • Record these connections, store them for historical data, and be able to review then centrally
  • Monitor for these connections on a frequency

That being said I was able to meet these requirements with the following:

  • PowerShell
  • SCCM

Identifying User Connections SMB Less than Version 2:

PowerShell:

Using PowerShell I was able to automate pulling the connections that were using a SMB version less than 2.

The Logic:

Every time the script runs and connection Dialect less than version 2 if found record it.
$SMBConnection = Get-SMBConnection | Where Dialect -LT 2

Storing the Connection Data:

There are some obvious place that we could store the recorded connection data. One choice could be the registry. However my first choice is in WMI and I will get to why later in this article.

To accomplish we are going to use create a custom WMI class and populate it with the connection information recorded when there is a match from the logic. This part of the code was reused from other articles (Links in Final Script) and adjusted to suit my requirements. Creating the custom WMI is wrapped in a function that is called a little further down the script.

The SMBv1Connections class will be placed in root\cimv2
Resulting in the path being: root\cimv2\SMBv1Connections

Creating the WMI Class - Function:

Creating the class will be handled by the function below.
First the New Class Object is created, Then properties and when a match is returned from the Get-SMBConnection | Where Dialect -LT 2 the connection data from each match is stored in the properties.

# Function to Create WMI Class            
Function CreateWMIClass{            
            
# Logic - Detect for SMB Connections less than version 2            
$SMBConnection = Get-SMBConnection | Where Dialect -LT 2            
            
# Create Management Class            
$newClass = New-Object System.Management.ManagementClass `
    ("root\cimv2", [String]::Empty, $null);             
$newClass["__CLASS"] = "SMBv1Connections";             
            
$newClass.Qualifiers.Add("Static", $true)            
            
# Add Properties            
## ServerName            
$newClass.Properties.Add("ServerName",[System.Management.CimType]::String, $false)            
$newClass.Properties["ServerName"].Qualifiers.Add("Key", $true)            
## ShareName            
$newClass.Properties.Add("ShareName",[System.Management.CimType]::String, $false)            
$newClass.Properties["ShareName"].Qualifiers.Add("Key", $true)            
## UserName            
$newClass.Properties.Add("UserName",[System.Management.CimType]::String, $false)            
$newClass.Properties["UserName"].Qualifiers.Add("Key", $true)            
## Credential            
$newClass.Properties.Add("Credential",[System.Management.CimType]::String, $false)            
$newClass.Properties["Credential"].Qualifiers.Add("Key", $true)            
## Dialect            
$newClass.Properties.Add("Dialect",[System.Management.CimType]::String, $false)            
$newClass.Properties["Dialect"].Qualifiers.Add("Key", $true)            
## NumOpens            
$newClass.Properties.Add("NumOpens",[System.Management.CimType]::String, $false)            
$newClass.Properties["NumOpens"].Qualifiers.Add("Key", $true)            
            
$newClass.Put()            
            
# Store the data in WMI            
    $SMBConnection | % { $i=0 } {            
        [void](Set-WmiInstance -Path \\.\root\cimv2:SMBv1Connections `
                               -Arguments @{ServerName=$_.ServerName;ShareName=$_.ShareName;            
                                            UserName=$_.UserName;Credential=$_.Credential;            
                                            Dialect=$_.Dialect;NumOpens=$_.NumOpens} -Verbose)            
        $i++            
    }            
            
} # CreateWMIClass

Calling the CreateWMIClass Function:

Now we do not want to create a WMI Class every time this script runs. So we must check to see if the class already exists.

If there has never been a match against the logic that is being used then the script will never create the Custom WMI class.

# Check for SMB Connections less than version 2 and Call CreateWMIClass Function if there is a match            
$SMBConnection = Get-SMBConnection | Where Dialect -LT 2            
If($SMBConnection){            
    # Check whether we already created our custom WMI class on this PC, if not, create it            
    [void](gwmi SMBv1Connections -ErrorAction SilentlyContinue -ErrorVariable wmiclasserror)            
    if($wmiclasserror) {            
        try {CreateWMIClass            
        }            
                    
        catch {            
            "Exit 1 - Could not create WMI class"            
            
        }            
    }            
                
    $Compliance = 'NonCompliant'            
}            
            
    Else{            
    $Compliance = 'Compliant'            
    }

Simple Logging:

At the top of the script I have placed a simple OutFile path and Get-Date to be used at the end.

# Output Information to be used later            
$OutFile = 'C:\Windows\temp\BL_SMBv1_UsageCheck.log'            
$Date = Get-Date |Out-String

Output:
# Output Findings and Compliance
$Output = @"

$Date
 
$Compliance`n


`n`r$SMBv1Connections
"@            
            
$Output| Out-file $OutFile            
            
$Compliance

The log is stored in a path specified at the beginning of the script **"C:\Windows\temp\BL_SMBv1_UsageCheck.log"

Gathering Data (Locally):

The gathering of data can be handled by creating a SCCM Baseline. A baseline will allow us to evaluate compliance for our connections of SMB less than version on a frequency. This is extremely helpful because the connection information can only be pulled if there is a current connection. Since connections can frequently go up or down we need to continuously evaluate against our criteria for them.

Configuration Item (General):

CI Name: SMB v1 - Usage Check - CI
CI Description: Checks for SMB connections less than 2.0

Configuration Item (Supported Platforms):
NOTE: I have only tested this on Windows 10. It should work with Windows 8.1.

Configuration Item (Settings General):
CI Settings Name: SMB v1 - Usage Check - PS
CI Setting Description: PS Script to Log SMB connections in WMI less than version 2

Configuration Item (Discovery Script):
Paste contents of Full Script into script window.
The script can be found here.

Configuration Item (Settings Rule):
CI Setting Rule: SMB v1 - Usage Check - Compliance
CI Setting Rule Description: Compliance = No SMB Connections or SMB Connections of Version 2 or Greater

Baseline (General):
BL Name: SMB v1 - Usage Check - BL
BL Description: Checks for SMB connections less than 2.0

Baseline (Evaluation Conditions):
Add Configuration Item: SMB v1 - Usage Check - CI

Baseline (Deployment Setting):
For better results the deployment settings should be something reasonably frequent.

NOTE: This solution is only for discovery. There are many articles out there on how to disable I wanted to go over how to pull the data for review so that an informed decision can be made. Not all companies are in a position to just turn off SMBv1.

Gather Data (Centrally):
If the SCCM Baseline gets a match for Non-Compliance (SMB connection less than version 2) then it stores the connection information in WMI (root\cimv2\SMBv1Connections). This information can be pulled into SCCM using Hardware Inventory.

Custom Hardware Inventory:
Now we need to point the SCCM Client Hardware Inventory to our new Custom WMI Class.

NOTE: If there are no matches for Non-Compliant devices yet then you are not ready for this step. Keep an eye on the compliance by using one of the canned reports in SCCM (i.e. Summary compliance by configuration baseline). Or if you are like me and are impatient you can make a copy of the script and populate the properties with static information

Now the class should show up in the list. Make sure all the boxes are checked. After a Machine Policy Retrieval & Evaluation Cycle the clients will know to include the new class in the next Hardware Inventory.

When the Hardware Inventory runs we should be able to see the new class pulled into the inventory

Review Data (Centrally):

SQL Query:

Select
SYS.Name0 [Device],
SMB.ServerName00 [Server Name],
SMB.ShareName00 [Share Name],
SMB.Dialect00 [Version],
SMB.UserName00 [User Name],
SMB.Credential00 [Credential],
USR.displayName0 [Display Name],
USR.title0 [Title],
USR.division0 [Division],
SMB.TimeKey

from SMBV1CONNECTIONS_DATA SMB

Left Join v_R_System SYS on SYS.ResourceID = SMB.MachineID
Left Join v_R_User USR on USR.Unique_User_Name0 = SMB.UserName00
Where SMB.Dialect00 < '2' 

Order By
TimeKey,
SMB.ServerName00

SQL Query Output:

Summary:

Not every one needs to go this deep into pulling the information however not all companies can just turn off this protocol. Companies with older servers (i.e. Server 2003) cannot use a higher version of SMB and turning off version 1 would break connections to their shares. There are methods out there to audit servers however every server would have to be audited for every SMB connection. This method seemed to get better results for me. I hope that you found this informative.

THE SOLUTION IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.