Stop Using SMB1

The NHS (National Health Service) in the U.K. has suffered a major ransomware attack affecting a large number of hospitals in the U.K. The attacker used this(patched) exploit.

This got me wondering about SMB1, I checked my homelab Windows Server 2012R2 file server and was surprised to see SMB1 enabled. It turns out SMB1 is still enabled by default…. There are cases where you have some legacy thing that only supports SMB1 but that’s the exception. So, How do you disable SMB1 in Windows Server 2012+?

  1. Check your SMB Server Configuration:
     &>Get-SmbServerConfiguration | Select EnableSMB1Protocol
    
     EnableSMB1Protocol
     ------------------
             	False
    
  2. Disable:
      Set-SmbServerConfiguration -EnableSMB1Protocol $false -Confirm:$false
    

Script:

This will disable SMB1 on the servers fed to it.

param(
[parameter(Mandatory=$true)]
[String[]]$Computers
)

foreach($computer in $Computers){
    $session = New-PSSession -ComputerName $computer
    Invoke-Command -Session $session -ScriptBlock{
        if((Get-SmbServerConfiguration).EnableSMB1Protocol){
            Set-SmbServerConfiguration -EnableSMB1Protocol $false -Confirm:$false
            Write-Host "SMB1 disabled on $env:computername"
        }
    }
}

Run it like this:

./script.ps1 -Computers computer1,computer2,etc.

Bam! that’s it. It would probably be better to remove it entirely though.

We can do that easily!

  1. Check to see if the FS-SMB1 feature is installed:

    &>Get-WindowsFeature -Name FS-SMB1
    
    Display Name                                            Name                       Install State
    ------------                                            ----                       -------------
    [X] SMB 1.0/CIFS File Sharing Support                   FS-SMB1                        Installed
    
    
  2. Remove it:

     &>Remove-WindowsFeature -Name FS-SMB1
    

    Note: The server will require a restart to fully complete the operation.

Script:

param(
[parameter(Mandatory=$true)]
[String[]]$Computers
)

foreach($computer in $Computers){
    $session = New-PSSession -ComputerName $computer
    Invoke-Command -Session $session -ScriptBlock{
        if((Get-WindowsFeature -Name "FS-SMB1").InstallState -eq "Installed"){
            Remove-WindowsFeature -Name "FS-SMB1" | Out-Null
            Write-Host "FS-SMB1  removed on $env:computername"
        }
    }
}

Run it like this:

./script.ps1 -Computers computer1,computer2,etc.

If you are using ansible you might want to make sure the role is removed when you run your initial playbook against the server. You can do so like this:

- name: Remove FS-SMB1 feature
  win_feature: name: "FS-SMB1" state: absent restart: yes

Thats it! SMB1 should be off or removed unless you have very specific needs that require it for some reason.

Five Minute AWK Mastery

I see alot of people thinking AWK is a hard skill to pickup. This is not the case, to effectively use AWK you only need to know a few things.

For the below examples I will be using df -h as the data source

The output:

 pbove@PHIL:/mnt/c/Users/pbove$ df -h
 Filesystem      Size  Used Avail Use% Mounted on
 rootfs          112G  106G  5.2G  96% /
 tmpfs           112G  106G  5.2G  96% /run
 none            112G  106G  5.2G  96% /run/lock
 none            112G  106G  5.2G  96% /run/shm
 none            112G  106G  5.2G  96% /run/user
  1. Basic AWK Syntax:

    The syntax of your basic AWK one liner is as follows:

    $>program | awk '{print $1}'

    This will take the output from “program” and pass it to the AWK interpreter as the input. The '{}' block surrounded by single quotes is an AWK “operation block” that will be executed on every line that is passed through the |, print $1 uses the “print” function in AWK to print the built in variable $1.

    Running this on our df -h output would get us this:

     pbove@PHIL:/mnt/c/Users/pbove$ df -h | awk '{print $1}'
     Filesystem
     rotfs
     tmpfs
     none
     none
     none
    

    You can also use operators to determine whether the block should run:

     pbove@PHIL:/mnt/c/Users/pbove$ df -h | awk '$1 == "Filesystem" {print $1}'
     Filesystem
    
  2. AWK Built-in Variables:

    As you may have guessed from the previous outputs $1 in AWK refers to the first field in the current line, there is a $d for every field in a line. An AWK field is by default delimited by one tab or space.

    $0 is the entire line.

    NR is the amount of records read.

     df -h | awk 'NR==2 {print $5}'
     96%
    

    FNR is the amount of records read in the current file/input.

     df -h | awk 'NR==2 {print $5}'
     96%
    

    The difference between the NR and FNR variable do not matter when you are taking one input “file” from the pipe, however you need to be careful if you pull in multiple files because NR will keep counting while FNR resets per file.

There you go, this should arm with with enough AWK knowledge to be useful. If you are interested in some more in depth reading I recommend “The AWK Programming Language” written by the creators of AWK if you can snag it for a reasonable price.