How to Setup, Manage, and Maintain WSUS
We can go on explaining why you should switch over your WSUS Server to SSL so that you can mitigate Man-In-The-Middle (MITM) attacks, but sometimes it is better to show you.
The following video is worth the watch as they explain exactly how relatively easy it is to take over a network by just having access to it with a WSUS Server that does not have SSL Enabled.
From Blackhat USA 2015 – WSUSpect – Compromising The Windows Enterprise Via Windows Update
Please, everyone, mitigate this risk and switch your WSUS to SSL. This does NOT mean that you can turn off HTTP as communication between clients and the WSUS server use both HTTP and HTTPS much like FTP uses port 20 (data) and 21 (command channel).
Emin Atac, a PowerShell MVP, posted a simple PowerShell method of switching your WSUS Server to use SSL with a self-signed Certificate which we have re-posted here with some modifications for streamlining. We have also broken this out into 2 groups – a self-signed certificate script and an internal CA certificate script. The self-signed certificate method contains 8 steps and 7 of them can be copy/pasted or run as a single step. If you have your own Internal CA, it is best to use your CA to request the certificate and import it into your certificate store on the WSUS server then run the script.
Self-Signed Certificate PowerShell Conversion to HTTPS for WSUS
PowerShell Example – Do not copy/paste this into a script. Instead run it line by line on the PowerShell console so that you can adjust based on your needs. If you need to deploy it to multiple systems, after confirming your commands, then you can take those and build it into a deployment script.
# 1. Create a self-signed certificate using the FQDN
# Setup the stage dynamically for the $FQDN based on if the system is a member of a domain or is just in a workgroup.
$DNSHostName = (Get-CimInstance win32_computersystem -Verbose:$False).DNSHostName
$DNSDomainName = $( if ((Get-CimInstance -Class Win32_ComputerSystem -Verbose:$False).PartOfDomain -eq 'True') { (Get-CimInstance win32_computersystem -Verbose:$False).Domain } )
$FQDN = "$DNSHostName$( if ((Get-CimInstance -Class Win32_ComputerSystem -Verbose:$False).PartOfDomain -eq 'True') { ".$DNSDomainName" } )".ToLower()
# Create the hash table for splatting
$SelfSignedHT = @{
DnsName = $FQDN
CertStoreLocation = "Cert:\LocalMachine\My"
}
# Create the self-signed certificate and set a variable to hold the object
$SelfSignedWSUSCertificate = New-SelfSignedCertificate @SelfSignedHT
# 2. Export its public key to the local user's Documents folder
Export-Certificate -Cert $SelfSignedWSUSCertificate -Type CERT -FilePath "$([Environment]::GetFolderPath("MyDocuments"))\SelfSignedWSUSCertificate.cer"
# 3. Import the public key in the Trusted Root Certificate Authorities store
Import-Certificate -FilePath "$([Environment]::GetFolderPath("MyDocuments"))\SelfSignedWSUSCertificate.cer" -CertStoreLocation Cert:\LocalMachine\Root
# 4. Select this certificate in the SSL bindings
Get-WebBinding -Protocol https
$SelfSignedWSUSCertificate | New-Item IIS:\SslBindings\0.0.0.0!8531
# 5. Require SSL for the following virtual roots only:
'SimpleAuthWebService','DSSAuthWebService',
'ServerSyncWebService','APIRemoting30',
'ClientWebService' | ForEach-Object {
Set-WebConfigurationProperty -Filter 'system.webserver/security/access' -Location "WSUS Administration/$($_)" -Name sslFlags -Value 8
}
# 6. Switch WSUS to SSL
& 'C:\Program Files\Update Services\Tools\WsusUtil.exe' configuressl $($FQDN)
# 7. Change your GPO to point to the new URL
if ($(Get-WindowsFeature -Name GPMC).installed -eq $False) { Install-WindowsFeature GPMC }
Import-Module -Name GroupPolicy
$WindowsUpdateKey = 'HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate'
$WindowsUpdateURI = 'https://{0}:8531' -f $($FQDN)
Get-GPO -All | Foreach-Object {
if ($_ | Get-GPRegistryValue -Key $WindowsUpdateKey -ValueName WUServer -EA 0) {
$_ | Set-GPRegistryValue -Key $WindowsUpdateKey -ValueName WUServer -Value $WindowsUpdateURI -Type String
$_ | Set-GPRegistryValue -Key $WindowsUpdateKey -ValueName WUStatusServer -Value $WindowsUpdateURI -Type String
# If you are NOT storing updates locally computers install from Microsoft Update - DO NOT set the UpdateServiceUrlAlternate URI
if ($(Get-WsusServer).GetConfiguration().HostBinariesOnMicrosoftUpdate -eq $False) {
$_ | Set-GPRegistryValue -Key $WindowsUpdateKey -ValueName UpdateServiceUrlAlternate -Value $WindowsUpdateURI -Type String
}
}
}
The last step is to distribute the public key of your self-signed certificate to your clients so that they trust your self-signed certificate. You’ll need to edit your GPO that targets clients and import your SelfSignedWSUSCertificate.cer file located in your Documents folder into ‘Computer Configuration / Policies / Windows Settings / Security Settings / Public Key Policies / Trusted Root Certificate Authorities’
Internal CA Certificate PowerShell Conversion to HTTPS for WSUS
This assumes you have already requested and received the certificate and it is installed on the WSUS server.
PowerShell Example – Do not copy/paste this into a script. Instead run it line by line on the PowerShell console so that you can adjust based on your needs. If you need to deploy it to multiple systems, after confirming your commands, then you can take those and build it into a deployment script.
# 1. Get the certificate from the certificate store and add the object into a variable
# Setup the stage dynamically for the $FQDN based on if the system is a member of a domain or is just in a workgroup.
$DNSHostName = (Get-CimInstance win32_computersystem -Verbose:$False).DNSHostName
$DNSDomainName = $( if ((Get-CimInstance -Class Win32_ComputerSystem -Verbose:$False).PartOfDomain -eq 'True') { (Get-CimInstance win32_computersystem -Verbose:$False).Domain } )
$FQDN = "$DNSHostName$( if ((Get-CimInstance -Class Win32_ComputerSystem -Verbose:$False).PartOfDomain -eq 'True') { ".$DNSDomainName" } )"
$CA_WSUSCertificate = Get-ChildItem -Path Cert:\LocalMachine\My -SSLServerAuthentication | Where-Object { $_.Subject -ilike "*$($FQDN.ToLower())*" }
if ($CA_WSUSCertificate.Count -gt 1) { Write-Output "There are too many certificates with the FQDN '$FQDN'. You will have to select only one for this variable or you will end up getting all errors trying to set the binding."}
# 2. Select this certificate in the SSL bindings
Get-WebBinding -Protocol https
$CA_WSUSCertificate | New-Item IIS:\SslBindings\0.0.0.0!8531
# 3. Require SSL for the following virtual roots only:
'SimpleAuthWebService','DSSAuthWebService',
'ServerSyncWebService','APIRemoting30',
'ClientWebService' | ForEach-Object {
Set-WebConfigurationProperty -Filter 'system.webserver/security/access' -Location "WSUS Administration/$($_)" -Name sslFlags -Value 8
}
# 4. Switch WSUS to SSL
& 'C:\Program Files\Update Services\Tools\WsusUtil.exe' configuressl $($FQDN)
# 5. Change your GPO to point to the new URL
if ($(Get-WindowsFeature -Name GPMC).installed -eq $False) { Install-WindowsFeature GPMC }
Import-Module -Name GroupPolicy
$WindowsUpdateKey = 'HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate'
$WindowsUpdateURI = 'https://{0}:8531' -f $($FQDN)
Get-GPO -All | Foreach-Object {
if ($_ | Get-GPRegistryValue -Key $WindowsUpdateKey -ValueName WUServer -EA 0) {
$_ | Set-GPRegistryValue -Key $WindowsUpdateKey -ValueName WUServer -Value $WindowsUpdateURI -Type String
$_ | Set-GPRegistryValue -Key $WindowsUpdateKey -ValueName WUStatusServer -Value $WindowsUpdateURI -Type String
# If you are NOT storing updates locally computers install from Microsoft Update - DO NOT set the UpdateServiceUrlAlternate URI
if ($(Get-WsusServer).GetConfiguration().HostBinariesOnMicrosoftUpdate -eq $False) {
$_ | Set-GPRegistryValue -Key $WindowsUpdateKey -ValueName UpdateServiceUrlAlternate -Value $WindowsUpdateURI -Type String
}
}
}
As you have already distributed your internal RootCA certificate, you are finished.