Example #1
0
async def get_transforms_options_func():
    # reload the transform data so we can provide updated information
    try:
        import app.api.transforms.utils
        importlib.reload(sys.modules['app.api.transforms.utils'])
    except Exception as e:
        print(e)
    from app.api.transforms.utils import TransformOperation
    t = TransformOperation()
    method_list = {func: await get_type_hints(getattr(t, func).__annotations__) for func in dir(t) if
                   callable(getattr(t, func)) and not func.startswith("__")}
    return method_list
Example #2
0
async def perform_load_transforms(data, cb, operation, op):
    # in the end this returns a dict of status and either a final file path or an error message
    load_transforms = await get_transforms_func(
        cb.registered_payload.payload_type.ptype, "load")
    if load_transforms['status'] == "success":
        # if we need to do something like compile or put code in a specific format
        #   we should have a temp working directory for whatever needs to be done, similar to payload creation
        uuid = await generate_uuid()
        working_path = "./app/payloads/operations/{}/{}".format(
            operation.name, uuid)
        # copy the payload type's files there
        shutil.copytree(
            "./app/payloads/{}/payload/".format(
                cb.registered_payload.payload_type.ptype), working_path)
        # now that we copied files here, do the same replacement we do for creating a payload
        for base_file in glob.iglob(working_path + "/*", recursive=False):
            base = open(base_file, 'r')
            # write to the new file, then copy it over when we're done
            custom = open(working_path + "/" + uuid,
                          'w')  # make sure our temp file won't exist
            for line in base:
                if 'C2PROFILE_NAME_HERE' in line:
                    # optional directive to insert the name of the c2 profile
                    replaced_line = line.replace(
                        "C2PROFILE_NAME_HERE",
                        cb.registered_payload.c2_profile.name)
                    custom.write(replaced_line)
                elif 'UUID_HERE' in line:
                    replaced_line = line.replace("UUID_HERE", uuid)
                    custom.write(replaced_line)
                else:
                    custom.write(line)
            base.close()
            custom.close()
            os.remove(base_file)
            os.rename(working_path + "/" + uuid, base_file)
        # also copy over and handle the c2 profile files just in case they have header files or anything needed
        for file in glob.glob(r'./app/c2_profiles/{}/{}/{}/*'.format(
                cb.registered_payload.operation.name,
                cb.registered_payload.c2_profile.name,
                cb.registered_payload.payload_type.ptype)):
            # once we copy a file over, try to replace some c2 params in it
            try:
                base_c2 = open(file, 'r')
                base_c2_new = open(
                    working_path + "/{}".format(file.split("/")[-1]), 'w')
            except Exception as e:
                shutil.rmtree(working_path)
                return {'status': 'error', 'error': 'failed to open c2 code'}
            await write_c2(base_c2_new, base_c2, cb.registered_payload)
            base_c2.close()
            base_c2_new.close()
        transform_output = []
        # always start with a list of paths for all of the things we want to load
        # check if somebody submitted {'cmds':'shell,load, etc', 'file_id': 4} instead of list of commands
        try:
            replaced_params = data['params'].replace("'", '"')
            funcs = js.loads(replaced_params)['cmds']
        except Exception as e:
            funcs = data['params']
        data['params'] = funcs
        for p in data['params'].split(","):
            # register this command as one that we're going to have loaded into the callback
            try:
                command = await db_objects.get(
                    Command,
                    payload_type=cb.registered_payload.payload_type,
                    cmd=p)
                try:
                    loaded_command = await db_objects.get(LoadedCommands,
                                                          callback=cb,
                                                          command=command)
                    loaded_command.version = command.version
                    await db_objects.update(loaded_command)
                except Exception as e:
                    # we couldn't find it, so we need to create it since this is a new command, not an update
                    loaded_command = await db_objects.create(
                        LoadedCommands,
                        callback=cb,
                        command=command,
                        version=command.version,
                        operator=op)
            except Exception as e:
                print(e)
            transform_output.append("./app/payloads/{}/commands/{}".format(
                cb.registered_payload.payload_type.ptype, p.strip()))
        # if we actually have transforms to do, then reload the utils to make sure we're using the latest
        if len(load_transforms['transforms']) > 0:
            try:
                import app.api.transforms.utils
                importlib.reload(sys.modules['app.api.transforms.utils'])
            except Exception as e:
                print(e)
            from app.api.transforms.utils import TransformOperation
            transforms = TransformOperation(working_dir=working_path + "/")

        for t in load_transforms['transforms']:
            try:
                transform_output = await getattr(transforms, t['name'])(
                    cb.registered_payload, transform_output, t['parameter'])
            except Exception as e:
                print(e)
                shutil.rmtree(working_path)
                return {
                    'status':
                    'error',
                    'error':
                    'failed to apply transform {}, with message: {}'.format(
                        t['name'], str(e)),
                    'cmd':
                    data['command'],
                    'params':
                    data['params']
                }
        # at the end, we need to make sure our final file path is not located in our current working dir
        # if the user selected a file outside of it, that's fine, same with if they did something that got it there
        # if not, handle it for them here
        if working_path in transform_output:
            new_path = "./app/payloads/operations/{}/load-{}".format(
                operation.name, datetime.datetime.utcnow())
            shutil.copy(transform_output, new_path)
            transform_output = new_path
        # now that the file is in a good place, remove the working area
        shutil.rmtree(working_path)
        return {'status': 'success', 'path': transform_output}
    else:
        return {
            'status': 'error',
            'error': 'failed to get transforms for this payload type',
            'cmd': data['command'],
            'params': data['params']
        }
Example #3
0
async def write_payload(uuid, user):
    # for projects that need compiling, we should copy all of the necessary files to a temp location
    #  do our stamping and compiling, save off the one final file to the rightful destination
    #  then delete the temp files. They will be in a temp folder identified by the payload's UUID which should be unique
    try:
        query = await db_model.payload_query()
        payload = await db_objects.get(query, uuid=uuid)
        query = await db_model.operation_query()
        operation = await db_objects.get(query, name=user['current_operation'])
    except Exception as e:
        print(e)
        return {
            'status': 'error',
            'error': 'failed to get payload db object to write to disk'
        }
    try:
        if payload.payload_type.file_extension:
            extension = payload.payload_type.file_extension
        else:
            extension = ""
        working_path = "./app/payloads/operations/{}/{}".format(
            operation.name, payload.uuid)
        # copy the payload type's files there
        shutil.copytree(
            "./app/payloads/{}/payload/".format(payload.payload_type.ptype),
            working_path)
        # now we will work with the files from our temp directory
        # make sure the path and everything exists for where the final payload will go, create it if it doesn't exist
        payload_directory = os.path.dirname(payload.location)
        pathlib.Path(payload_directory).mkdir(parents=True, exist_ok=True)

        # wrappers won't necessarily have a c2 profile associated with them
        c2_path = './app/c2_profiles/{}/{}/{}/{}{}'.format(
            payload.operation.name, payload.c2_profile.name,
            payload.payload_type.ptype, payload.c2_profile.name, extension)
        try:
            base_c2 = open(c2_path, 'r')
        except Exception as e:
            # if the wrapper doesn't have a c2 profile, that's ok
            if payload.payload_type.wrapper:
                pass
            # if the normal profile doesn't though, that's an issue, raise the exception
            else:
                raise e

    except Exception as e:
        print(e)
        shutil.rmtree(working_path)
        return {
            'status': 'error',
            'error': 'failed to open all needed files. ' + str(e)
        }
    # if we didn't actually find C2PROFILEHERE in the main code, we are probably looking at a multi-file project
    #   in that case, keep track so that we can copy the file over to our temp directory, fill it out, and compile
    wrote_c2_inline = False
    # we will loop over all the files in the temp directory as we attempt to write out our information
    # this will help multi file projects as well as ones where maybe code and headers need to be in different files
    for base_file in glob.iglob(working_path + "/*", recursive=False):
        base = open(base_file, 'r')
        # write to the new file, then copy it over when we're done
        custom = open(working_path + "/" + payload.uuid,
                      'w')  # make sure our temp file won't exist
        for line in base:
            if "C2PROFILE_HERE" in line and base_c2:
                # this means we need to write out the c2 profile and all parameters here
                await write_c2(custom, base_c2, payload)
                wrote_c2_inline = True
            elif 'C2PROFILE_NAME_HERE' in line:
                # optional directive to insert the name of the c2 profile
                replaced_line = line.replace("C2PROFILE_NAME_HERE",
                                             payload.c2_profile.name)
                custom.write(replaced_line)
            elif 'UUID_HERE' in line:
                replaced_line = line.replace("UUID_HERE", uuid)
                custom.write(replaced_line)
            elif 'COMMANDS_HERE' in line:
                # go through all the commands and write them to the payload
                try:
                    query = await db_model.payloadcommand_query()
                    commands = await db_objects.execute(
                        query.where(PayloadCommand.payload == payload))
                    for command in commands:
                        # try to open up the corresponding command file
                        cmd_file = open(
                            './app/payloads/{}/commands/{}'.format(
                                payload.payload_type.ptype,
                                command.command.cmd), 'r')
                        # we will write everything from the beginning to COMMAND_ENDS_HERE
                        for cmdline in cmd_file:
                            if 'COMMAND_ENDS_HERE' not in cmdline:
                                custom.write(cmdline)
                            else:
                                break  # stop once we find 'COMMAND_ENDS_HERE'
                        cmd_file.close()
                except Exception as e:
                    print(e)
                    return {
                        'status':
                        'error',
                        'error':
                        'failed to get and write commands to payload on disk'
                    }
            elif 'COMMAND_COUNT_HERE' in line:
                count = await db_objects.count(PayloadCommand.select().where(
                    PayloadCommand.payload == payload))
                replaced_line = line.replace('COMMAND_COUNT_HERE', str(count))
                custom.write(replaced_line)
            elif 'COMMAND_STRING_LIST_HERE' in line:
                query = await db_model.payloadcommand_query()
                commands = await db_objects.execute(
                    query.where(PayloadCommand.payload == payload))
                cmdlist = ','.join(
                    [str('"' + cmd.command.cmd + '"') for cmd in commands])
                replaced_line = line.replace('COMMAND_STRING_LIST_HERE',
                                             cmdlist)
                custom.write(replaced_line)
            elif 'COMMAND_RAW_LIST_HERE' in line:
                query = await db_model.payloadcommand_query()
                commands = await db_objects.execute(
                    query.where(PayloadCommand.payload == payload))
                cmdlist = ','.join([cmd.command.cmd for cmd in commands])
                replaced_line = line.replace('COMMAND_RAW_LIST_HERE', cmdlist)
                custom.write(replaced_line)
            elif 'COMMAND_HEADERS_HERE' in line:
                # go through all the commands and write them to the payload
                try:
                    query = await db_model.payloadcommand_query()
                    commands = await db_objects.execute(
                        query.where(PayloadCommand.payload == payload))
                    for command in commands:
                        # try to open up the corresponding command file
                        cmd_file = open(
                            './app/payloads/{}/commands/{}'.format(
                                payload.payload_type.ptype,
                                command.command.cmd), 'r')
                        found_headers = False
                        for cmdline in cmd_file:
                            if found_headers:
                                custom.write(cmdline)
                            elif 'COMMAND_ENDS_HERE' in cmdline:
                                found_headers = True
                        #custom.write(cmd_file.read())
                        cmd_file.close()
                except Exception as e:
                    print(e)
                    return {
                        'status':
                        'error',
                        'error':
                        'failed to get and write commands to payload on disk'
                    }
            elif 'WRAPPEDPAYLOADHERE' in line and payload.payload_type.wrapper:
                # first we need to do the proper encoding, then we write it do the appropriate spot
                wrapped_payload = open(payload.wrapped_payload.location,
                                       'rb').read()
                # eventually give a choice of how to encode, for now though, always base64 encode
                #if payload.payload_type.wrapped_encoding_type == "base64":
                wrapped_payload = base64.b64encode(wrapped_payload).decode(
                    "UTF-8")
                replaced_line = line.replace("WRAPPEDPAYLOADHERE",
                                             str(wrapped_payload))
                custom.write(replaced_line)
            else:
                custom.write(line)
        base.close()
        custom.close()
        os.remove(base_file)
        os.rename(working_path + "/" + payload.uuid, base_file)
    try:
        base_c2.close()
    except Exception as e:
        print(e)
        pass
    custom.close()
    if not wrote_c2_inline:
        # we didn't write the c2 information into the main file, so it's in another file, copy it over and fill it out
        for file in glob.glob(r'./app/c2_profiles/{}/{}/{}/*'.format(
                payload.operation.name, payload.c2_profile.name,
                payload.payload_type.ptype)):
            # once we copy a file over, try to replace some c2 params in it
            try:
                base_c2 = open(file, 'r')
                base_c2_new = open(
                    working_path + "/{}".format(file.split("/")[-1]), 'w')
            except Exception as e:
                shutil.rmtree(working_path)
                return {'status': 'error', 'error': 'failed to open c2 code'}
            await write_c2(base_c2_new, base_c2, payload)
            base_c2.close()
            base_c2_new.close()

    # now that it's written to disk, we need to potentially do some compilation or extra transforms
    try:
        import app.api.transforms.utils
        importlib.reload(sys.modules['app.api.transforms.utils'])
    except Exception as e:
        print(e)
    from app.api.transforms.utils import TransformOperation
    transform = TransformOperation(working_dir=working_path)
    transform_request = await get_transforms_func(payload.payload_type.ptype,
                                                  "create")
    if transform_request['status'] == "success":
        transform_list = transform_request['transforms']
        # do step 0, prior_output = path of our newly written file
        transform_output = os.path.abspath(working_path) + "/"
        for t in transform_list:
            try:
                transform_output = await getattr(transform,
                                                 t['name'])(payload,
                                                            transform_output,
                                                            t['parameter'])
            except Exception as e:
                print(e)
                shutil.rmtree(working_path)
                return {
                    'status':
                    'error',
                    'error':
                    'failed to apply transform {}, with message: {}'.format(
                        t['name'], str(e))
                }
        try:
            if transform_output != payload.location:
                # this means we ended up with a final file in a location other than what we specified
                if transform_output == os.path.abspath(working_path) + "/":
                    transform_output += payload.payload_type.ptype + extension
                shutil.copy(transform_output, payload.location)
            shutil.rmtree(working_path)
            return {'status': 'success', 'path': payload.location}
        except Exception as e:
            return {'status': 'error', 'error': str(e)}
    try:
        shutil.copy(working_path + "/" + payload.uuid, payload.location)
        shutil.rmtree(working_path)
        return {'status': 'success', 'path': payload.location}
    except Exception as e:
        return {'status': 'error', 'error': str(e)}
Example #4
0
async def get_transforms_options_func():
    t = TransformOperation()
    method_list = {func: await get_type_hints(getattr(t, func).__annotations__) for func in dir(t) if
                   callable(getattr(t, func)) and not func.startswith("__")}
    return method_list