├── .gitignore ├── README.md └── sawh.ps1 /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX General 2 | .DS_Store 3 | .AppleDouble 4 | .LSOverride 5 | ._* 6 | 7 | # VIM Swap Files 8 | *.swp 9 | 10 | # Output files 11 | *.csv 12 | *.xml 13 | *.txt 14 | *.rtf 15 | *.xlsx 16 | *.json 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Stand-Alone Windows Hardening (SAWH) 2 | SAWH is a PowerShell script to reduce the attack surface of Windows systems that are not attached to a Windows Active Directory Domain and do not require Windows services to function. Human-Machine Interface (MHI) systems within process environments often only require local access to interact with the system. These systems typically do not need to use services such as Network Browsing, IPv6, SMBv1, NetBIOS, and other Windows services to function properly. Therefore, to reduce the attack surface, many of these services can be disabled. This script provides a configurable way to modify the configuration of a stand-alone system without the need to configure, test, and install Security Templates. [Security Templates and Group Policy Objects (GPO)](https://docs.microsoft.com/en-us/windows/security/threat-protection/security-compliance-toolkit-10), of course, are the BEST way to handle system hardening and SAWH should only be used as a stop-gap until your team can plan and test those technologies. 3 | 4 | # WARNING 5 | 6 | ***Use At Your Own Risk!!!! Do not run on production systems without testing.*** 7 | 8 | Use at your own risk. Cutaway Security is not responsible for how this script affects your system, your network, your services, or your process. Users accept all responsibility for using this script in testing and production environments. 9 | 10 | ***Use At Your Own Risk!!!! Do not run on production systems without testing.*** 11 | 12 | # Capabilities 13 | ## Running Modes 14 | SAWH provides three running modes. 15 | 16 | * 'check' - this performs a check of the system and the configuration of the script's actions. 17 | * 'disable' - this modifies the system to disable services and settings following the action verbs configured in the script. 18 | * 'rollback' - this modifies the system to rollback services and settings following the action verbs configured in the script. The rollback is not performed from a stored configuration for the system. The rollback resets the system to a normal default configuration by enabling the Windows services and network adapter settings. NOTE: except for SMBv1, you can roll this setting back manually. 19 | 20 | ## Configurations 21 | The following configurations can be updated within the script. Your team should review each and determine which should be enabled and which should be disabled. Then, they should test completely before using in production. 22 | 23 | * Interface Mode: modifies the mode of each network interface. Disabling puts the interfaces into 'Public' mode. Rolling back puts the interfaces into 'Private' mode. 24 | * NetBIOS: modifies the settings of each network interface. Disabling disables NetBIOS on each interface. Rolling back enables NetBIOS on each interface. 25 | * Firewall Rules: modifies the Windows Host-based Firewall with a rule named "Block Windows Services - SAWH" that controls TCP ports 135, 137, 139, and 445. Enabling creates the rule (if not present) and enables the rule. Rolling back does not remove the rule, it just disables it. 26 | * Bindings: Network interfaces have multiple configuration settings that can be controlled. The bindings setting controls the function of all. Each setting has its own setting. 27 | * IPv6: This setting controls the use of IPv6 on all interfaces. Disabling will disable IPv6 on all interfaces. Rolling back will enable IPv6 on all interfaces. 28 | * LLTP: This setting controls the use of Link-Layer Topology Discovery Mapper I/O Driver and the Microsoft LLDP Driver on all interfaces. Disabling will disable LLTP on all interfaces. Rolling back will enable LLTP on all interfaces. 29 | * Client: This setting controls the use of Client for Microsoft Networks and File and Printer Sharing for Microsoft Networks on all interfaces. Disabling will disable these services on all interfaces. Rolling back will enable these services on all interfaces. 30 | * NAMP: This setting controls the use of Microsoft Network Adapter Multiplexor Protocol on all interfaces. Disabling will disable NAMP on all interfaces. Rolling back will enable NAMP on all interfaces. 31 | * RDP: This setting controls the use of Terminal Services (RDP) on the system. Disabling will disable the RDP service in registry and also create a firewall rule name "Block RDP - SAWH" that blocks TCP 3389. Rolling back will enable the RDP service in registry and also disable the "Block RDP - SAWH" firewall without removing it. 32 | * This is the only rule that is disabled by default. This is because many organizations will require RDP to access these stand-alone systems. Update with care and testing. 33 | * SMB Configuration: This setting controls the configuration settings for SMB. Disabling will turn off SMB server and Workstation shares and will turn on and require SMB signing and encryption. Rolling back will reset the system to normal SMB default configuration which is to turn on SMB server and Workstation shares and disable SMB signing and encryption. 34 | * SMBv1: This setting controls the use of SMBv1. Disabling will disable SMBv1 on the system. ***Rolling back does nothing.*** You don't need SMBv1 for a stand-alone system. Don't enable it. Fire your vendor or integrator if they force you to enable it. If you really need it, you'll figure out how to enable it. 35 | * Seriously, you don't need SMBv1. Disabling it is extremely important. 36 | * Default Windows Apps: By default Windows 10 installs tens of additional applications not needed for ICS environment on the first user log in, such as BingWeather or XboxGameOverlay. Some of them are described on the [Mircrosoft website](https://docs.microsoft.com/en-us/windows/application-management/apps-in-windows-10). Disabling will uninstall most of the default Windows Apps. Rolling back will install them again (without recreating menu start tiles and windows bar shortcuts). The apps list can be modified per needs in the code. 37 | 38 | ## Considerations 39 | Check is safe. It makes no changes and there is a separate confirmation prompt when changes will be made to the system. 40 | Rolling back puts the system's state into an insecure default state. This script does not maintain the system's original configuration. You should run and store the check action in case you need to reconfigure the system to match the original state. 41 | 42 | # Usage 43 | Tell us about your experience on Twitter by tagging [@cutawaysecurity](https://twitter.com/cutawaysecurity) or, preferably, in this Github repo so others can help. Be sure to include your Windows version. 44 | 45 | ## Deploying via removable media 46 | * Prepare for rollback by backing up or taking a virtual snapshot of the system. 47 | * Download 'sawh.ps1' from this repository. 48 | * Modify any of the configurations verbs to change modifications to your desired configuration. 49 | * Copy the 'sawh.ps1' to a trusted removable media and place the file on the target system in the user's Downloads directory. 50 | * Start a PowerShell Terminal as Administrator. **This is required.** 51 | * Change to your downloads directory. 52 | * Allow scripts to run within the scope of this PowerShell process. 53 | ```powershell 54 | Set-ExecutionPolicy Bypass -Scope Process 55 | ``` 56 | * Execute the script. 57 | ```powershell 58 | .\sawh.ps1 59 | ``` 60 | * Follow the prompts. 61 | * Reboot your system. 62 | * Test your system's functionality. Rollback if necessary. 63 | 64 | ## Deploying via web server 65 | * Prepare for rollback by backing up or taking a virtual snapshot of the system. 66 | * Download 'sawh.ps1' from this repository. 67 | * Modify any of the configurations verbs to change modifications to your desired configuration. 68 | * Start a webserver on your system using Python. 69 | ```python 70 | python3 -m http.server 8181 71 | ``` 72 | * Start a PowerShell Terminal on the target system as Administrator. **This is required.** 73 | * Change to the user's downloads directory. 74 | * Download the SAWH PowerShell script from the Python webserver. 75 | ```powershell 76 | (New-Object Net.WebClient).DownloadString('http://:8181/chaps/chaps.ps1') >.\sawh.ps1 77 | ``` 78 | * Allow scripts to run within the scope of this PowerShell process. 79 | ```powershell 80 | Set-ExecutionPolicy Bypass -Scope Process 81 | ``` 82 | * Execute the script. 83 | ```powershell 84 | .\sawh.ps1 85 | ``` 86 | * Follow the prompts. 87 | * Reboot your system. 88 | * Test your system's functionality. Rollback if necessary. 89 | 90 | # Systems Tested 91 | Have you tested one successfully? Let us know. 92 | 93 | ## Windows Versions 94 | * Windows 10 Enterprise 95 | * 10.0.17763 96 | * Windows 2016 Server 97 | * 10.0.14393 98 | ## HMI / Software Solutions Tested 99 | * [BITS BACnet Site Auditor](https://www.bac-test.com/bacnet-site-auditor-download/) 100 | 101 | # Acknowledgements 102 | The following people and teams have assisted with the testing and / or direction of this project. CutSec sincerely appreciates their input and support. 103 | 104 | * Tom Liston [@tliston](https://twitter.com/tliston) - Bad Wolf Security, LLC 105 | * Ken Lassey, Cornell University 106 | 107 | # TODO 108 | 109 | * Log output to a local file as well as stdout. 110 | * Firewall rule to block UDP-based Windows service ports. 111 | * Disable other unnecessary Windows services. 112 | * Test user accounts and alert when there are no users that are not members of the Administrators group. 113 | * Determine if you can update system configuration to ensure new interfaces start with these settings? 114 | * Disable remote WMI and remote PowerShell. 115 | * Disable non-Administrators from starting CMD.exe and each version of PowerShell [using hash rules or path rules](https://docs.microsoft.com/en-us/windows-server/identity/software-restriction-policies/work-with-software-restriction-policies-rules). 116 | * Add startup/login/shutdown script to check and log configurations. -------------------------------------------------------------------------------- /sawh.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | sawh.ps1 - Stand-Alone Windows Hardening (SAWH) is a PowerShell 3 | script to disable unnecessary Windows services on stand-alone Windows 4 | systems, such as Human Machine Interfaces and stand-alone workstations. 5 | 6 | WARNING: Do not run on production systems without testing. 7 | WARNING: Use at your own risk. Cutaway Security is not responsible for 8 | how this script affects your system, your network, your services, 9 | or your process. Users accept all responsibility for using this 10 | script in testing and production enviornments. 11 | 12 | Don't forget to run 'Set-ExecutionPolicy Bypass -Scope Process' to start. 13 | Be sure to reboot afterwards. 14 | 15 | Acknowledgements: 16 | Tom Liston (@tliston) - Bad Wolf Security, LLC 17 | Ken Lassey, Cornell University 18 | #> 19 | 20 | <# 21 | License: 22 | Copyright (c) 2021, Cutaway Security, Inc. 23 | 24 | sawh.ps1 is free software: you can redistribute it and/or modify 25 | it under the terms of the GNU General Public License as published by 26 | the Free Software Foundation, either version 3 of the License, or 27 | (at your option) any later version. 28 | 29 | sawh.ps1 is distributed in the hope that it will be useful, 30 | but WITHOUT ANY WARRANTY; without even the implied warranty of 31 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 32 | GNU General Public License for more details. 33 | You should have received a copy of the GNU General Public License 34 | along with this program. If not, see . 35 | Point Of Contact: Don C. Weber 36 | #> 37 | 38 | #################### 39 | # Global Parameters 40 | #################### 41 | 42 | # Common Configuration Parameters 43 | $script_name = 'sawh.ps1' 44 | $sysversion = (Get-CimInstance Win32_OperatingSystem).version 45 | $show_warning = $true 46 | $warning = ' 47 | 48 | ################################################################################### 49 | *** Use At Your Own Risk!!!! Do not run on production systems without testing. *** 50 | 51 | WARNING: Do not run on production systems without testing. 52 | WARNING: Use at your own risk. Cutaway Security is not responsible for 53 | how this script affects your system, your network, your services, 54 | or your process. Users accept all responsibility for using this 55 | script in testing and production enviornments. 56 | 57 | *** Use At Your Own Risk!!!! Do not run on production systems without testing. *** 58 | ################################################################################### 59 | 60 | ' 61 | $start_state = $true # Enable / disable writing the system's state before beginning 62 | $completed_state = $true # Enable / disable writing the system's state after changes 63 | 64 | # Global Configuration verbs, modify these to disable modifications 65 | $inf_private_mode = $true # Network interfaces mode - true: 'Private' mode, false: 'Public' mode 66 | $disable_netbios = $true # Disable NetBIOS for all network interfaces 67 | $fw_rules = $true # Apply SAWH firewall rules 68 | $inf_bindings = $true # Change configuration of network interfaces 69 | $inf_bindings_ipv6 = $true # Disable IPv6 on all interfaces 70 | $inf_bindings_lltp = $true # Disable LLTP on all interfaces 71 | $inf_bindings_client = $true # Disable Client for Microsoft Networks and File and Printer Sharing for Microsoft Networks on all interfaces 72 | $inf_bindings_namp = $true # Disable NAMP on all interfaces 73 | $disable_rdp = $false # Disable rdp and block it on firewall. Not used by default because this may be required by some organizations 74 | $harden_smb = $true # Change configuration of SMB to more secure 75 | $disable_smbv1 = $true # Disable SMBv1, rolling back does nothing 76 | $uninstall_windows_apps = $true # Uninstall default Windows apps not needed for ICS 77 | 78 | # Global Action verbs, user input changes these 79 | $disable = $false 80 | $rollback = $false 81 | $check = $false 82 | 83 | 84 | #################### 85 | # Functions 86 | #################### 87 | 88 | #################### 89 | # Administration Functions 90 | #################### 91 | 92 | # Check for Administrator Role 93 | #################### 94 | function Get-AdminState { 95 | if (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")){ 96 | Write-Host "[!] You do not have Administrator rights. This script will not run correctly. Exiting" 97 | Exit 98 | } else { 99 | Write-Host "[*] Script running with Administrator rights." 100 | } 101 | } 102 | #################### 103 | 104 | # Confirm System Modifications 105 | #################### 106 | function Get-UserConfirmation { 107 | if ($show_warning){ Write-Host '*** Use At Your Own Risk!!!! Do not run on production systems without testing. ***' } 108 | $confirmation = Read-Host "Are you Sure You Want To Proceed? [n/y]" 109 | if ($confirmation -ne 'y') { 110 | Write-Host "[*] User selected to exit. Exiting..." 111 | Exit 112 | } else { 113 | Write-Host "[*] User selected to continue. Good luck..." 114 | } 115 | } 116 | #################### 117 | 118 | #################### 119 | # Action Functions 120 | #################### 121 | 122 | # Network interface modes 123 | #################### 124 | function Get-InterfaceModeState { 125 | Write-Host '[*] Checking Network interface modes' 126 | (Get-NetAdapter -Physical | Where-Object {$_.Name -NotLike '*Loopback*'}) | ForEach-Object -Process {Get-NetConnectionProfile -InterfaceAlias $_.Name} 127 | 128 | # Let's give a little whitespace for readability 129 | Write-Host '' 130 | } 131 | 132 | function Set-InterfaceModeState { 133 | 134 | Param( 135 | # Enable means to change the setting to the default / insecure state. 136 | $Enable = $false 137 | ) 138 | 139 | if ($inf_private_mode){ 140 | # Check the physical interfaces, avoid loopbacks, and only act on interfaces that are up 141 | # NOTE: this will not change anything with intefaces with the status 'Disconnected' 142 | if (-NOT $Enable) { 143 | # Put all interfaces into 'Public' mode 144 | Write-Host '[*] Disable: Putting network interfaces into Public mode' 145 | (Get-NetAdapter -Physical | Where-Object {$_.Name -NotLike '*Loopback*' -And $_.Status -eq 'Up'}) | ForEach-Object -Process {Set-NetConnectionProfile -InterfaceAlias $_.Name -NetworkCategory Public} 146 | }else{ 147 | # Put all interfaces into 'Private' mode 148 | Write-Host '[*] Enable / Rollback: Putting network interfaces into Private mode' 149 | (Get-NetAdapter -Physical | Where-Object {$_.Name -NotLike '*Loopback*' -And $_.Status -eq 'Up'}) | ForEach-Object -Process {Set-NetConnectionProfile -InterfaceAlias $_.Name -NetworkCategory Private} 150 | } 151 | }else{ 152 | Write-Host '[!] Modification of network interfaces is disabled.' 153 | } 154 | 155 | # Let's give a little whitespace for readability 156 | Write-Host '' 157 | } 158 | #################### 159 | 160 | # NetBIOS 161 | #################### 162 | function Get-NetBIOSState{ 163 | # Check the physical interfaces, avoid loopbacks, and only act on interfaces that are up 164 | # Get their interface GUID to query the specific registry key 165 | Write-Host "[*] Checking Interface NetBIOS States" 166 | (Get-NetAdapter -Physical | Where-Object {$_.Name -NotLike '*Loopback*' -And $_.Status -eq 'Up'}) | ForEach-Object -Process { 167 | $if_guid = $_.InterfaceGuid; 168 | $if_nb_setting = (Get-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Services\NetBT\Parameters\Interfaces\TCPIP_$if_guid).NetbiosOptions; 169 | $if_name = $_.Name; 170 | if ($if_nb_setting){$nb_config = 'Enabled'}else{$nb_config = 'Disabled'} 171 | Write-Host "[*] Interface $if_name : NetBIOS $nb_config [$if_nb_setting]"; 172 | } 173 | 174 | # Let's give a little whitespace for readability 175 | Write-Host '' 176 | } 177 | 178 | function Set-NetBIOSState(){ 179 | 180 | Param( 181 | # Enable means to change the setting to the default / insecure state. 182 | $Enable = $false 183 | ) 184 | 185 | if ($disable_netbios){ 186 | if (-NOT $Enable) { 187 | # Disable NetBIOS on active interfaces 188 | (Get-NetAdapter -Physical | Where-Object {$_.Name -NotLike '*Loopback*' -And $_.Status -eq 'Up'}) | ForEach-Object -Process { 189 | $if_guid = $_.InterfaceGuid; 190 | $if_nb_setting = (Get-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Services\NetBT\Parameters\Interfaces\TCPIP_$if_guid).NetbiosOptions; 191 | $if_name = $_.Name; 192 | if ($if_nb_setting){ 193 | Set-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Services\NetBT\Parameters\Interfaces\TCPIP_$if_guid -Name NetBIOSoptions -Value 0 194 | Write-Host "[*] Interface $if_name : NetBIOS changed from $if_nb_setting to 0"; 195 | }else{ 196 | Write-Host "[*] Interface $if_name : NetBIOS Already Disabled [$if_nb_setting]"; 197 | } 198 | } 199 | }else{ 200 | # Enable NetBIOS on active interfaces 201 | (Get-NetAdapter -Physical | Where-Object {$_.Name -NotLike '*Loopback*' -And $_.Status -eq 'Up'}) | ForEach-Object -Process { 202 | $if_guid = $_.InterfaceGuid; 203 | $if_nb_setting = (Get-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Services\NetBT\Parameters\Interfaces\TCPIP_$if_guid).NetbiosOptions; 204 | $if_name = $_.Name; 205 | if ($if_nb_setting){ 206 | Write-Host "[*] Interface $if_name : NetBIOS Already Enabled [$if_nb_setting]"; 207 | }else{ 208 | Set-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Services\NetBT\Parameters\Interfaces\TCPIP_$if_guid -Name NetBIOSoptions -Value 2 209 | Write-Host "[*] Interface $if_name : NetBIOS changed from $if_nb_setting to 2"; 210 | } 211 | } 212 | } 213 | }else{ 214 | Write-Host '[!] Modification of network interface NetBIOS settings is disabled.' 215 | } 216 | 217 | # Let's give a little whitespace for readability 218 | Write-Host '' 219 | } 220 | #################### 221 | 222 | # Firewall Rules 223 | #################### 224 | function Get-SAWHFWRulesState(){ 225 | # Check for the 'Block Windows Services - SAWH' 226 | # Get their interface GUID to query the specific registry key 227 | Write-Host '[*] Checking for Block Windows Services - SAWH rule using Windows Firewall' 228 | $check_sw_fw_rule = Get-NetFirewallRule -DisplayName "Block Windows Services - SAWH" -ErrorAction SilentlyContinue 229 | if ($check_sw_fw_rule){ 230 | if (($check_sw_fw_rule).Enable){ 231 | Write-Host '[*] Block Windows Services - SAWH rule enabled.' 232 | }else{ 233 | Write-Host '[*] Block Windows Services - SAWH rule disabled.' 234 | } 235 | Write-Host '[*] Windows Services - SAWH rule configuration' 236 | $check_sw_fw_rule 237 | Write-Host '[*] Windows Services - SAWH rule port settings' 238 | $check_sw_fw_rule | Get-NetFirewallPortFilter 239 | }else{ 240 | Write-Host '[*] Block Windows Services - SAWH rule not configured on this system' 241 | } 242 | 243 | # Let's give a little whitespace for readability 244 | Write-Host '' 245 | } 246 | 247 | function Set-SAWHFWRulesState(){ 248 | 249 | Param( 250 | # Enable means to change the setting to the default / insecure state. 251 | $Enable = $false 252 | ) 253 | 254 | if ($fw_rules){ 255 | $check_sw_fw_rule = Get-NetFirewallRule -DisplayName "Block Windows Services - SAWH" -ErrorAction SilentlyContinue 256 | if (-NOT $Enable) { 257 | # Disable Windows services by adding firewall rule 258 | if ($check_sw_fw_rule){ 259 | if (($check_sw_fw_rule).Enable){ 260 | Write-Host '[*] Block Windows Services - SAWH rule already enabled.' 261 | }else{ 262 | Set-NetFirewallRule -DisplayName "Block Windows Services - SAWH" -Enabled True 263 | Write-Host '[*] Block Windows Services - SAWH rule enabled.' 264 | } 265 | }else{ 266 | # TODO: Add UDP Firewall Rule 267 | New-NetFirewallRule -DisplayName "Block Windows Services - SAWH" -Direction Inbound -LocalPort 135,137,139,445 -Protocol TCP -Action Block 268 | } 269 | }else{ 270 | # Enable Windows services by disabling firewall rule 271 | if ($check_sw_fw_rule){ 272 | if (($check_sw_fw_rule).Enable){ 273 | Set-NetFirewallRule -DisplayName "Block Windows Services - SAWH" -Enabled False 274 | Write-Host '[*] Block Windows Services - SAWH rule disabled.' 275 | }else{ 276 | Write-Host '[*] Block Windows Services - SAWH rule already disabled.' 277 | } 278 | }else{ 279 | Write-Host '[*] Block Windows Services - SAWH rule not configured on this system' 280 | } 281 | } 282 | }else{ 283 | Write-Host '[!] Modification of firewall rules is disabled.' 284 | } 285 | 286 | # Let's give a little whitespace for readability 287 | Write-Host '' 288 | } 289 | #################### 290 | 291 | # Interface inf_bindings 292 | #################### 293 | function Get-NetInfBindingsState(){ 294 | #################### 295 | # Check Network Adapter inf_bindings 296 | #################### 297 | Write-Host '[*] Checking Network Adapter inf_bindings' 298 | (Get-NetAdapter -Physical | Where-Object {$_.Name -NotLike '*Loopback*' -And $_.Status -eq 'Up'}).InterfaceAlias | ForEach-Object -Process {Get-NetAdapterBinding -InterfaceAlias $_} 299 | 300 | # Let's give a little whitespace for readability 301 | Write-Host '' 302 | } 303 | 304 | function Set-NetInfBindingsState(){ 305 | 306 | Param( 307 | # Enable means to change the setting to the default / insecure state. 308 | $Enable = $false 309 | ) 310 | 311 | if ($inf_bindings){ 312 | if (-NOT $Enable) { 313 | # Disable selected inf_bindings 314 | (Get-NetAdapter -Physical | Where-Object {$_.Name -NotLike '*Loopback*' -And $_.Status -eq 'Up'}).InterfaceAlias | ForEach-Object -Process { 315 | if ($inf_bindings_ipv6) { 316 | # Disable IPv6 317 | Disable-NetAdapterBinding -InterfaceAlias $_ -ComponentID ms_tcpip6 318 | } 319 | if ($inf_bindings_lltp) { 320 | # Disable Link-Layer Topology Discovery Mapper I/O Driver 321 | Disable-NetAdapterBinding -InterfaceAlias $_ -ComponentID ms_lltdio 322 | # Disable Microsoft LLDP protocol Driver 323 | Disable-NetAdapterBinding -InterfaceAlias $_ -ComponentID ms_lldp 324 | } 325 | if ($inf_bindings_client) { 326 | # Disable Client for Microsoft Networks 327 | Disable-NetAdapterBinding -InterfaceAlias $_ -ComponentID ms_msclient 328 | # Disable File and Printer Sharing for Microsoft Networks 329 | Disable-NetAdapterBinding -InterfaceAlias $_ -ComponentID ms_server 330 | } 331 | if ($inf_bindings_namp) { 332 | # Disable Microsoft Network Adapter Multiplexor Protocol 333 | Disable-NetAdapterBinding -InterfaceAlias $_ -ComponentID ms_implat 334 | } 335 | } 336 | }else{ 337 | # Enable selected inf_bindings 338 | (Get-NetAdapter -Physical | Where-Object {$_.Name -NotLike '*Loopback*' -And $_.Status -eq 'Up'}).InterfaceAlias | ForEach-Object -Process { 339 | if ($inf_bindings_ipv6) { 340 | # Disable IPv6 341 | Enable-NetAdapterBinding -InterfaceAlias $_ -ComponentID ms_tcpip6 342 | } 343 | if ($inf_bindings_lltp) { 344 | # Disable Link-Layer Topology Discovery Mapper I/O Driver 345 | Enable-NetAdapterBinding -InterfaceAlias $_ -ComponentID ms_lltdio 346 | # Disable Microsoft LLDP protocol Driver 347 | Enable-NetAdapterBinding -InterfaceAlias $_ -ComponentID ms_lldp 348 | } 349 | if ($inf_bindings_client) { 350 | # Disable Client for Microsoft Networks 351 | Enable-NetAdapterBinding -InterfaceAlias $_ -ComponentID ms_msclient 352 | # Disable File and Printer Sharing for Microsoft Networks 353 | Enable-NetAdapterBinding -InterfaceAlias $_ -ComponentID ms_server 354 | } 355 | if ($inf_bindings_namp) { 356 | # Disable Microsoft Network Adapter Multiplexor Protocol 357 | Enable-NetAdapterBinding -InterfaceAlias $_ -ComponentID ms_implat 358 | } 359 | } 360 | } 361 | }else{ 362 | Write-Host '[!] Modification of interface inf_bindings is disabled.' 363 | } 364 | 365 | # Let's give a little whitespace for readability 366 | Write-Host '' 367 | } 368 | #################### 369 | 370 | # Terminal Services (RDP) 371 | #################### 372 | function Get-TerminalServicesState(){ 373 | # Check for RDP Registry Setting 374 | Write-Host '[*] Checking RDP Registry Configuration' 375 | if ((Get-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Terminal Server' -name "fDenyTSConnections").fDenyTSConnections){ 376 | Write-Host '[*] RDP is Disabled' 377 | }else{ 378 | Write-Host '[*] RDP is Enabled' 379 | } 380 | 381 | # Check for the 'Block RDP - SAWH' 382 | # Get their interface GUID to query the specific registry key 383 | Write-Host '[*] Check for Block RDP - SAWH rule using Windows Firewall' 384 | $check_rdp_fw_rule = Get-NetFirewallRule -DisplayName "Block RDP - SAWH" -ErrorAction SilentlyContinue 385 | if ($check_rdp_fw_rule){ 386 | if (($check_rdp_fw_rule).Enable){ 387 | Write-Host '[*] Block RDP - SAWH rule enabled.' 388 | }else{ 389 | Write-Host '[*] Block RDP - SAWH rule disabled.' 390 | } 391 | Write-Host '[*] RDP - SAWH rule configuration' 392 | $check_rdp_fw_rule 393 | Write-Host '[*] RDP - SAWH rule port settings' 394 | $check_rdp_fw_rule | Get-NetFirewallPortFilter 395 | }else{ 396 | '[*] Block RDP - SAWH rule not configured on this system' 397 | } 398 | 399 | # Let's give a little whitespace for readability 400 | Write-Host '' 401 | } 402 | 403 | function Set-TerminalServicesState(){ 404 | 405 | Param( 406 | # Enable means to change the setting to the default / insecure state. 407 | $Enable = $false 408 | ) 409 | 410 | if ($disable_rdp){ 411 | $disable_rdp_setting = Get-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Terminal Server' -name "fDenyTSConnections" 412 | $check_rdp_fw_rule = Get-NetFirewallRule -DisplayName "Block RDP - SAWH" -ErrorAction SilentlyContinue 413 | if (-NOT $Enable) { 414 | # Disable RDP in registry 415 | if ($disable_rdp_setting.fDenyTSConnections){ 416 | Write-Host '[*] RDP was already disabled' 417 | }else{ 418 | Set-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Terminal Server' -name "fDenyTSConnections" -value 1 419 | Write-Host '[*] RDP was disabled' 420 | } 421 | # Disable RDP in Firewall 422 | if ($check_rdp_fw_rule){ 423 | if (($check_rdp_fw_rule).Enable){ 424 | Write-Host '[*] Block RDP - SAWH rule already enabled.' 425 | }else{ 426 | Set-NetFirewallRule -DisplayName "Block RDP - SAWH" -Enabled True 427 | Write-Host '[*] Block RDP - SAWH rule enabled.' 428 | } 429 | }else{ 430 | # TODO: Add UDP Firewall Rule 431 | New-NetFirewallRule -DisplayName "Block RDP - SAWH" -Direction Inbound -LocalPort 3389 -Protocol TCP -Action Block 432 | } 433 | }else{ 434 | # Enable RDP in registry 435 | if ($disable_rdp_setting.fDenyTSConnections){ 436 | Set-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Terminal Server' -name "fDenyTSConnections" -value 0 437 | Write-Host '[*] RDP was enabled' 438 | }else{ 439 | Write-Host '[*] RDP was already enabled' 440 | } 441 | # Enable RDP by disabling firewall rule 442 | if ($check_rdp_fw_rule){ 443 | if (($check_rdp_fw_rule).Enable){ 444 | Set-NetFirewallRule -DisplayName "Block RDP - SAWH" -Enabled False 445 | Write-Host '[*] Block RDP - SAWH rule disabled.' 446 | }else{ 447 | Write-Host '[*] Block RDP - SAWH rule already disabled.' 448 | } 449 | }else{ 450 | Write-Host '[*] Block RDP - SAWH rule not configured on this system' 451 | } 452 | } 453 | }else{ 454 | Write-Host '[!] Modification of Terminal Services (RDP) is disabled.' 455 | } 456 | 457 | # Let's give a little whitespace for readability 458 | Write-Host '' 459 | } 460 | #################### 461 | 462 | # Service Message Bus (SMB) Hardening 463 | #################### 464 | function Get-SMBConfigState(){ 465 | 466 | #################### 467 | # Check SMB Configuration 468 | #################### 469 | Write-Host '[*] Checking SMB Configuration' 470 | Write-Host "[*] SMB configuration is currently: " 471 | Get-SmbServerConfiguration 472 | 473 | # Let's give a little whitespace for readability 474 | Write-Host '' 475 | } 476 | 477 | function Set-SMBConfigState(){ 478 | 479 | Param( 480 | # Enable means to change the setting to the default / insecure state. 481 | $Enable = $false 482 | ) 483 | 484 | #################### 485 | # Disable SMBv1 - This should be last because of reboot prompt 486 | #################### 487 | if ($harden_smb){ 488 | if (-NOT $Enable) { 489 | Write-Host '[*] Hardening SMB configuration settings.' 490 | Set-SmbServerConfiguration -AutoShareServer $false -AutoShareWorkstation $false -RequireSecuritySignature $true -EnableSecuritySignature $true -EncryptData $true -Confirm:$false 491 | }else{ 492 | Write-Host '[*] Setting SMB service back to standard default configuration.' 493 | Set-SmbServerConfiguration -AutoShareServer $true -AutoShareWorkstation $true -RequireSecuritySignature $false -EnableSecuritySignature $false -EncryptData $false -Confirm:$false 494 | } 495 | } 496 | 497 | # Let's give a little whitespace for readability 498 | Write-Host '' 499 | } 500 | 501 | # Service Message Bus version 1 (SMBv1) 502 | #################### 503 | function Get-SMBv1State(){ 504 | 505 | #################### 506 | # Check SMBv1 507 | #################### 508 | Write-Host '[*] Checking SMBv1 Configuration' 509 | $smb_state = (Get-WindowsOptionalFeature -Online -FeatureName smb1protocol).State 510 | Write-Host "[*] SMBv1 is currently: $smb_state" 511 | 512 | # Let's give a little whitespace for readability 513 | Write-Host '' 514 | } 515 | 516 | function Set-SMBv1State(){ 517 | 518 | Param( 519 | # Enable means to change the setting to the default / insecure state. 520 | $Enable = $false 521 | ) 522 | 523 | #################### 524 | # Disable SMBv1 - This should be last because of reboot prompt 525 | #################### 526 | if ($disable_smbv1){ 527 | $smb_state = (Get-WindowsOptionalFeature -Online -FeatureName smb1protocol).State 528 | if (-NOT $Enable) { 529 | if ($smb_state -eq 'Enabled'){ 530 | Write-Host '[*] Disabling SMBv1 - requires reboot' 531 | Disable-WindowsOptionalFeature -Online -FeatureName smb1protocol 532 | }else{ 533 | Write-Host '[*] SMBv1 already disabled.' 534 | } 535 | }else{ 536 | Write-Host '[*] We are not going to enable SMBv1. You do not need it. Do it yourself.' 537 | # Enable-WindowsOptionalFeature -Online -FeatureName smb1protocol 538 | } 539 | } 540 | 541 | # Let's give a little whitespace for readability 542 | Write-Host '' 543 | } 544 | 545 | #################### 546 | 547 | # Default Windows apps 548 | #################### 549 | function Get-DefaultWindowsApps(){ 550 | Write-Host '[*] Getting list of installed Windows apps' 551 | Get-AppxPackage | Format-Table Name 552 | # Uncomment to get list of apps that will be installed for future users 553 | #Get-AppxProvisionedPackage -Online | Format-Table DisplayName, PackageName 554 | } 555 | 556 | function Set-DefaultWindowsApps(){ 557 | Param( 558 | # Enable means to change the setting to the default / insecure state. 559 | $Enable = $false 560 | ) 561 | 562 | #List of default windows apps to uninstall 563 | $default_windows_apps = ( 564 | "Microsoft.BingWeather", 565 | "Microsoft.BingNews", 566 | "Microsoft.BingFinance", 567 | "Microsoft.BingSports", 568 | "Microsoft.BingTranslator", 569 | "Microsoft.Print3D", 570 | "Microsoft.3DBuilder", 571 | "Microsoft.Microsoft3DViewer", 572 | "Microsoft.DesktopAppInstaller", 573 | "Microsoft.GetHelp", 574 | "Microsoft.Getstarted", 575 | "Microsoft.Messaging", 576 | "Microsoft.MicrosoftOfficeHub", 577 | "Microsoft.MicrosoftSolitaireCollection", 578 | "Microsoft.MixedReality.Portal", 579 | "Microsoft.OneConnect", 580 | "Microsoft.People", 581 | "Microsoft.SkypeApp", 582 | "Microsoft.StorePurchaseApp", 583 | "Microsoft.Wallet", 584 | "Microsoft.WindowsMaps", 585 | "Microsoft.WindowsStore", 586 | "Microsoft.Xbox.TCUI", 587 | "Microsoft.XboxApp", 588 | "Microsoft.XboxGameOverlay", 589 | "Microsoft.XboxGamingOverlay", 590 | "Microsoft.XboxIdentityProvider", 591 | "Microsoft.XboxSpeechToTextOverlay", 592 | "Microsoft.YourPhone", 593 | "Microsoft.ZuneMusic", 594 | "Microsoft.ZuneVideo", 595 | "Microsoft.Whiteboard", 596 | "Microsoft.WindowsSoundRecorder", 597 | "microsoft.windowscommunicationsapps", 598 | "Microsoft.RemoteDesktop", #this doesn't block rdp, its just modern Windows app 599 | "Microsoft.NetworkSpeedTest", 600 | "Microsoft.Office.Sway" 601 | ) 602 | 603 | if ($uninstall_windows_apps){ 604 | if (-NOT $Enable) { 605 | Write-Host '[*] Uninstalling selected default Windows apps for all current users.' 606 | foreach($app in $default_windows_apps){ 607 | Write-host "Uninstalling $app" 608 | Get-AppxPackage -Name $app -AllUsers | Remove-AppxPackage 609 | # Uncomment to remove it completely, makes it impossible to install 610 | #Get-AppxProvisionedPackage -Online | Where-Object {$_.DisplayName -eq $app} | Remove-AppxProvisionedPackage -Online 611 | Write-Host '[*] Selected default Windows apps uninstalled.' 612 | } 613 | } 614 | else{ 615 | Write-Host '[*] Installing selected default Windows apps.' 616 | foreach($app in $default_windows_apps){ 617 | Write-host "Installing $app" 618 | Get-AppxPackage -AllUsers $app | ForEach-Object {Add-AppxPackage -DisableDevelopmentMode -Register "$($_.InstallLocation)\AppXManifest.xml"} 619 | Write-Host '[*] Selected default Windows apps installed - shortcuts need to be restored manually.' 620 | } 621 | } 622 | } 623 | } 624 | 625 | #################### 626 | # Print Functions 627 | #################### 628 | 629 | 630 | # Print program beginning message 631 | #################### 632 | function Write-ProgStart { 633 | if ($show_warning){ Write-Host "$warning" } 634 | Write-Host "[*] Started Date/Time: $(get-date -format yyyyMMddTHHmmssffzz)" 635 | Write-Host "[*] Running on Windows: $sysversion" 636 | Write-Host "[*] $script_name is about to start. Run the following Nmap scan (from a seperate system) and check current statue before proceeding:" 637 | Write-Host '[*] sudo nmap -sT -p 135,137,139,445,3389 ' 638 | } 639 | #################### 640 | 641 | # Print program completed message 642 | #################### 643 | function Write-ProgComplete { 644 | Write-Host "[*] Completed Date/Time: $(get-date -format yyyyMMddTHHmmssffzz)" 645 | Write-Host "[*] $script_name has completed. Run the following Nmap scan (from a seperate system) and check the results:" 646 | Write-Host '[*] sudo nmap -sT -p 135,137,139,445,3389 ' 647 | Write-Host '[*] Do not forget to reboot before testing.' 648 | } 649 | #################### 650 | 651 | # Print configuration information 652 | #################### 653 | function Write-SAWHConfig { 654 | Write-Host "" 655 | Write-Host "################################" 656 | Write-Host "[*] SAWH Configuration Settings" 657 | Write-Host "################################" 658 | Write-Host "[*] Running on Windows: $sysversion" 659 | Write-Host "[*] Modifying network interface mode is set to: $inf_private_mode" 660 | Write-Host "[*] Modifying NetBIOS is set to: $disable_netbios" 661 | Write-Host "[*] Modifying Firewall Rules is set to: $fw_rules" 662 | Write-Host "[*] Modifying Network Adapter inf_bindings is set to: $inf_bindings" 663 | Write-Host " [*] Modifying Network Adapter IPv6 Binding is set to: $inf_bindings_ipv6" 664 | Write-Host " [*] Modifying Network Adapter LLTP inf_bindings is set to: $inf_bindings_lltp" 665 | Write-Host " [*] Modifying Network Adapter Client / Server inf_bindings is set to: $inf_bindings_client" 666 | Write-Host " [*] Modifying Network Adapter Multiplexor Binding is set to: $inf_bindings_namp" 667 | Write-Host "[*] Modifying Terminal Services (RDP) is set to: $disable_rdp" 668 | Write-Host "[*] Modifying SMB Configuration is set to: $harden_smb" 669 | Write-Host "[*] Modifying SMBv1 is set to: $disable_smbv1" 670 | Write-Host "[*] Uninstalling default Windows Apps is set to: $uninstall_windows_apps" 671 | Write-Host "################################" 672 | Write-Host "" 673 | } 674 | #################### 675 | 676 | # Print System State 677 | #################### 678 | function Write-SystemState { 679 | Get-InterfaceModeState 680 | Get-NetBIOSState 681 | Get-SAWHFWRulesState 682 | Get-NetInfBindingsState 683 | Get-TerminalServicesState 684 | Get-SMBConfigState 685 | Get-SMBv1State 686 | Get-DefaultWindowsApps 687 | } 688 | #################### 689 | 690 | 691 | #################### 692 | # Main 693 | #################### 694 | Get-AdminState 695 | Write-ProgStart 696 | 697 | # Determine what user wants to do 698 | #################### 699 | $action = Read-Host "Do you want to check, disable, or rollback Windows services? [check/disable/rollback]" 700 | # Set user input. 701 | if ($action -eq 'check') { 702 | $check = $true 703 | } 704 | if ($action -eq 'disable') { 705 | $disable = $true 706 | } 707 | if ($action -eq 'rollback') { 708 | $rollback = $true 709 | } 710 | # Check user input. Fail if it isn't exactly what we expected 711 | if ($rollback -eq $false -And $disable -eq $false -And $check -eq $false){ 712 | Write-Host "[!] User did not select a valid action. Exiting..." 713 | Exit 714 | } 715 | 716 | # Run check function 717 | #################### 718 | if ($check){ 719 | Write-SAWHConfig 720 | Write-SystemState 721 | Exit 722 | } 723 | 724 | # Run action functions 725 | #################### 726 | # Write state before we start? 727 | if ($start_state) { Write-SystemState } 728 | 729 | # Run disable function 730 | #################### 731 | if ($disable){ 732 | # Get user confirmation before proceeding 733 | Write-Host "[*] SAWH Disable Function" 734 | Get-UserConfirmation 735 | 736 | Set-InterfaceModeState 737 | Set-NetBIOSState 738 | Set-SAWHFWRulesState 739 | Set-NetInfBindingsState 740 | Set-TerminalServicesState 741 | Set-SMBConfigState 742 | Set-SMBv1State 743 | Set-DefaultWindowsApps 744 | } 745 | 746 | # Run rollback function 747 | #################### 748 | if ($rollback){ 749 | # Get user confirmation before proceeding 750 | Write-Host "[*] SAWH Rollback Function" 751 | Get-UserConfirmation 752 | 753 | Set-InterfaceModeState -Enable $true 754 | Set-NetBIOSState -Enable $true 755 | Set-SAWHFWRulesState -Enable $true 756 | Set-NetInfBindingsState -Enable $true 757 | Set-TerminalServicesState -Enable $true 758 | Set-SMBConfigState -Enable $true 759 | Set-SMBv1State -Enable $true 760 | Set-DefaultWindowsApps -Enable $true 761 | 762 | } 763 | 764 | # Write state after completion? 765 | if ($completed_state) { Write-SystemState } 766 | 767 | # All done, say goodbye 768 | Write-ProgComplete 769 | --------------------------------------------------------------------------------