Investigating Off-Premise Wireless Behaviour (or, "I Know What You Connected To")

Published: 2017-02-21
Last Updated: 2017-02-21 22:57:43 UTC
by Rob VandenBrink (Version: 1)
7 comment(s)

Last week, I was working with a client on a web-filtering solution, using one of their organization's laptops.  We happened to notice the long-long-LONG list of SSIDs that were on this machine, may of them open SSIDs.  The host we were looking at had the default "dlink" and "linksys" SSIDs as auto-connect, so not a great situation.  Coincidentally, this was the same day Xavier posted his diary about collecting this same information (the ssid list) from live machines (https://isc.sans.edu/forums/diary/How+was+your+stay+at+the+Hotel+La+Playa/22069/).  It really seems like people still have a pathological need to connect up to free WiFi.

I got to thinking about how to collect this information in an Active Directory domain using PowerShell.  It's quite easy for Windows 10, but not so much for Windows 7 clients. For the "older environment" case, I ended up falling back to:
netsh wlan show profiles  to get the list of wireless profiles
netsh wlan show profiles name=PROFILENAME  to get the details for the profile "PROFILENAME"
Combine that up with psexec (because psexec *always* works - well, almost always), and some text manipulation, and you have the code below.
Yes, I do know that this could have been done by pulling everything out of the registry, but in this case perfect is the enemy of "done" - I had a few clients who wanted this done quickly, and this approach got it done in that "quickly" time frame.

The resulting script will list all wireless profiles across an AD domain.  I did have a "test connection" line in there, but enough organizations have ping disabled now that I took that out. 

How to use this information?  For most organizations, this is a chance to do some outreach, some end-user education about safer computing.  In most cases, this means that we recommend that they tether to their phone rather than connect to random free SSIDs.

In a more security conscious environment, say if it's a bank or if clearances are involved, what this can be used for is as a simple audit.  In higher security shops, it's more common to see Group Policy be used to say "only this short list of SSIDs are permitted", where the list is the organizations' "real" wireless networks, as well as (in some cases) a pre-configured cell phone "tethered" network.

As always, let us know how this code works out.  There are a few errors I'm still trying to suppress, and it can take quite a long time to run this, but the clients that I've used this with have gotten good use out of the information.


The code (recommend PowerShell 4.0 or better):
$nodenets = @()
$domainmembers = get-adcomputer -filter *
foreach ($node in $domainmembers) {
    $netlist = iex ("./psexec /accepteula \\"+$node.name +" netsh wlan show profiles") 2>./a | Select-String -Pattern ": "
    if(($netlist -like "*was not found*") -or ($netlist.length -eq 0)) { write-host "No Wireless on host " $node.name }
    else {
      write-host "Assessing Wireless on host " $node.name
      foreach ($net in $netlist) {
        [console]::write(".")
        $netprf = ($net -split(": "))[1]
        $cmd = "./psexec /accepteula \\"+$node.name +" netsh wlan show profiles name="+ "`'"+$netprf+"`'"
        $netparmlist = iex $cmd 2>./a
        $netparmlist2 = $netparmlist | select-string -pattern ": " | select-string -pattern "Applied" -NotMatch | select-string -pattern "Profile" -NotMatch
        $x = New-Object psobject
        $x | add-member -membertype NoteProperty -name "Node" -Value $node.name
        foreach($parm in $netparmlist2) {
          $t1 = $parm -split ": "
          $x | add-member –membertype NoteProperty –name ($t1[0].trim(" ")) –Value ($t1[1]) ;
          }
        $nodenets += $x
        }
      }
  }
$nodenets | select Node, Name, "Connection Mode", "SSID Name", Authentication, Cipher, "Security Key" | Out-GridView

(watch for updates over the next few days at https://github.com/robvandenbrink/opw )

 

The output (you could just as easily output to CSV for use in Excel):

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

Keywords:
7 comment(s)

Comments

[quote]Combine that up with psexec (because psexec *always* works - well, almost always)[/quote]

There is ABSOLUTELY no need for psexec here (and in MANY other cases too): just use NETSH.exe /R <remote_computer> WLAN Show Profiles
Thanks, when you're in a hurry sometimes you miss obvious things (or at least I do).
I'll post an update to https://github.com/robvandenbrink/opw (for "Off Premise Wireless") tonight or tomorrow.
I should also be able to nail down the errors in that "add-member" loop.
Not using psexec should speed this up considerably
[quote=comment#38997]Thanks, when you're in a hurry sometimes you miss obvious things (or at least I do).
...
Not using psexec should speed this up considerably[/quote]

If NETSH.exe hadn't the /R:<remote> switch I'd rather use WINRS.exe /R:<remote> (for standalone commands or conventional scripts) or (in the case here) PowerShell remoting instead of a 3rd party tool. Both are available on every Windows and use WINRM under the hood...
Actually "netsh -r " is fairly broken. The wlan and interface commands for starters don't work (interactive session shown below, credentials removed - same error if the command is fully specified):

C:\windows\system32>netsh -r 10.50.11.36
[10.50.11.36] netsh>wlan ?
The following command was not found: wlan ?.

Microsoft's current best advice is to use psexec.

Of course, if you're running the latest OS across the domain, you can use PowerShell:
[Windows.Networking.Connectivity.NetworkInformation]::GetConnectionProfiles()

Unfortunately, most larger orgs aren't running Windows 10 across all workstations (yet).
I have collected this information from Windows machines as well using COM.

import win32com.client
nlm = win32com.client.Dispatch('{DCB00C01-570F-4A9B-8D69-199FDBA5723B}')
nl = nlm.GetNetworks(3) # Get all networks
n = nl.Next(1)
while n[0]:
print n[0].GetName(), n[0].GetDescription(), n[0].GetCategory(), n[0].GetDomainType()
n = nl.Next(1)


In particular what I think is vital is the GetDomainType() call. I find many users do not understand the difference between Private and Public networks. Many users I have been responsible for think "Private" means they want the network to be private, and don't understand that selecting Private means it is supposed to already be private.
Just with the current code, apostrophe's in the network name cause issues (such as John Smith's Network)
Updating the $cmd line to use double quotes to enclose the network name should help.

$cmd = "./psexec /accepteula \\"+$node.name +" netsh wlan show profiles name="+ "`""+$netprf+"`""
Hi,

As this does allow people to track movements and be in pineapple heaven, cleaning out your open wifi lists is a good idea. To aid in this, I wrote this for windows:

https://github.com/secopsconsult/powershell

(Get-OpenwifiNetworks.ps1).

In addition, Mubix has also released this:

https://github.com/mubix/osx-wificleaner

Regards,

Tim

Diary Archives