Threat Level: green Handler on Duty: Rob VandenBrink

SANS ISC: Powershell, Active Directory and the Windows Host Firewall - SANS Internet Storm Center SANS ISC InfoSec Forums


Sign Up for Free!   Forgot Password?
Log In or Sign Up for Free!
Powershell, Active Directory and the Windows Host Firewall

When Windows XP was released in late 2001, one of the new features that everyone thought was outstanding was the workstation firewall.  This feature was going to save us all, blocking attacks and malware on known and easily exploitable ports such as those used by AD - surely we could quantify our own domains and block any and all traffic from non-domain stations?  Or block attack traffic from our AD neighbours?

Sadly, it's now 2019 (just over 17 years later), and it's depressing for us in the security industry to see that firewalls are routinely disabled domain-wide in most Windows shops by the folks who admin those domains.

Why is this so terrible?  For starters, the most common windows malware these days propagates over port tcp/445 (used for SMB, which is used extensively in AD, among other protocols), and in most shops there's no good reason for one workstation to have the capability to connect to another workstation on tcp/445.  Really, that traffic is almost always confined to client <-> server communications.  In most environments, there is no client to client workstation communication requirements at all - sometimes we'll see that soft-phones will need ports open for VOIP, but that's about it.  For a "tcp/445 inbound to workstations" rule specifically, you likely only want to permit Domain Controllers, and then also maybe the management hosts that you'll be running scripts from to audit / maintain your workstations.

So, should we start by blocking tcp/445 from workstation subnets?  No, that's very much missing the point. For a workstation firewall, permit the client to server traffic that you need on the outbound rule, as well as any server to client traffic that is needed on the inbound rule, look at what you need for internet (keep reading) and anything else, then block all other traffic.

What, no "any/any" to the internet?  Sure, you could go there, but you likely only need a handful of ports outbound (and NONE inbound) for internet traffic for most stations - more and more we're seeing just http and https, with protocols like ssh, ftps, sftp to a handful of known destinations.  DNS requests should only be permitted to your DNS servers (where you can log them and sink-hole requests to known malicious sites).   Many environments should be blocking internet-bound cleartext protocols like FTP, but just plain don't.  You *could* do a "permit all" to the internet, then trust the firewall egress filter, but that approach won't help you when that mobile workstation leaves the office at the end of the work day, if it was ever there.

What the firewall egress filter will buy you however is more "mature" logging and reporting.   You can (and should) centrally log your workstation firewall traffic hits and stats, but Windows logging is so verbose, and SEIM solutions don't tend to do a great job on workstation firewalls.  You may want an "at work" policy that allows anything outbound to the internet from the workstation firewall, after all the internal rules are processed, so that permitted and blocked traffic gets logged and reported at the perimeter firewall.  Just be sure that the "internet" rule for the "Public" and "Home" network profiles reflect what's in your firewall's egress filter (or are more restrictive), and are maintained to stay that way - you don't want that outbound/any/any to still be in play if a workstation leaves the office!

If there is any question about if one port or another is being used inbound or outbound, WireShark is your friend.  It's fairly simple to set up a capture session looking just for the port in question (a capture filter of "tcp port 445" for instance will only capture that port). 

How can you set your status network-wide?  Group Policy has this dialed in!  You'll likely have many of the server firewall policies set individually, but workstations can normally be configured globally in a GPO, once you've got  your policy tested.  Do keep in mind though that you can easily lobotomize a domain with GPO's - you'll want to test your policies on a small but representative group of stations, then roll the GPO to a series of pilot groups before you include all workstations.

Normally you'll have one set of rules for workstations when they are "at work", then a much more restrictive "away" set of rules, usually when not at work the workstation firewall should deny all unsolicited inbound traffic for instance.

How can you check your server and workstation firewall status?  The PowerShell script below will list out the firewall status (not the individual rules) for each host in AD - the saved file can then be read into Excel (or whatever) to process for any further action:

$pcs = get-adcomputer -filter * -property Name,OperatingSystem,Operatingsystemversion,IPV4Address
$fwinfo = @()
$i=0
foreach ($pc in $pcs) {
    $i+=1
    write-host $i
    $tempval = new-object psobject
    if (Test-Connection -ComputerName $pc.DNSHostName -count 2 -Quiet) {
    $tempval = Get-NetFirewallProfile -cimsession $pc.DNSHostName -PolicyStore activestore | select name, enabled, defaultinboundaction, DefaultOutboundAction
    if ($tempval.count -gt 0) {
        $tempval | add-member -membertype noteproperty -name HostName -value $pc.dnshostname
        $tempval | add-member -membertype noteproperty -name OperatingSystem -value $pc.OperatingSystem
        $tempval | add-member -membertype noteproperty -name IpAddress -value $pc.IPV4Address
        $fwinfo += $tempval
    }
}
}
$fwinfo | export-csv -path ./fwstate.csv

This gets us the state, but what about the rules, as well as the ports and protocols associated with the rules?  For a local workstation, the code below will get you that information.  Note though  that modern firewall rules are way more than just ports and protocols - many (if nto most) rules are application based, allowing those ports and protocols to or from specific applications only.

$pfrules = @()
$rules =  get-netfirewallrule
foreach ( $rule in $rules ) {
  $pf = $rule | get-netfirewallportfilter
  $tempval = new-object psobject
  $tempval = $rule | select displayname, description, enabled, profile, direction, action, policystoresource, policystoresourcetype
  $tempval | add-member -membertype noteproperty -name Protocol -value $pf.protocol
  $tempval | add-member -membertype noteproperty -name LocalPort -value $pf.LocalPort
  $tempval | add-member -membertype noteproperty -name RemotePort -value $pf.RemotePort
  $tempval | add-member -membertype noteproperty -name ICMPType -value $pf.ICMPType
  $tempval | add-member -membertype noteproperty -name DynamicTarget -value $pf.DynamicTarget
  $pfrules += $tempval
}

For a typical host, that'll give you a rule count in the high 300's, so this will add up if you enumerate domain-wide.  However, it's worth doing to find outliers.  Looking for protocol rules that are inbound TCP and active for instance cuts the count down quite a bit:

$tcpin = $pfrules | where { $_.Direction -eq 'Inbound' -and $_.Enabled -eq 'True' -and $_.Protocol -eq 'TCP' }
$tcpin.count
29

Even that is a lot to look at, especially if you are enumerating groups of hosts or the entire domain - again, Excel is DEFINITELY your friend for this excercise.  


Expanding our original collection script to include packet filter rules domain wide would look like this:

$pcs = get-adcomputer -filter * -property Name,OperatingSystem,Operatingsystemversion,IPV4Address
$pfrules = @()
$i=0
foreach ($pc in $pcs) {
    $i+=1
    write-host $i
    $tempval = new-object psobject
    if (Test-Connection -ComputerName $pc.DNSHostName -count 2 -Quiet) {
    $fwrules = Get-NetFirewallRule -cimsession $pc.DNSHostName -PolicyStore activestore
    foreach ( $rule in $fwrules ) {
        $pf = $rule | get-netfirewallportfilter
        $tempval = new-object psobject
        $tempval = $rule | select displayname, description, enabled, profile, direction, action, policystoresource, policystoresourcetype
        $tempval | add-member -membertype noteproperty -name Protocol -value $pf.protocol
        $tempval | add-member -membertype noteproperty -name LocalPort -value $pf.LocalPort
        $tempval | add-member -membertype noteproperty -name RemotePort -value $pf.RemotePort
        $tempval | add-member -membertype noteproperty -name ICMPType -value $pf.ICMPType
        $tempval | add-member -membertype noteproperty -name DynamicTarget -value $pf.DynamicTarget
        $tempval | add-member -membertype noteproperty -name HostName -value $pc.dnshostname
        $tempval | add-member -membertype noteproperty -name OperatingSystem -value $pc.OperatingSystem
        $tempval | add-member -membertype noteproperty -name IpAddress -value $pc.IPV4Address
        $pfrules += $tempval
        }
    }
}
$pfrules | export-csv -path ./fw-packetfilterrules.csv

 

So, the next time you have a conversation when they say that "it must have been targeted malware" or "it was a nation-state class attack" when they are ransomwared, take a peek at their GPO's - see if they had their workstation and servers firewalls enabled, let alone configured!  Run a quick audit of what's actually on their workstations and servers, especially the settings for laptops when they are off-premise.

Have you been involved in an incident where host firewalls (Windows or otherwise) have truly saved the day?  Or have you been in one that was a true trip to h-e-double-hockey-sticks, and proper host firewalls would have maybe prevented that trip?  Please, share using our comment form below!

===============
Rob VandenBrink
Compugen

Rob VandenBrink

489 Posts
ISC Handler
Brilliant tool for those CIS20 assessments. Thanks!
Anonymous
As mentioned, many firewall rules are scoped to a particular application or service. I've found you can use the Get-NetFirewallApplicationFilter and Get-NetFirewallServiceFilter cmdlets to add this information. The only thing I haven't figured out yet is for Windows Store Apps the Get-NetFirewallApplicationFilter returns a 'package' field with the app's SID and I'm not sure how to turn that into the name of the actual app.
Anonymous

Sign Up for Free or Log In to start participating in the conversation!