Fighting Fire with Fire: Building a Windows Security Fortress with Scripts
Fighting Fire with Fire: Building a Windows Security Fortress with Scripts
"If scripts are outlawed, only outlaws will have scripts." This sentiment lies at the heart of a long-standing debate over scripting security. Whenever a new virus or cyber-attack emerges, scripts are often the first to be blamed. However, banning scripts entirely is a classic case of throwing the baby out with the bathwater. Scripts are not just potential attack vectors; they are also powerful, flexible tools for automation and security hardening in the hands of a system administrator. This article explores how to use Windows scripts (combining WMI and ADSI) to replicate and even enhance the core functions of the Microsoft Baseline Security Analyzer (MBSA), turning a potential vulnerability into a powerful defense mechanism.
Knowledge is Power: The Synergy of Scripts and MBSA
The Microsoft Baseline Security Analyzer (MBSA) is an excellent free tool that analyzes computers for potential security risks, such as missing security patches or weak password policies. However, MBSA's primary function is to "report." It tells you "what" is wrong but cannot automatically "fix" the problem. For example, MBSA can report that 2,967 computers on your network have the Guest account enabled, but you still need to go and disable them one by one manually.
This is where scripting shines. The power of scripting lies not only in its ability to "get" security information but also in its capacity to automatically "act" on that information. We can write scripts to check for and automatically remediate identified security issues. Below, we will demonstrate through a series of specific security tasks how to use scripts to perform MBSA's checks and, where possible, write further scripts to fix the issues automatically.
Note: To simplify the examples, the following scripts are all targeted at the local machine. With minor modifications, they can be easily extended to manage hundreds or thousands of computers across a network.
Scripting 14 Core Security Tasks
Task 1: Retrieve Computer Name and IP Address
When conducting a security audit, the first step is to identify the target machine. The following WMI script retrieves the computer name and its enabled IP addresses.
' Get Computer Name
strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set colComputers = objWMIService.ExecQuery("Select * from Win32_ComputerSystem")
For Each objComputer in colComputers
Wscript.Echo "Computer Name: " & objComputer.Name
Next
' Get IP Address
Set IPConfigSet = objWMIService.ExecQuery("Select IPAddress from Win32_NetworkAdapterConfiguration Where IPEnabled=TRUE")
For Each IPConfig in IPConfigSet
If Not IsNull(IPConfig.IPAddress) Then
For Each strAddress in IPConfig.IPAddress
WScript.Echo "IP Address: " & strAddress
Next
End If
Next
Task 2: Check OS Service Pack Version
Ensuring systems have the latest service pack is fundamental to defending against known vulnerabilities. This script queries the latest Service Pack version via WMI.
strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set colOS = objWMIService.ExecQuery("Select * from Win32_OperatingSystem")
For Each objOS in colOS
Wscript.Echo "Service Pack: " & objOS.ServicePackMajorVersion & "." & objOS.ServicePackMinorVersion
Next
Task 3: Check Installed Security Hotfixes
Many successful attacks are due to the failure to install released security patches. This script lists all installed Quick Fix Engineering (QFE) updates on the system.
strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set colQuickFixes = objWMIService.ExecQuery("Select * from Win32_QuickFixEngineering")
For Each objQuickFix in colQuickFixes
Wscript.Echo "HotFix ID: " & objQuickFix.HotFixID & " - Description: " & objQuickFix.Description
Next
Task 4: Check Number of Local Administrators
Too many administrators mean a larger attack surface. This script not only lists all members of the local Administrators group but can also automatically remove non-compliant accounts.
' List Administrators
Set objGroup = GetObject("WinNT://./Administrators,group")
For Each objUser in objGroup.Members
Wscript.Echo objUser.Name
Next
' Automatically Remove Non-Compliant Admins (Example Policy: Allow only local Administrator and domain admin fabrikam\Administrator)
Set objGroup = GetObject("WinNT://./Administrators,group")
For Each objUser in objGroup.Members
If LCase(objUser.Name) <> "administrator" and LCase(objUser.Name) <> "fabrikam\administrator" Then
objGroup.Remove(objUser.ADsPath)
End If
Next
Task 5: Check for Passwords That Don't Expire
Forcing regular password expiration is an effective security measure. The following script finds all accounts set to "Password never expires" and can automatically change that setting.
Const ADS_UF_DONT_EXPIRE_PASSWD = &H10000
' Check and Report
Set colAccounts = GetObject("WinNT://.")
colAccounts.Filter = Array("user")
For Each objUser In colAccounts
flag = objUser.Get("UserFlags")
If flag AND ADS_UF_DONT_EXPIRE_PASSWD Then
Wscript.Echo objUser.Name & ": Password does not expire."
End If
Next
' Auto-Remediate: Force all user passwords to expire
For Each objUser In colAccounts
flag = objUser.Get("UserFlags")
If flag AND ADS_UF_DONT_EXPIRE_PASSWD Then
objUser.UserFlags = flag XOR ADS_UF_DONT_EXPIRE_PASSWD
objUser.SetInfo
End If
Next
Task 6: Test for Weak Passwords
MBSA can detect weak passwords like blank passwords or passwords identical to the username. Scripts can simulate this check. This example detects if the password is "password".
On Error Resume Next
strPassword = "password"
Set colAccounts = GetObject("WinNT://.")
colAccounts.Filter = Array("user")
For Each objUser In colAccounts
objUser.ChangePassword strPassword, strPassword
If Err = 0 or Err = -2147023569 Then
Wscript.Echo objUser.Name & " is using the weak password '" & strPassword & "'."
End If
Err.Clear
Next
Task 7: Check File System Type
Using the NTFS file system is essential for access control. This script checks if all local hard drive partitions are formatted with NTFS.
strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set colDisks = objWMIService.ExecQuery("Select * from Win32_LogicalDisk Where DriveType = 3")
For Each objDisk in colDisks
If UCase(objDisk.FileSystem) <> "NTFS" Then
Wscript.Echo "Warning: Drive " & objDisk.DeviceID & " is using " & objDisk.FileSystem & ", not NTFS."
End If
Next
Task 8: Check Auto-Logon Settings
Auto-logon is convenient but poses a serious security risk. This script checks and disables the auto-logon feature via the registry.
Const HKEY_LOCAL_MACHINE = &H80000002
strKeyPath = "Software\Microsoft\Windows NT\CurrentVersion\WinLogon"
strValueName = "AutoAdminLogon"
Set objReg = GetObject("winmgmts:\\.\root\default:StdRegProv")
' Check Status
objReg.GetDWORDValue HKEY_LOCAL_MACHINE, strKeyPath, strValueName, dwValue
If dwValue = 1 Then
Wscript.Echo "Auto-logon is enabled."
' Disable Auto-Logon
dwValue = 0
objReg.SetDWORDValue HKEY_LOCAL_MACHINE, strKeyPath, strValueName, dwValue
Wscript.Echo "Auto-logon has been disabled."
End If
Task 9: Check Guest Account Status
The Guest account should always be disabled. This script checks its status and automatically disables it if found enabled.
Set objUser = GetObject("WinNT://./Guest")
If objUser.AccountDisabled Then
Wscript.Echo "The Guest account is disabled."
Else
Wscript.Echo "Warning: The Guest account is currently enabled."
objUser.AccountDisabled = True
objUser.SetInfo
Wscript.Echo "The Guest account has now been automatically disabled."
End If
Task 10: Check for Anonymous Logon (RestrictAnonymous)
Restricting anonymous access prevents unauthorized users from enumerating domain usernames and shares. This script checks and sets the correct registry key to restrict anonymous access.
Const HKEY_LOCAL_MACHINE = &H80000002
strKeyPath = "System\CurrentControlSet\Control\Lsa"
strValueName = "RestrictAnonymous"
Set objReg = GetObject("winmgmts:\\.\root\default:StdRegProv")
' Check and Remediate
objReg.GetDWORDValue HKEY_LOCAL_MACHINE, strKeyPath, strValueName, dwValue
If dwValue = 0 Then
Wscript.Echo "Anonymous access is enabled, posing a risk."
dwValue = 1
objReg.SetDWORDValue HKEY_LOCAL_MACHINE, strKeyPath, strValueName, dwValue
Wscript.Echo "Anonymous access has been restricted."
End If
Task 11: List Running Services
Knowing what services are running helps detect malware or unauthorized applications (like a private FTP server). This script can list services and also stop a specified service.
' List all services and their state
strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set colServices = objWMIService.ExecQuery("Select * from Win32_Service")
For Each objService in colServices
Wscript.Echo objService.DisplayName, objService.State
Next
' Stop a specific service (e.g., UPnPHost)
Set colServices = objWMIService.ExecQuery("Select * from Win32_Service Where Name = 'upnphost'")
For Each objService in colServices
objService.StopService()
Next
Task 12: Check File Shares and Permissions
Insecure shares are a common entry point for data breaches and lateral movement. This script can list all shares and their paths.
strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set colShares = objWMIService.ExecQuery("Select * from Win32_Share")
For Each objShare in colShares
Wscript.Echo "Share Name: " & objShare.Name & ", Path: " & objShare.Path
Next
Conclusion
Far from being the villain of the security world, scripting is a powerful weapon for system administrators to achieve automated, scalable security management. By combining the checking logic of MBSA with the execution power of scripts, we can not only find problems but also solve them efficiently and consistently, thereby building a robust and intelligent security defense line across the enterprise network.