Windows hardening
There are many things I like in GNU/Linux systems, nonetheless, Windows has many upsides too. I’ve already admitted I’m still using from time to time even older/unsupported versions of Windows.
Maybe it’s just me, but I tend to install Windows (inside a Virtual Machine) quite often. Also, because of my INIMA project, I’ve done many installations for testing.
The most "painful" and error-prone process is configuring Windows.
Unlike most GNU/Linux operating systems, most tasks are easier to solve through graphical programs and not from the command line. This might be more user-friendly and discoverable without reading a manual, but only if the tasks need to be done once, and one has no interest in automating it. It also makes it harder to determine how the machine is configured, as one needs to use multiple programs.
Especially when thinking about security, it is important to automate as much as possible. Otherwise, it is too common to forget some open port, misconfigured program, and so on. It is also extremely important to be able to determine how the system is configured and to be able to change the configuration as easily as possible.
My security approach
Instead of executing and analyzing everything, I prefer my system to execute only what’s necessary. I’m not that maniac/expert (yet) to disable everything, it means knowing and understanding every aspect of the operating systems and programs it uses. In practice, the system is still doing a lot of things that I’m not aware of behind the scenes, but if I find something that I’m almost certain I do not need, then I’ve very probably disabled it.
The main motivation behind this approach is reducing the possible attack surface. If there is a malevolent file somewhere, why take any risk and execute it?
Antiviruses have their vulnerabilities and privacy implications too, so they are not a silver bullet.
After all, it’s just another program that is executed on our device, but
-
it runs as an administrator/with permission to do almost everything
-
it can change the behavior of other programs and the operating systems
-
it reads practically everything it can find and uses an internet connection.
While writing it, it felt like describing a very dangerous program, or the operating system itself. Thus, if there is some vulnerability in the antivirus software, it can be used very badly.
It also happened multiple times that AV software broke Windows installations not because they were exploited, but because they had a logic error and removed some files or changed some settings that were relevant to the operating system.
Also, most software seems to ship with outdated dependencies.
I’m not saying that Antivirus Software should be simply dismissed, they have their use cases too, but normally not when I’m using the computer.
Normally there is no recommendation to run an AV all the time on a GNU/Linux-based system. One of the reasons is that there are not as many programs running in the background as Windows. And even if it would be the case it is normally possible to disable nearly everything, while on Windows, this might be possible, but it is much harder and might undermine the stability of the system.
So on Windows, I still use an AV (if the machine is connected to the internet), but since Windows 10 has an integrated one, I stopped reaching for third-party vendors, even if they might be better. Otherwise, I still reach for ClamWin, but not for real-time protection (also because it does not provide such functionality).
Types of threats
A hacked PC has a lot of value, even if most people do not realize it, as they do "not have anything to hide or important on their machines".
Some common types of misuse of a hacked computer are
-
Use the resources of the infected PC (host website, crypto mining, …)
-
"destroy" system or user data
-
hide and steal data, eventually ask for money
-
take advantage of user interaction to solve puzzles
On KrebsOnSecurity 🗄️ there is a very informative graphic that enlists those and many more potential cases of abuse of a hacked computer.
Most, if not all types of attacks can be avoided by not executing malicious code.
Do not log in as an administrator
While the most precious data is the user data (as operating systems can hopefully be reinstalled, which, acknowledged, is not always true, for example for smartphones), running as non-administrative users reduces the surfaces of attack.
So running all programs without administrator rights will not prohibit a malevolent program from deleting or encrypting all documents and photos, like Cryptolocker or similar malware did, but it makes it harder for a program to change system settings, for example disabling the firewall, opening ports, changing Windows policies, replacing programs and so on.
Since Windows XP it is possible to run Windows with a non-default non-administrator account. As stated before, this automatically reduces the user’s privileges and access to files and folders, and the chance of potential damage.
Unfortunately on Windows XP, the mechanism for running a program as an administrator while being a different user is cumbersome, and many programs did not work correctly. Programs like SuRun helped to tackle those issues, but today (since Windows Vista the mechanism changed and improved) it’s no longer necessary.
But still, there are low-hanging fruits. I still name the default account "root". Even if UAC is enabled and the systems require the user to confirm some action, it is an administrator account. The only operation I normally do with this account is to create a second non-administrator account and log out. From now on, I only log in to the second account, and if something needs administrator privileges it’s a right-click away: right-click on the executable and select "Run as Administrator".
As for now, there are only two major annoyances:
-
the user folder is different,
-
some operations might require typing the password more than once
The first issue can be mitigated by creating a link from the root user folder to the normal user folder. The second issue can be mitigated by opening a prompt (cmd or PowerShell) as administrator and execute from there all the operations. It is easier said than done (for me at least), as I do not know yet how to reach some graphical user interfaces from the prompt, and also because some programs (like explorer.exe) are not possible to execute as a different user.
Disable execution of common double extensions
Windows Explorer is the default file manager of the operating system. It has, unfortunately, some inconvenient default settings.
First, change its settings to show all file extensions and hidden files.
$explorerm = "HKLM:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"
$exploreru = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"
# show hidden files
New-ItemProperty -path $explorerm -Name "Hidden" -Value 1 -Force | Out-Null
New-ItemProperty -path $exploreru -Name "Hidden" -Value 1 -Force | Out-Null
attrib "$env:USERPROFILE\NTUSER.DAT" +s +h # except for this one
# show file extensions
New-ItemProperty -path $explorerm -Name "HideFileExt" -Value 0 -Force | Out-Null
New-ItemProperty -path $exploreru -Name "HideFileExt" -Value 0 -Force | Out-Null
Unfortunately, if a new user is created, the default setting for this user is to hide the extension, thus the settings need to be applied for every user.
It is possible to change the default settings when creating a new user, even if a little bit cumbersome:
reg load HKLM\defaultuser C:\Users\Default\NTUSER.DAT
$explorer_adv="HKLM:\defaultuser\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"
# show hidden files
New-ItemProperty -path $explorer_adv -Name "Hidden" -Value 1 -Force | Out-Null
# show file extensions
New-ItemProperty -path $explorer_adv -Name "HideFileExt" -Value 0 -Force
[gc]::Collect() # might otherwise be impossible to unload registry
reg unload HKLM\defaultuser
Hiding file extensions is a security hazard.
It is also an inconsistent behavior as it seems to permit multiple files with the same name. The benefits of hiding known extensions are unclear, as even non-technical users, in my experience, do not seem to have problems if those are shown. On the other hand, it makes it easier to explain file types, to non-technical users, without explaining the meaning of icons, which change depending on the version of Windows and depending on which software is installed.
Malware like Cryptolocker took advantage of this behavior, as it was an executable file with the filename and the icon disguised as a PDF file.
The following policies work virtually on all Windows versions, as I’ve used some variants of it since Windows XP (Home Edition), even if only the non-Home edition of Windows has gpedit, a graphical tool for enabling, disabling and configuring policies.
$policies_codeid="HKLM:\SOFTWARE\Policies\Microsoft\Windows\Safer\CodeIdentifiers\";
New-ItemProperty -Path $policies_codeid -Name "authenticodeenabled" -Value 0 | Out-Null
New-ItemProperty -Path $policies_codeid -Name "DefaultLevel" -Value 262144 | Out-Null
New-ItemProperty -Path $policies_codeid -Name "PolicyScope" -Value 0 | Out-Null
New-ItemProperty -Path $policies_codeid -Name "TransparentEnabled" -Value 1 | Out-Null
$executabletypes=@( #gpedit, Computer Configuration, Windows Settings, Security Settings, Software restriction Policies, Designated File types
,"ade", "adp", "bas", "bat", "chm", "cmd", "com", "cpl", "crt", "diagcab"
,"exe", "hlp", "hta", "inf", "ins", "isp", "mdb", "mde", "msc", "msi"
,"msp", "mst", "ocx", "pcd", "pif", "reg", "scr", "shs", "url", "vb", "vsix"
,"wsc"
# test/check, not listed like the others, but also get "executed" on double-click
,"application", "gadget", "vbs", "vbe", "js", "jse", "ws", "wsf"
,"wsh", "ps1", "ps1xml", "ps2" , "ps2xml", "psc1", "psc2"
,"msh", "msh1", "msh2", "mshxml", "msh1xml", "msh2xml", "scf", "rgs"
)
New-ItemProperty -Path $policies_codeid -Name "ExecutableTypes" -PropertyType MultiString -Value $executabletypes | Out-Null
foreach ($ext in $executabletypes) {
$guid = "{"+(New-Guid).guid+"}"
$path = "$policies_codeid\0\Paths\$guid"; # disallowed=0, Unrestricted=262144
New-Item $path -Force | Out-Null
New-ItemProperty -Path $path -Name "Description" -Value "INIMA" | Out-Null
New-ItemProperty -Path $path -Name "SaferFlags" -Value 0 | Out-Null
New-ItemProperty -Path $path -Name "Name" -Value "name" | Out-Null
New-ItemProperty -Path $path -Name "ItemData" -Value "*.????.$ext" | Out-Null
}
It will prevent execution files like foo.pdf.exe
and bar.docx.bat
.
It might break some applications that have a dot in the filename, for example, something like foo-1.2.exe
(which is not so uncommon in installers). In those cases, it is possible to rename the file, or temporarily disable the policies.
Otherwise, and this has been my approach, just block the most common extension, like pdf
, txt
, and doc
. It is not as effective, but it is so much better than nothing, and I do not think I ever had one use case where I needed to disable them:
$policies_codeid="HKLM:\SOFTWARE\Policies\Microsoft\Windows\Safer\CodeIdentifiers\";
New-ItemProperty -Path $policies_codeid -Name "authenticodeenabled" -Value 0 | Out-Null
New-ItemProperty -Path $policies_codeid -Name "DefaultLevel" -Value 262144 | Out-Null
New-ItemProperty -Path $policies_codeid -Name "PolicyScope" -Value 0 | Out-Null
New-ItemProperty -Path $policies_codeid -Name "TransparentEnabled" -Value 1 | Out-Null
$executabletypes=@( #gpedit, Computer Configuration, Windows Settings, Security Settings, Software restriction Policies, Designated File types
,"ade", "adp", "bas", "bat", "chm", "cmd", "com", "cpl", "crt", "diagcab"
,"exe", "hlp", "hta", "inf", "ins", "isp", "mdb", "mde", "msc", "msi"
,"msp", "mst", "ocx", "pcd", "pif", "reg", "scr", "shs", "url", "vb", "vsix"
,"wsc"
)
$commonextensions=@(
# documents
, "doc?", "pdf", "txt", "?htm?", "ppt?", "xls?",
# multimedia
, "mp?", "jp?g", "png"
# archives
, "zip", "rar"
)
New-ItemProperty -Path $policies_codeid -Name "ExecutableTypes" -PropertyType MultiString -Value $executabletypes | Out-Null
foreach ($cex in $commonextensions) {
foreach ($ext in $executabletypes) {
$guid = "{"+(New-Guid).guid+"}"
$path = "$policies_codeid\0\Paths\$guid"; # disallowed=0, Unrestricted=262144
New-Item $path -Force | Out-Null
New-ItemProperty -Path $path -Name "Description" -Value "INIMA" | Out-Null
New-ItemProperty -Path $path -Name "SaferFlags" -Value 0 | Out-Null
New-ItemProperty -Path $path -Name "Name" -Value "name" | Out-Null
New-ItemProperty -Path $path -Name "ItemData" -Value "*.$cex.$ext" | Out-Null
}
}
Disable execution of programs based on location
It might seem a good idea to also inhibit the execution of programs outside of the install directory and Windows folder.
On the other hand, there are many valid use cases, for example when developing, or automating some tasks with cmd
or PowerShell
, where some executables land in non-standard locations.
Also, some programs do not follow the Windows standard convention and want to get installed somewhere in the user directory.
It is possible to either avoid those programs or fine-tune the whitelist where software can be executed.
Otherwise, I believe it is enough to inhibit the execution from the Download
directory, where most "unknown" files land. The user can manually move them somewhere else before executing them, but I found it impractical for some workflows.
Blacklisting %TMP%
, generally, a well-known location for many malware programs breaks too many programs, especially updaters, and installers.
On the other hand, it is possible to change the value of %TMP%
for those programs that need to extract and execute a temporary file.
Disable/Remove unused services and programs
Because why run unnecessary programs? It’s easier to find something if there are fewer places to hide.
Also, as described in the beginning, all those running programs might decrease the security of the system.
Have thumbnails enabled? It means that a program is going to scan all files and check if it is an image and eventually generate a thumbnail. It can and has been 🗄️ exploited in the past. Without user interaction, just downloading a file, and some program behind the user’s back opens the file and compromises the system.
Of course, it won’t help the end-user very much if the exploit works with the program used for interacting with the file after downloading it, but it reduces the attack surface.
Also, there is no magic list of all things that can be safely disabled, as every user has different needs.
For example, I dislike most 3rd party applications installed by default and generally speaking, most preinstalled apps from the Windows store.
# 3rd party programs, and programs with no use
Get-AppxPackage | where {$_.name -Match "officehub|skype|getstarted|zune|solitaire|twitter|candy|farmville|airborne|advertising|bing|people|phone|xbox|sway|pandora|adobe|eclipse|duolingo|speed|power|messaging|remote"} | Remove-AppxPackage -ErrorAction SilentlyContinue
# may remove functionality from Windows
Get-AppxPackage | where {$_.name -Match "3dbuilder|windowsalarms|windowscommunication|windowscamera|onenote|soundrecorder|store|viewer|paint|help"} | Remove-AppxPackage -ErrorAction SilentlyContinue
While it is nice if the operating system provides some functionality out of the box, there might be better programs, even for free for accomplishing those tasks.
Also, I do not need many services constantly running in the background
# Geo services
Get-Service lfsvc,MapsBroker -ErrorAction SilentlyContinue | Stop-Service -PassThru | Set-Service -StartupType Disabled | Out-Null
# search
Get-Service WSearch -ErrorAction SilentlyContinue | Stop-Service -PassThru | Set-Service -StartupType Disabled | Out-Null
Get-Service HomeGroupListener,HomeGroupProvider -ErrorAction SilentlyContinue | Stop-Service -PassThru | Set-Service -StartupType Disabled | Out-Null
# disable media player
Get-Service WMPNetworkSvc -ErrorAction SilentlyContinue | Stop-Service -PassThru | Set-Service -StartupType Disabled | Out-Null
# Xbox, games
Get-Service XblAuthManager,XblGameSave,XboxNetApiSvc -ErrorAction SilentlyContinue | Stop-Service -PassThru | Set-Service -StartupType Disabled | Out-Null
Another nice side-effect is more free resources for other programs (especially on low-end machines or virtualization environments).
Web Browser
Windows comes with Internet Explorer and/or Edge as a default browser.
For many years, I’ve preferred Firefox, and continue to do so, because of its customization possibilities, privacy, and security options.
In particular (thanks to extensions)
-
Completely or partially disable javascript/malware/content (thanks to NoScript, yesscript, and uBlock Origin)
-
automatically removing cookies (thanks to Cookie AutoDelete)
-
remove trackers (without extension, but also thanks to the EFF)
-
HTTPS everywhere (thanks to the EFF)
-
user agents (can be done manually, or thanks to different extensions like User-Agent Switcher and Manager)
-
containers (thanks to Multi-Account Containers and Temporary Containers)
-
remove tracking elements from URLs (thanks to ClearURLs, also very useful when sharing or simply saving links)
-
Password manager integration (thanks to KeePassXC)
What’s especially important for me it’s that it permits blocking malware before it gets executed (because it is possible to control the execution and loading of javascript code and external resources). Good privacy tooling and flexibility are of course also important. But the browser is also cross-platform, which means I can use it on my desktop and my phone, with similar settings or extensions, without needing to learn different programs to do the same thing.
I have no exhaustive list of extensions, those listed are some of those I know and use, but like all other computer programs: it’s additional code I’m running on my machine.
It means they might increase the attack surface, and they could be malicious.
This is why I try to limit myself to those that increase the security and those I need.
While some people might argue that blocking javascript does make little sense as it breaks too many websites (it is only partially true, some websites work better with javascript disabled), I noticed that as of today no one claims that executing by default email attachments or automatically clicking on links is a good thing.
It is so obvious that we should not simply click on "foo.exe" attached to an email, especially if we do not know or fully trust who sent the mail. Actually, some corporations will disallow email attachments for security reasons.
But then, why do we execute all that stuff from random web pages? Also well-known webpages might do questionable things, like eBay scanning for the open ports on your computer.
Yet for every webpage we load, the default behavior is still to execute all the code it contains, and all the code linked on other sites, where the author of the website we are looking at has no control over it.
Email clients
The browser already does a lot of work and is probably the most targeted software, as users use it mainly to interact with unknown content and external resources.
This is one of the main reasons I prefer to avoid webmails and download emails offline.
Thunderbird is currently my main graphical mail manager of choice.
I recommend convert messages automatically to plain text 🗄️.
It might make some messages less "nice" to see, but it has some advantages. From a security perspective, I do not need to ask myself if there is some interactive content that might get triggered (there are other advantages, but not relevant to this article).
Also, for good disable the user agent 🗄️, as it does not provide any benefit and it only leaks metadata.
Alternate programs
Many types of attacks exploit particular programs, and the most used programs are also normally the most targeted. As many people do not change many default options, some of the most used programs are also those preinstalled on the system.
This is one more reason to prefer, for example, Firefox to Chrome, Edge, or Internet Explorer. Not only because it has different tools for privacy and security, but also because it is less likely to be targeted.
Another example is the pdf reader. Adobe Reader is the de facto default PDF reader (except those integrated into the browser) and provides a lot of features that most users do not need.
There are many lightweight alternatives, and while it is difficult to compare possible security issues, as the team behind Adobe Reader is probably much bigger than a team behind a smaller project, attacks leveraging some functionalities or default setting of Adobe Reader, or the reader integrated into the browser, might not apply to a third-party, less mainstream reader.
I’ve already listed a browser (Firefox) and a mail client (Thunderbird), other programs I use are
-
Sumatra PDF as pdf reader and eBook reader (also support
.xps
,.chm
and other formats) -
7-Zip for handling archives (
.zip
,.rar
,.7z
,.tar.gz
, and many others) -
LibreOffice as Office Suite (compatible with most Microsoft Office documents), even if I tend to prefer text documents (
.txt
) -
Notepad++ as text editor
Updates
If the machine is connected to the internet, security updates must be installed regularly, with no exceptions.
Not only for the operating systems, but also for all programs installed, or at least those that might interact with external files.
Unfortunately, Windows does not have a package manager. A program that manages all your installation, libraries, and even system configuration files.
Every program does or does not have its separate routine for controlling if there are updates. This means that normally, some of the installed programs will get updated, because there will be either ton of services looking for updates all the time, or the program itself will connect to the internet, even if normally it would not need to do so.
This approach has so many drawbacks and issues, that luckily different teams have tried to provide a solution.
As of today, there are tools for automating the installation and updating of software, even if those are not as simple, powerful, and flexible as the package managers from the GNU/Linux ecosystem.
Thanks to those programs, it is possible to disable most update checkers and use only one tool, which will reduce the usage of resources, and give the end-user a better overview of the system.
Unfortunately using an external package manager has its risks/downsides too, as we need to trust other people for gettings programs, instead of getting them from the author.
In the GNU/Linux ecosystem, this is normally not an issue, because if we cannot trust those providing the packages, then we can not trust the operating system either, as it is managed by the package manager too.
In Windows this is not the case, we are adding a middle-man between us, and the software we are going to install. If the package manager is open source, we can at least verify it is not doing anything harmful.
The real solution would be an integrated package manager in Windows, as we already trust Microsoft to some extent, as it develops the operating system, and thus already has access to every file. As pointed out in this ticket in the winget project, it seems that currently there are no plans on the Microsoft side to develop something similar.
Good or bad programs?
There is no clear distinction between a good or bad program, which is the reason why there is no silver bullet. Any program/concept can be used for good or bad.
rm
and del
can be used maliciously, better check what arguments are being passed into, but no one is going to extend them with some sort of blacklist or whitelist of files that can or cannot be deleted.
Encrypting documents is normally considered a feature of a program, a secure thing as it prevents other people from looking at them. But this is also what crypto locker does.
Office documents can contain macros. Those can be very useful, but can also interact with the system and send data.
In both cases, the difference between good and bad usage is the context and the input provided.
Who holds the key to decrypting the content? Who owns the files that are going to be deleted/changed? What files are going to be removed?
Generally speaking, it is best to let the system execute the least possible sensible amount of code. Especially unknown code and untrusted inputs.
AV
I dismissed them at the beginning, as they can become a target too (after all, it’s a piece of software like the others and the operating system).
Antiviruses, just like validators, are useful for verifying the integrity of files and eventually fixing them.
Even a corrupted non-malicious file can be used to attack a system.
For example, a malformed .jpg
file could block the antivirus, explorer.exe
, or another program that tries to parse it.
On Android setting an image as background can soft-brick the phone. In this case the image is even valid, but the program handling it is buggy. It is generally impossible for the system to avoid in advance all problematic files.
The same is true for what happened with the iphone and mac, where a piece of text could crash some programs, which might bring down the entire system.
So blocking executables and "script languages" inside other formats is not sufficient for having a "safe" system.
Backup
A backup is very helpful against those threats that try to destabilize the operating system or destroy user data but has little to no effect against threats that want to leak or steal something, such as private pictures or other confidential data.
Virtual Environments
On a computer, a program has normally access to nearly any resource.
Given the program foo.exe
, what does it do?
Without analyzing the program itself, or without executing it, it is hard, if possible to tell.
Will it access personal data or system files? Will it modify it? Will it send it over the wire?
And even if we know how a program behaves, if it is used by another program, it’s hard to predict if it can be used against us.
Simple tools like rm
and mv
are easy to understand, but how can we generally restrict them and leave them as functional as possible? Both can be used for deleting files. If the user wants it, fine, but what if not?
While containers, sandboxes, and virtual machines are not the answer to everything, they are tools for the end-user to limit the scope of programs and avoid incidental or accidental loss of data.
Conclusion
In practice, there are ways to recognize known (and through heuristic unknown) malware programs.
Unfortunately, most known approaches for Windows end-users do not try to minimize the chances of getting infected.
Most reasons are backward compatibility with previous versions.
Nevertheless as we, as humans and end-users, are not able to see and understand all components of our system playing together, we will inevitably do mistakes. Thus, minimizing proactively the chances of getting infected should be the highest priority from a security perspective.
Do you want to share your opinion? Or is there an error, some parts that are not clear enough?
You can contact me anytime.