async def export_command_list(request, user, ptype): if user['auth'] not in ['access_token', 'apitoken']: abort(status_code=403, message= "Cannot access via Cookies. Use CLI or access via JS in browser") payload_type = unquote_plus(ptype) try: query = await db_model.payloadtype_query() payload_ptype = await db_objects.get(query, ptype=payload_type) query = await db_model.operation_query() operation = await db_objects.get(query, name=user['current_operation']) except Exception as e: print(e) return json({ 'status': 'error', 'error': 'unable to find that payload type' }) cmdlist = [] try: payloadtype_json = payload_ptype.to_json() del payloadtype_json['id'] del payloadtype_json['operator'] del payloadtype_json['creation_time'] payloadtype_json['files'] = [] for file in glob.iglob( "./app/payloads/{}/payload/*".format(payload_type)): payload_file = open(file, 'rb') file_dict = { file.split("/")[-1]: base64.b64encode(payload_file.read()).decode('utf-8') } payloadtype_json['files'].append(file_dict) query = await db_model.command_query() commands = await db_objects.execute( query.where(Command.payload_type == payload_ptype)) for c in commands: cmd_json = c.to_json() del cmd_json['id'] del cmd_json['creation_time'] del cmd_json['operator'] del cmd_json['payload_type'] query = await db_model.commandparameters_query() params = await db_objects.execute( query.where(CommandParameters.command == c)) params_list = [] for p in params: p_json = p.to_json() del p_json['id'] del p_json['command'] del p_json['cmd'] del p_json['operator'] del p_json['payload_type'] params_list.append(p_json) cmd_json['parameters'] = params_list query = await db_model.attackcommand_query() attacks = await db_objects.execute( query.where(ATTACKCommand.command == c)) attack_list = [] for a in attacks: a_json = a.to_json() del a_json['command'] del a_json['command_id'] del a_json['id'] attack_list.append(a_json) cmd_json['attack'] = attack_list query = await db_model.artifacttemplate_query() artifacts = await db_objects.execute( query.where((ArtifactTemplate.command == c) & (ArtifactTemplate.deleted == False))) artifact_list = [] for a in artifacts: a_json = { "command_parameter": a.command_parameter.name if a.command_parameter else "null", "artifact": a.artifact.name, "artifact_string": a.artifact_string, "replace_string": a.replace_string } artifact_list.append(a_json) cmd_json['artifacts'] = artifact_list cmd_file = open( "./app/payloads/{}/commands/{}".format(payload_type, c.cmd), 'rb') cmd_json['file'] = base64.b64encode( cmd_file.read()).decode('utf-8') cmdlist.append(cmd_json) # get all the c2 profiles we can that match up with this payload type for the current operation query = await db_model.payloadtypec2profile_query() profiles = await db_objects.execute( query.where(PayloadTypeC2Profile.payload_type == payload_ptype)) profiles_dict = {} for p in profiles: files = [] for profile_file in glob.iglob("./app/c2_profiles/{}/{}/*".format( p.c2_profile.name, payload_type)): file_contents = open(profile_file, 'rb') file_dict = { profile_file.split("/")[-1]: base64.b64encode(file_contents.read()).decode('utf-8') } files.append(file_dict) profiles_dict[p.c2_profile.name] = files payloadtype_json['c2_profiles'] = profiles_dict # get all of the module load transformations query = await db_model.transform_query() load_transforms = await db_objects.execute( query.where((Transform.t_type == "load") & (Transform.payload_type == payload_ptype))) load_transforms_list = [] for lt in load_transforms: lt_json = lt.to_json() del lt_json['payload_type'] del lt_json['operator'] del lt_json['timestamp'] del lt_json['t_type'] del lt_json['id'] load_transforms_list.append(lt_json) payloadtype_json['load_transforms'] = load_transforms_list # get all of the payload creation transformations query = await db_model.transform_query() create_transforms = await db_objects.execute( query.where((Transform.t_type == "create") & (Transform.payload_type == payload_ptype))) create_transforms_list = [] for ct in create_transforms: ct_json = ct.to_json() del ct_json['payload_type'] del ct_json['operator'] del ct_json['timestamp'] del ct_json['t_type'] del ct_json['id'] create_transforms_list.append(ct_json) payloadtype_json['create_transforms'] = create_transforms_list except Exception as e: print(e) return json({ 'status': 'error', 'error': 'failed to get information for that payload type: ' + str(e) }) return json({"payload_types": [{**payloadtype_json, "commands": cmdlist}]})
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'}
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)}