Example #1
0
async def get_one_payload_info(request, uuid, user):
    try:
        payload = await db_objects.get(Payload, uuid=uuid)
    except Exception as e:
        print(e)
        return json({'status': 'error', 'error': 'failed to find payload'})
    if payload.operation.name in user['operations']:
        payloadcommands = await db_objects.execute(
            PayloadCommand.select().where(PayloadCommand.payload == payload))
        commands = [{
            "cmd": c.command.cmd,
            "version": c.version,
            "apfell_version": c.command.version
        } for c in payloadcommands]
        # now we need to get the c2 profile parameters as well
        c2_profile_params = await db_objects.execute(
            C2ProfileParametersInstance.select().where(
                C2ProfileParametersInstance.payload == payload))
        params = [p.to_json() for p in c2_profile_params]
        return json({
            'status': 'success',
            **payload.to_json(), "commands": commands,
            "c2_profile_parameters_instance": params
        })
    else:
        return json({
            'status':
            'error',
            'error':
            'you need to be part of the right operation to see this'
        })
Example #2
0
async def create_callback(request):
    data = request.json
    if 'user' not in data:
        return json({'status': 'error',
                     'error': 'User required'})
    if 'host' not in data:
        return json({'status': 'error',
                     'error': 'Host required'})
    if 'pid' not in data:
        return json({'status': 'error',
                     'error': 'PID required'})
    if 'ip' not in data:
        return json({'status': 'error',
                     'error': 'IP required'})
    if 'uuid' not in data:
        return json({'status': 'error',
                     'error': 'uuid required'})
    # Get the corresponding Payload object based on the uuid
    try:
        payload = await db_objects.get(Payload, uuid=data['uuid'])
        # now that we have a uuid and payload, we should check if there's a matching parent callback
        if payload.pcallback:
            pcallback = await db_objects.get(Callback, id=payload.pcallback)
        else:
            pcallback = None
    except Exception as e:
        print(e)
        return json({'status': 'error',
                     'error': 'Failed to find payload',
                     'msg': str(e)})
    try:
        cal = await db_objects.create(Callback, user=data['user'], host=data['host'], pid=data['pid'],
                                      ip=data['ip'], description=payload.tag, operator=payload.operator,
                                      registered_payload=payload, pcallback=pcallback, operation=payload.operation)
        if 'encryption_type' in data:
            cal.encryption_type = data['encryption_type']
        if 'decryption_key' in data:
            cal.decryption_key = data['decryption_key']
        if 'encryption_key' in data:
            cal.encryption_key = data['encryption_key']
        await db_objects.update(cal)
        payload_commands = await db_objects.execute(PayloadCommand.select().where(PayloadCommand.payload == payload))
        # now create a loaded command for each one since they are loaded by default
        for p in payload_commands:
            await db_objects.create(LoadedCommands, command=p.command, version=p.version, callback=cal, operator=payload.operator)
    except Exception as e:
        print(e)
        return json({'status': 'error',
                     'error': 'Failed to create callback',
                     'msg': str(e)})
    cal_json = cal.to_json()
    status = {'status': 'success'}
    return response.json({**status, **cal_json}, status=201)
Example #3
0
async def get_one_payload_info(request, uuid, user):
    try:
        payload = await db_objects.get(Payload, uuid=uuid)
    except Exception as e:
        print(e)
        return json({'status': 'error', 'error': 'failed to find payload'})
    if payload.operation.name in user['operations']:
        payloadcommands = await db_objects.execute(
            PayloadCommand.select().where(PayloadCommand.payload == payload))
        commands = [c.command.cmd for c in payloadcommands]
        return json({
            'status': 'success',
            **payload.to_json(), "commands": commands
        })
    else:
        return json({
            'status':
            'error',
            'error':
            'you need to be part of the right operation to see this'
        })
Example #4
0
async def create_callback_func(data):
    if 'user' not in data:
        return {'status': 'error', 'error': 'User required'}
    if 'host' not in data:
        return {'status': 'error', 'error': 'Host required'}
    if 'pid' not in data:
        return {'status': 'error', 'error': 'PID required'}
    if 'ip' not in data:
        return {'status': 'error', 'error': 'IP required'}
    if 'uuid' not in data:
        return {'status': 'error', 'error': 'uuid required'}
    # Get the corresponding Payload object based on the uuid
    try:
        payload = await db_objects.get(Payload, uuid=data['uuid'])
        pcallback = None
    except Exception as e:
        print(e)
        return {}
    try:
        cal = await db_objects.create(Callback, user=data['user'], host=data['host'], pid=data['pid'],
                                      ip=data['ip'], description=payload.tag, operator=payload.operator,
                                      registered_payload=payload, pcallback=pcallback, operation=payload.operation)
        if 'encryption_type' in data:
            cal.encryption_type = data['encryption_type']
        if 'decryption_key' in data:
            cal.decryption_key = data['decryption_key']
        if 'encryption_key' in data:
            cal.encryption_key = data['encryption_key']
        await db_objects.update(cal)
        payload_commands = await db_objects.execute(PayloadCommand.select().where(PayloadCommand.payload == payload))
        # now create a loaded command for each one since they are loaded by default
        for p in payload_commands:
            await db_objects.create(LoadedCommands, command=p.command, version=p.version, callback=cal, operator=payload.operator)
    except Exception as e:
        print(e)
        return {'status': 'error', 'error': 'Failed to create callback', 'msg': str(e)}
    cal_json = cal.to_json()
    status = {'status': 'success'}
    return {**status, **cal_json}
Example #5
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(str(sys.exc_info()[-1].tb_lineno) + " " + str(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.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(str(sys.exc_info()[-1].tb_lineno) + " " + str(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(str(sys.exc_info()[-1].tb_lineno) + " " + str(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(str(sys.exc_info()[-1].tb_lineno) + " " + str(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(str(sys.exc_info()[-1].tb_lineno) + " " + str(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.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()
    transform_request = await get_transforms_func(payload.payload_type.ptype,
                                                  "create")
    if transform_request['status'] == "success":
        transform_list = transform_request['transforms']
        # now we have a temporary location with everything we need
        # zip it all up and save it
        if not payload.payload_type.container_running:
            return {"status": "error", 'error': 'build container not running'}
        if payload.payload_type.last_heartbeat < datetime.utcnow() + timedelta(
                seconds=-30):
            query = await db_model.payloadtype_query()
            payload_type = await db_objects.get(
                query, ptype=payload.payload_type.ptype)
            payload_type.container_running = False
            await db_objects.update(payload_type)
            shutil.rmtree(working_path)
            return {
                "status":
                "error",
                'error':
                'build container not running, no heartbeat in over 30 seconds'
            }
        shutil.make_archive(
            "./app/payloads/operations/{}/{}".format(operation.name,
                                                     payload.uuid), 'zip',
            working_path)
        file_data = open(
            "./app/payloads/operations/{}/{}".format(
                operation.name, payload.uuid) + ".zip", 'rb').read()
        result = await send_pt_rabbitmq_message(
            payload.payload_type.ptype,
            "create_payload_with_code.{}".format(payload.uuid),
            base64.b64encode(
                js.dumps({
                    "zip": base64.b64encode(file_data).decode('utf-8'),
                    "transforms": transform_list,
                    "extension": payload.payload_type.file_extension
                }).encode()).decode('utf-8'))
        shutil.rmtree(working_path)
        os.remove("./app/payloads/operations/{}/{}".format(
            operation.name, payload.uuid) + ".zip")
        return {**result, "uuid": payload.uuid}
    else:
        return {'status': 'error', 'error': 'failed to query for transforms'}
Example #6
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 #7
0
async def create_payload(request, user):
    data = request.json
    data['operator'] = user['username']
    data['current_operation'] = user['current_operation']
    if 'payload' in data:
        try:
            operation = await db_objects.get(Operation,
                                             name=user['current_operation'])
            old_payload = await db_objects.get(Payload,
                                               uuid=data['payload'],
                                               operation=operation)
            db_commands = await db_objects.execute(
                PayloadCommand.select().where(
                    PayloadCommand.payload == old_payload))
            commands = [c.command.cmd for c in db_commands]
            data['payload_type'] = old_payload.payload_type.ptype
            data['c2_profile'] = old_payload.c2_profile.name
            data['commands'] = commands
            # we need to set the key-value pairs for the c2 profile parameters
            final_c2_params = {}
            c2_params = await db_objects.execute(
                C2ProfileParametersInstance.select().where(
                    C2ProfileParametersInstance.payload == old_payload))
            for param in c2_params:
                final_c2_params[param.c2_profile_parameters.name] = param.value
            data['c2_profile_parameters'] = final_c2_params
            if 'tag' not in data:
                data['tag'] = old_payload.tag
            if old_payload.payload_type.wrapper:
                data['wrapper'] = True
                data['wrapped_payload'] = old_payload.wrapped_payload
        except Exception as e:
            print(e)
            return json({
                'status': 'error',
                'error': 'failed to get old payload values'
            })
    if 'tag' not in data:
        if 'task' in data:
            if data['pcallback']:
                data['tag'] = user['username'] + " using " + data[
                    'command'] + " from callback " + data['pcallback']
            else:
                data['tag'] = user['username'] + " created using " + data[
                    'command']
        else:
            data['tag'] = data['payload_type'] + " payload created by " + user[
                'username']
    # first we need to register the payload
    rsp = await register_new_payload_func(data, user)
    if rsp['status'] == "success":
        # now that it's registered, write the file, if we fail out here then we need to delete the db object
        payload = await db_objects.get(Payload, uuid=rsp['uuid'])
        create_rsp = await write_payload(rsp['uuid'], user)
        if create_rsp['status'] == "success":
            # if this was a task, we need to now issue the task to use this payload
            if 'task' in data:
                task = {
                    'command':
                    data['command'],
                    'params':
                    data['params'] + " " + rsp['payload_type'] + " " +
                    rsp['uuid'],
                    'operator':
                    user['username']
                }
                task_status = await add_task_to_callback_func(
                    task, data['pcallback'], user)
                return json(task_status)
            else:
                return json({'status': 'success'})
        else:
            await db_objects.delete(payload, recursive=True)
            return json({'status': 'error', 'error': create_rsp['error']})
    else:
        print(rsp['error'])
        return json({'status': 'error', 'error': rsp['error']})
Example #8
0
async def write_payload(uuid, user):
    try:
        payload = await db_objects.get(Payload, uuid=uuid)
    except Exception as 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 = ""
        base = open('./app/payloads/{}/{}{}'.format(payload.payload_type.ptype,
                                                    payload.payload_type.ptype,
                                                    extension))
        payload_directory = os.path.dirname(payload.location)
        pathlib.Path(payload_directory).mkdir(parents=True, exist_ok=True)
        custom = open(payload.location, 'w')
        # wrappers won't necessarily have a c2 profile associated with them
        if not payload.payload_type.wrapper:
            base_c2 = open('./app/c2_profiles/{}/{}/{}/{}{}'.format(
                payload.operation.name, payload.c2_profile.name,
                payload.payload_type.ptype, payload.c2_profile.name,
                extension))

    except Exception as e:
        print(e)
        return {
            'status': 'error',
            'error': 'failed to open all needed files. ' + str(e)
        }
    for line in base:
        if "C2Profile" in line and not payload.payload_type.wrapper:
            # this means we need to write out the c2 profile and all parameters here
            await write_c2(custom, base_c2, payload)
        # this will eventually be write_ptype_params like above, but not yet
        elif 'XXXX' in line:
            replaced_line = line.replace("XXXX", uuid)
            custom.write(replaced_line)
        elif 'COMMAND DECLARATIONS AND IMPLEMENTATIONS' in line:
            # go through all the commands and write them to the payload
            try:
                commands = await db_objects.execute(
                    PayloadCommand.select().where(
                        PayloadCommand.payload == payload))
                for command in commands:
                    # try to open up the corresponding command file
                    cmd_file = open('./app/payloads/{}/{}'.format(
                        payload.payload_type.ptype, command.command.cmd))
                    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()
            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()
    if not payload.payload_type.wrapper:
        base_c2.close()
    custom.close()
    # now that it's written to disk, we need to potentially do some compilation or extra transforms
    transform = TransformOperation()
    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 = payload.location
        for t in transform_list:
            try:
                transform_output = await getattr(transform,
                                                 t['name'])(payload,
                                                            transform_output,
                                                            t['parameter'])
            except Exception as e:
                print(e)
                return {
                    'status':
                    'error',
                    'error':
                    'failed to apply transform {}, with message: {}'.format(
                        t['name'], str(e))
                }
        if transform_output != payload.location:
            # this means we ended up with a final file in a location other than what we specified
            print(transform_output)
        return {'status': 'success', 'path': transform_output}
    return {'status': 'success', 'path': payload.location}
Example #9
0
async def write_payload(uuid, user, data):
    # 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(str(sys.exc_info()[-1].tb_lineno) + " " + str(e))
        return {
            'status': 'error',
            'error': 'failed to get payload db object to write to disk'
        }
    try:
        working_path = "./app/payloads/operations/{}/{}".format(
            operation.name, payload.uuid)
        # copy the payload type's files there
        await local_copytree(
            "./app/payloads/{}/payload/".format(payload.payload_type.ptype),
            working_path)
        # now we will work with the files from our temp directory
    except Exception as e:
        print(str(sys.exc_info()[-1].tb_lineno) + " " + str(e))
        try:
            shutil.rmtree(working_path)
        except Exception as err:
            print(str(sys.exc_info()[-1].tb_lineno) + " " + str(err))
            pass
        return {
            'status': 'error',
            'error': 'failed to copy over all needed files. ' + str(e)
        }
    wrote_commands_inline = False
    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
    # this iterates over all payload files in the working path
    for base_file in glob.iglob(working_path + "/**", recursive=True):
        try:
            # print("base_file: " + base_file)
            # print("is folder: " + str(os.path.isdir(base_file)))
            if os.path.isdir(base_file):
                continue
            base = open(base_file, 'r')
            # print("payload file: " + base_file)
            # write to the new file, then copy it over when we're done
            custom = open(base_file + payload.uuid,
                          'w')  # make sure our temp file won't exist
            for line in base:
                # search for any of our payload_type-based pre-processing commands
                if "C2PROFILE_HERE" in line:
                    # this means we need to write out the c2 profile and all parameters here
                    try:
                        wrote_c2_inline = True
                        await write_c2_inline(custom, payload)
                    except Exception as e:
                        print(str(sys.exc_info()[-1].tb_lineno) + " " + str(e))
                        shutil.rmtree(working_path)
                        return {
                            'status':
                            'error',
                            'error':
                            'failed to get and write C2 profiles to payload on disk: '
                            + str(e)
                        }
                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
                    wrote_commands_inline = True
                    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
                            try:
                                cmd_file = open(
                                    './app/payloads/{}/commands/{}/{}.{}'.
                                    format(
                                        payload.payload_type.ptype,
                                        command.command.cmd,
                                        command.command.cmd,
                                        payload.payload_type.file_extension),
                                    '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(
                                    str(sys.exc_info()[-1].tb_lineno) + " " +
                                    str(e))
                                print("Failed to read command: " +
                                      command.command.cmd)
                                raise e  # stop, propagate out
                    except Exception as e:
                        print(str(sys.exc_info()[-1].tb_lineno) + " " + str(e))
                        shutil.rmtree(working_path)
                        return {
                            'status':
                            'error',
                            'error':
                            'failed to get and write commands to payload on disk: '
                            + str(e)
                        }
                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
                            try:
                                cmd_file = open(
                                    './app/payloads/{}/commands/{}/{}.{}'.
                                    format(
                                        payload.payload_type.ptype,
                                        command.command.cmd,
                                        command.command.cmd,
                                        payload.payload_type.file_extension),
                                    'r')
                                found_headers = False
                                for cmdline in cmd_file:
                                    if found_headers:
                                        custom.write(cmdline)
                                    elif 'COMMAND_ENDS_HERE' in cmdline:
                                        found_headers = True
                                cmd_file.close()
                            except Exception as e:
                                print(
                                    str(sys.exc_info()[-1].tb_lineno) + " " +
                                    str(e))
                                print("Failed to read command: " +
                                      command.command.cmd)
                                raise e
                    except Exception as e:
                        print(str(sys.exc_info()[-1].tb_lineno) + " " + str(e))
                        shutil.rmtree(working_path)
                        return {
                            'status':
                            'error',
                            'error':
                            'failed to get and write commands to payload on disk: '
                            + str(e)
                        }
                elif 'WRAPPED_PAYLOAD_HERE' 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("WRAPPED_PAYLOAD_HERE",
                                                 str(wrapped_payload))
                    custom.write(replaced_line)
                else:
                    custom.write(line)
            base.close()
            custom.close()
            os.remove(base_file)
            os.rename(base_file + payload.uuid, base_file)
        except Exception as e:
            # we likely got a binary file that can't be parsed like this, so move on
            custom.close()
            os.remove(base_file + payload.uuid)
            print(
                "Tried to read lines of a binary file, moving to the next file: "
                + str(e))
    try:
        custom.close()
    except Exception as e:
        pass
    # if we didn't write the commands anywhere, then it's needed in its current separate files, copy them over
    if not wrote_commands_inline:
        query = await db_model.payloadcommand_query()
        commands = await db_objects.execute(
            query.where(PayloadCommand.payload == payload))
        for command in commands:
            try:
                # copy the payload type's files there
                await local_copytree(
                    './app/payloads/{}/commands/{}'.format(
                        payload.payload_type.ptype, command.command.cmd),
                    working_path + "/{}".format(command.command.cmd))
            except Exception as e:
                print(str(sys.exc_info()[-1].tb_lineno) + " " + str(e))
                shutil.rmtree(working_path)
                return {
                    'status':
                    'error',
                    'error':
                    'failed to get and write commands to payload on disk: ' +
                    str(e)
                }
    if not wrote_c2_inline:
        # we didn't write c2 inline into the file, so we need to copy it over
        try:
            await write_c2(working_path, payload)
        except Exception as e:
            print(str(sys.exc_info()[-1].tb_lineno) + " " + str(e))
            shutil.rmtree(working_path)
            return {
                "status": "error",
                'error':
                'Failed to write c2 files to temporary folder: ' + str(e)
            }
    # transform_request = await get_transforms_func(payload.payload_type.ptype, "create")
    transform_request = await get_payload_transforms(payload)
    if transform_request['status'] == "success":
        transform_list = transform_request['transforms']
        # now we have a temporary location with everything we need
        # zip it all up and save it
        if not payload.payload_type.container_running:
            return {"status": "error", 'error': 'build container not running'}
        if payload.payload_type.last_heartbeat < datetime.utcnow() + timedelta(
                seconds=-30):
            query = await db_model.payloadtype_query()
            payload_type = await db_objects.get(
                query, ptype=payload.payload_type.ptype)
            payload_type.container_running = False
            await db_objects.update(payload_type)
            shutil.rmtree(working_path)
            return {
                "status":
                "error",
                'error':
                'build container not running, no heartbeat in over 30 seconds'
            }
        shutil.make_archive(
            "./app/payloads/operations/{}/{}".format(operation.name,
                                                     payload.uuid), 'zip',
            working_path)
        file_data = open(
            "./app/payloads/operations/{}/{}".format(
                operation.name, payload.uuid) + ".zip", 'rb').read()
        result = await send_pt_rabbitmq_message(
            payload.payload_type.ptype,
            "create_payload_with_code.{}".format(payload.uuid),
            base64.b64encode(
                js.dumps({
                    "zip": base64.b64encode(file_data).decode('utf-8'),
                    "transforms": transform_list,
                    "extension": payload.payload_type.file_extension
                }).encode()).decode('utf-8'), user['username'])
        shutil.rmtree(working_path)
        os.remove("./app/payloads/operations/{}/{}".format(
            operation.name, payload.uuid) + ".zip")
        return {**result, "uuid": payload.uuid}
    else:
        return {'status': 'error', 'error': 'failed to query for transforms'}