def _enable_demo(self, demo, is_enabled): if not is_enabled: self.timer.Stop() self.tshark.stop_capture() self.tshark = None self._polling_demo = None return if self.network: channel = self.network.channel else: channel = None # Put the interface into the correct mode. interface = self._get_interface() if (interface.monitor_mode and interface.monitor_mode_channel != channel): interface.disable_monitor_mode() self._interface_refresh() interface = self._get_interface() if demo.MONITOR_MODE: interface.enable_monitor_mode(channel) self._interface_refresh() elif not demo.MONITOR_MODE and interface.monitor_mode: interface.disable_monitor_mode() self._interface_refresh() # Start TShark with the demo parameters. self._polling_demo = demo interface = self._get_interface() interface_name = interface.monitor_mode or interface.name if demo.TSHARK_SUPPLY_PASSWORD: prefs = (demo.TSHARK_PREFERENCES + ['uat:80211_keys:\\"wpa-pwd\\",\\"%s:%s\\"' % (self.network.password, self.network.essid)]) else: prefs = demo.TSHARK_PREFERENCES self.tshark = TShark(interface=interface_name, fields=demo.TSHARK_FIELDS, separator=self.TSHARK_SEPARATOR, capture_filter=demo.TSHARK_CAPTURE_FILTER, read_filter=demo.TSHARK_READ_FILTER, preferences=prefs) self.tshark.start_capture() self.timer.Start(self.TSHARK_POLL_INTERVAL)
class WirelessDemoSet(): """A collection of wireless insecurity demos.""" # Class constants. DEMOS = (wireless_demos.AccessPointDemo(), wireless_demos.HttpBasicAuthSniffDemo(),) BORDER = 5 REFRESH_LABEL = "Refresh" DEAUTH_LABEL = "Force deauth using" NETWORK_INTERFACE_LABEL = "Network Interface" WIRELESS_NETWORK_LABEL = "Sniff..." MONITOR_MODE_LABEL_OFF = "Monitor mode is OFF." SELECT_NETWORK_LABEL = "Meta-data on all networks" TSHARK_SEPARATOR = '/t' TSHARK_POLL_INTERVAL = 500 def __init__(self, parent): self.current_demo = self.DEMOS[0] self._polling_demo = None self.timer = wx.Timer() self.timer.Bind(wx.EVT_TIMER, self._poll_tools) self.tshark = None self.interfaces = [] self.interface = None self.deauth_interface = None self.networks = [] self.network = None self.is_running = False self._init_control_panel(parent) self._init_data_panel(parent) def get_users(self): return self.data_grid.GetObjects() def initialize_data(self): self._interface_refresh() self._network_refresh() def merge_users(self, new_users): users_dict = {} users = self.get_users() for user in users: users_dict[user.mac] = user for new_user in new_users: user = users_dict.get(new_user.mac) if user: user.merge(new_user) else: users_dict[new_user.mac] = new_user self.data_grid.SetObjects(users_dict.values()) def destroy(self): for i in self.interfaces: i.disable_monitor_mode() def _poll_tools(self, event): while self.tshark: try: line = self.tshark.queue.get_nowait() except Empty: break line = line[:-1] # Remove newline. raw_fields = self.tshark.split_fields(line) fields = self._polling_demo.interpret_tshark_output(raw_fields) if fields: print fields new_user = wlan.User(**fields) # Access points aren't users. for network in self.networks: if new_user.mac == network.bssid: new_user = None break if not new_user: continue # Match the user's network's BSSID to a known ESSID. if (new_user.current_network and new_user.current_network.bssid and not new_user.current_network.essid): bssid = new_user.current_network.bssid for network in self.networks: if network.bssid == bssid: new_user.current_network.essid = network.essid break for user in self.get_users(): if user.mac == new_user.mac: old_user = user break else: old_user = None if old_user: old_user.merge(new_user) self.data_grid.RefreshObject(old_user) else: self.data_grid.AddObject(new_user) def enable_demo(self, is_enabled): # Update the UI before blocking operations begin. self.deauth_button.Enable(is_enabled and self.current_demo != self.DEMOS[0] and self.interface is not None) self._enable_interface_panel(not is_enabled) for user in self.get_users(): user.sniffable = False user.eapol_flags = 0 self.data_grid.RepopulateList() # Call subprocesses that might block. wx.CallAfter(self._enable_demo, self.current_demo, is_enabled) self.is_running = is_enabled return is_enabled def _enable_demo(self, demo, is_enabled): if not is_enabled: self.timer.Stop() self.tshark.stop_capture() self.tshark = None self._polling_demo = None return if self.network: channel = self.network.channel else: channel = None # Put the interface into the correct mode. interface = self._get_interface() if (interface.monitor_mode and interface.monitor_mode_channel != channel): interface.disable_monitor_mode() self._interface_refresh() interface = self._get_interface() if demo.MONITOR_MODE: interface.enable_monitor_mode(channel) self._interface_refresh() elif not demo.MONITOR_MODE and interface.monitor_mode: interface.disable_monitor_mode() self._interface_refresh() # Start TShark with the demo parameters. self._polling_demo = demo interface = self._get_interface() interface_name = interface.monitor_mode or interface.name if demo.TSHARK_SUPPLY_PASSWORD: prefs = (demo.TSHARK_PREFERENCES + ['uat:80211_keys:\\"wpa-pwd\\",\\"%s:%s\\"' % (self.network.password, self.network.essid)]) else: prefs = demo.TSHARK_PREFERENCES self.tshark = TShark(interface=interface_name, fields=demo.TSHARK_FIELDS, separator=self.TSHARK_SEPARATOR, capture_filter=demo.TSHARK_CAPTURE_FILTER, read_filter=demo.TSHARK_READ_FILTER, preferences=prefs) self.tshark.start_capture() self.timer.Start(self.TSHARK_POLL_INTERVAL) def _enable_interface_panel(self, is_enabled): for control in (self.monitor_mode_label, self.interface_choice, self.interface_refresh_button): control.Enable(is_enabled) def _get_interface(self): name = self.interface_choice.GetStringSelection() for i in self.interfaces: if i.name == name: return i return None def _init_control_panel(self, parent): self.control_panel = wx.Panel(parent, -1) # Network interface selection. self.interface_choice = wx.Choice(self.control_panel, -1, size=wx.Size(100, -1), choices=[]) self.interface_choice.Bind(wx.EVT_CHOICE, self._interface_selected) self.interface_refresh_button = wx.Button(self.control_panel, label=self.REFRESH_LABEL) self.interface_refresh_button.Bind(wx.EVT_BUTTON, self._interface_refresh) self.monitor_mode_label = wx.StaticText(self.control_panel, -1, self.MONITOR_MODE_LABEL_OFF) # Wireless network selection. self.network_choice = wx.combo.BitmapComboBox(self.control_panel, -1, size=(300,-1), style=wx.CB_READONLY, choices=[]) self.network_choice.Bind(wx.EVT_COMBOBOX, self._network_selected) self.network_refresh_button = wx.Button(self.control_panel, label=self.REFRESH_LABEL) self.network_refresh_button.Bind(wx.EVT_BUTTON, self._network_refresh) self.deauth_button = wx.Button(self.control_panel, label=self.DEAUTH_LABEL) self.deauth_button.Bind(wx.EVT_BUTTON, self._force_deauth) self.deauth_button.Enable(False) self.deauth_interface_choice = wx.Choice(self.control_panel, -1, size=wx.Size(100, -1), choices=[]) self.deauth_interface_choice.Bind(wx.EVT_CHOICE, self._deauth_interface_selected) # Layout. sizer = wx.BoxSizer(wx.HORIZONTAL) flags = wx.ALL | wx.ALIGN_CENTER_VERTICAL self.interface_box = wx.StaticBox(self.control_panel, -1, self.NETWORK_INTERFACE_LABEL) interface_sizer = wx.StaticBoxSizer(self.interface_box, wx.HORIZONTAL) interface_sizer.Add(self.monitor_mode_label, flag=flags, border=self.BORDER) interface_sizer.Add(self.interface_choice, flag=flags, border=self.BORDER) interface_sizer.Add(self.interface_refresh_button, flag=flags, border=self.BORDER) sizer.Add(interface_sizer, flag=flags, border=self.BORDER) self.network_box = wx.StaticBox(self.control_panel, -1, self.WIRELESS_NETWORK_LABEL) network_sizer = wx.StaticBoxSizer(self.network_box, wx.HORIZONTAL) network_sizer.Add(self.network_choice, flag=flags, border=self.BORDER) network_sizer.Add(self.network_refresh_button, flag=flags, border=self.BORDER) network_sizer.Add(self.deauth_button, flag=(wx.ALIGN_CENTER_VERTICAL | wx.TOP | wx.BOTTOM | wx.LEFT), border=self.BORDER) network_sizer.Add(self.deauth_interface_choice, flag=(wx.ALIGN_CENTER_VERTICAL | wx.TOP | wx.BOTTOM | wx.RIGHT), border=self.BORDER) sizer.Add(network_sizer, flag=flags, border=self.BORDER) self.control_panel.SetSizer(sizer) def _init_data_panel(self, parent): self.data_panel = wx.Panel(parent, -1, style=0) self.data_grid = olv.ObjectListView(self.data_panel, wx.ID_ANY, size=(-1,600), style=(wx.LC_REPORT | wx.LC_VRULES | wx.SUNKEN_BORDER)) self.data_grid.AddNamedImages("locked", wx.Bitmap(IMAGE_LOCKED)) self.data_grid.AddNamedImages("unlocked", wx.Bitmap(IMAGE_UNLOCKED)) sniffable_column = olv.ColumnDefn(title="?", fixedWidth=40, align="left", isEditable=False, imageGetter=locked_getter) creds_column = olv.ColumnDefn("Credentials", "left", 175, valueGetter="credentials_to_string", isEditable=False, minimumWidth=175, isSpaceFilling=True, checkStateGetter="anonymous_creds") networks_column = olv.ColumnDefn("Previous Wifi Networks", "left", 175, valueGetter="aps_to_string", isEditable=False, minimumWidth=175, isSpaceFilling=True, checkStateGetter="anonymous_aps") value_getter = "current_network_to_string" self.current_network_column = olv.ColumnDefn(title="Last Wifi Network", align="left", width=175, valueGetter=value_getter, isEditable=False) cols = [sniffable_column, olv.ColumnDefn("MAC Address", "left", 175, "mac", isEditable=False), olv.ColumnDefn("Nickname", "left", 175, valueGetter="nickname_to_string", valueSetter="nickname_from_string"), olv.ColumnDefn("Wifi Chipset", "left", 175, "hardware", isEditable=False), olv.ColumnDefn("IP Address", "left", 175, "ip", isEditable=False), olv.ColumnDefn("Hostname", "left", 175, "hostname", isEditable=False), self.current_network_column, creds_column, networks_column] self.sniffable_column_index = cols.index(sniffable_column) self.credentials_column_index = cols.index(creds_column) self.networks_column_index = cols.index(networks_column) self.data_grid.SetColumns(cols) self.data_grid.SetEmptyListMsg("Start a demo or use \"File > Import\"" " to populate this list.") self.data_grid.cellEditMode = olv.ObjectListView.CELLEDIT_DOUBLECLICK font = wx.Font(pointSize=11, family=wx.FONTFAMILY_MODERN, style=wx.FONTSTYLE_NORMAL, weight=wx.FONTWEIGHT_NORMAL, underline=False, face="", encoding=wx.FONTENCODING_DEFAULT) self.data_grid.SetFont(font) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(self.data_grid, 1, wx.ALL|wx.EXPAND, self.BORDER) self.data_panel.SetSizer(sizer) self.data_grid.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self._item_activated) self.data_grid.Bind(olv.EVT_SORT, self._column_sort) # Sort by number of elements, not string representation of list. def _column_sort(self, event): if event.sortColumnIndex in (self.credentials_column_index, self.networks_column_index,): self.data_grid.SortListItemsBy(length_sorter, event.sortAscending) event.wasHandled = True elif event.sortColumnIndex == self.sniffable_column_index: self.data_grid.SortListItemsBy(sniffable_sorter, event.sortAscending) def _item_activated(self, event): user = self.data_grid.GetSelectedObject() if user: user_frame = UserFrame(self.data_panel, -1, user=user) user_frame.Bind(EVT_USER_MODIFIED, self._user_modified) user_frame.Show() def _user_modified(self, event): self.data_grid.RefreshObject(event.user) def _interface_refresh(self, event=None): new_interfaces = wlan.enumerate_interfaces() # Retain knowledge of which interfaces are in monitor # mode. This is needed because airmon-ng only reports the # monitor mode name of an inteface in the results of putting # that interface into monitor mode, but not when listing all # interfaces in general. The assumption here is that no # external program or action will change the monitor mode # state of an interface. for new in new_interfaces: for old in self.interfaces: if new.name == old.name: new.monitor_mode = old.monitor_mode new.monitor_mode_channel = old.monitor_mode_channel # Don't list monitoring interfaces as separate interfaces. for i in new_interfaces: name = i.name for j in new_interfaces: if name == j.monitor_mode: new_interfaces.remove(i) # Also, don't list anything that even looks like a monitoring # interface. Whether an interface is actually in monitor mode # could be better verified using something like iwconfig. for i in new_interfaces: if i.name.startswith('mon'): new_interfaces.remove(i) self.interfaces = new_interfaces # Construct a list of the new interface names, taking care to # track changes in monitor mode. interface_names = [] for i in self.interfaces: interface_names.append(i.name) self.interface_choice.SetItems(interface_names) self.deauth_interface_choice.SetItems(interface_names) if self.interface and self.interface.name in interface_names: self.interface_choice.SetStringSelection(self.interface.name) else: self.interface_choice.SetSelection(0) if (self.deauth_interface and self.deauth_interface.name in interface_names): self.deauth_interface_choice.SetStringSelection( self.deauth_interface.name) else: self.deauth_interface_choice.SetSelection(0) self._interface_selected() self._deauth_interface_selected() def _interface_selected(self, event=None): # Show the user the state of monitor mode. self.interface = self._get_interface() if self.interface and self.interface.monitor_mode: label = "Monitoring as %s." % self.interface.monitor_mode else: label = self.MONITOR_MODE_LABEL_OFF self.monitor_mode_label.SetLabel(label) def _deauth_interface_selected(self, event=None): name = self.deauth_interface_choice.GetStringSelection() for i in self.interfaces: if i.name == name: self.deauth_interface = i break else: self.deauth_interface = None def _filter_by_network(self, network): if network: f = olv.Filter.TextSearch(self.data_grid, columns=(self.current_network_column,), text=network.essid) else: f = None self.data_grid.SetFilter(f) self.data_grid.RepopulateList() def _network_selected(self, event): # Ask the user for a new password for the selected network. old_network = self.network network = event.GetClientObject() if self._network_password_input(network): self.network = network else: if self.network: self.network_choice.SetStringSelection(str(self.network)) else: self.network_choice.SetSelection(0) return # Update the padlock associated with the selected network. if self.network: i = event.GetSelection() if self.network.password: self.network_choice.SetItemBitmap(i, wx.Bitmap(IMAGE_UNLOCKED)) else: self.network_choice.SetItemBitmap(i, wx.Bitmap(IMAGE_LOCKED)) # Restart the appropriate demo on the new network. if self.network != old_network: self._filter_by_network(self.network) if self.network: new_demo = self.DEMOS[1] else: new_demo = self.DEMOS[0] if self.is_running: self.enable_demo(False) self.current_demo = new_demo self.enable_demo(True) else: self.current_demo = new_demo def _network_refresh(self, event=None): interface = self.interface_choice.GetStringSelection() if not interface: self.network_choice.SetItems([]) else: current_index = self.network_choice.GetSelection() current_network = self.network_choice.GetClientData(current_index) old_networks = self.networks self.networks = wlan.enumerate_networks(interface) for n in self.networks: # Show only WPA and open networks. if not all(['WPA' in s for s in n.security]): self.networks.remove(n) continue # Retain previous information, like password. for old in old_networks: if old == n: n.merge(old) self.network_choice.SetItems([]) if self.networks: self.network_choice.Append(self.SELECT_NETWORK_LABEL, clientData=None) for n in self.networks: if n.password: icon = wx.Bitmap(IMAGE_UNLOCKED) else: icon = wx.Bitmap(IMAGE_LOCKED) self.network_choice.Append(str(n), icon, n) if current_network in self.networks: self.network_choice.SetStringSelection(str(current_network)) else: self.network_choice.SetSelection(0) self._filter_by_network(self.network) def _network_password_input(self, network): if network is None: return True dialog = wx.PasswordEntryDialog(self.control_panel, message = "Enter a password for the" "\"%s\" network." % network.essid, caption = "Network Password", value = network.password or '') status = dialog.ShowModal() if status == wx.ID_OK: password = dialog.GetValue() if password == '': password = None network.password = password dialog.Destroy() return status == wx.ID_OK def _force_deauth(self, event): leave_in_monitor_mode = self.deauth_interface.monitor_mode self.deauth_interface.enable_monitor_mode(self.network.channel) bssid = self.network.bssid interface = self.deauth_interface.monitor_mode for user in self.get_users(): if (user.current_network == self.network and not user.sniffable): if not wlan.force_deauthentication(bssid, user.mac, interface): # If it doesn't work the first time, it's probably # because the interface isn't done being put into # monitor mode, so sleep for a while and try one # more time. See issue #74. time.sleep(3) wlan.force_deauthentication(bssid, user.mac, interface) if not leave_in_monitor_mode: self.deauth_interface.disable_monitor_mode()