async def remove_command_parameter(request, user, cid, pid): 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") try: query = await db_model.command_query() command = await db_objects.get(query, id=cid) query = await db_model.commandparameters_query() parameter = await db_objects.get(query, id=pid, command=command) except Exception as e: print(e) return json({ 'status': 'error', 'error': 'failed to find command or parameter' }) p_json = parameter.to_json() await db_objects.delete(parameter) # update the command since we just updated a parameter to it async with db_objects.atomic(): query = await db_model.command_query() command = await db_objects.get(query, id=cid) command.version = command.version + 1 await db_objects.update(command) return json({ 'status': 'success', **p_json, 'new_cmd_version': command.version })
async def create_command_parameter(request, user, id): try: operator = await db_objects.get(Operator, username=user['username']) command = await db_objects.get(Command, id=id) except Exception as e: return json({'status': 'error', 'error': 'failed to find command'}) data = request.json if "name" not in data: return json({'status': 'error', 'error': '"name" is required'}) if 'type' not in data: return json({'status': 'error', 'error': '"type" is a required parameter'}) if 'required' not in data: return json({'status': 'error', 'error': '"required" is a required parameter'}) if data['type'] == "String" and 'hint' not in data: return json({'status': 'error', 'error': "\"hint\" required if type is \"String\""}) if data['type'] == "Choice" and 'choices' not in data: return json({'status': 'error', 'error': "\"choices\" is required if type is \"Choice\""}) if data['type'] == "ChoiceMultiple" and 'choices' not in data: return json({'status': 'error', 'error': "\"choices\" is required if type is \"ChoiceMultiple\""}) if 'hint' not in data: data['hint'] = "" try: param, created = await db_objects.get_or_create(CommandParameters, **data, command=command, operator=operator) async with db_objects.atomic(): command = await db_objects.get(Command, id=id) command.version = command.version + 1 await db_objects.update(command) print("created command param") return json({'status': 'success', **param.to_json(), 'new_cmd_version': command.version}) except Exception as e: print(e) return json({'status': 'error', 'error': 'failed to create parameter' + str(e)})
async def download_file_to_disk_func(data): # upload content blobs to be associated with filemeta id if 'chunk_num' not in data: return {'status': 'error', 'error': 'missing chunk_num'} if 'chunk_data' not in data: return {'status': 'error', 'error': 'missing chunk data'} try: query = await db_model.filemeta_query() file_meta = await db_objects.get(query, agent_file_id=data['file_id']) except Exception as e: print(e) return {'status': 'error', 'error': 'failed to get File info'} try: # print("trying to base64 decode chunk_data") if data['chunk_num'] <= file_meta.chunks_received: return {'status': 'error', 'error': 'out of order or duplicate chunk'} chunk_data = base64.b64decode(data['chunk_data']) f = open(file_meta.path, 'ab') f.write(chunk_data) f.close() async with db_objects.atomic(): file_meta = await db_objects.get(query, agent_file_id=data['file_id']) file_meta.chunks_received = file_meta.chunks_received + 1 # print("received chunk num {}".format(data['chunk_num'])) if file_meta.chunks_received == file_meta.total_chunks: file_meta.complete = True contents = open(file_meta.path, 'rb').read() file_meta.md5 = await hash_MD5(contents) file_meta.sha1 = await hash_SHA1(contents) await db_objects.update(file_meta) except Exception as e: print("Failed to save chunk to disk: " + str(e)) return {'status': 'error', 'error': 'failed to store chunk: ' + str(e)} return {'status': 'success'}
async def update_command(request, user, id): 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") updated_command = False try: query = await db_model.command_query() command = await db_objects.get(query, id=id) query = await db_model.operator_query() operator = await db_objects.get(query, username=user['username']) except Exception as e: print(e) return json({'status': 'error', 'error': 'failed to get command'}) if request.form: data = js.loads(request.form.get('json')) else: data = request.json if "description" in data and data['description'] != command.description: command.description = data['description'] updated_command = True if "needs_admin" in data and data['needs_admin'] != command.needs_admin: command.needs_admin = data['needs_admin'] updated_command = True if "help_cmd" in data and data['help_cmd'] != command.help_cmd: command.help_cmd = data['help_cmd'] updated_command = True if "is_exit" in data and data['is_exit'] is True: query = await db_model.command_query() try: exit_commands = await db_objects.execute( query.where((Command.is_exit == True) & (Command.payload_type == command.payload_type))) # one is already set, so set it to false for e in exit_commands: e.is_exit = False await db_objects.update(e) command.is_exit = data['is_exit'] except Exception as e: # one doesn't exist, so let this one be set print(str(e)) if request.files: updated_command = True cmd_code = request.files['upload_file'][0].body cmd_file = open("./app/payloads/{}/commands/{}".format(command.payload_type.ptype, command.cmd), "wb") # cmd_code = base64.b64decode(data['code']) cmd_file.write(cmd_code) cmd_file.close() elif "code" in data: updated_command = True cmd_file = open("./app/payloads/{}/commands/{}".format(command.payload_type.ptype, command.cmd), "wb") cmd_code = base64.b64decode(data['code']) cmd_file.write(cmd_code) cmd_file.close() command.operator = operator await db_objects.update(command) if updated_command: async with db_objects.atomic(): query = await db_model.command_query() command = await db_objects.get(query, id=command.id) command.version = command.version + 1 await db_objects.update(command) return json({'status': 'success', **command.to_json()})
async def update_command_parameter(request, user, cid, pid): updated_a_field = False try: query = await db_model.operator_query() operator = await db_objects.get(query, username=user['username']) query = await db_model.command_query() command = await db_objects.get(query, id=cid) query = await db_model.commandparameters_query() parameter = await db_objects.get(query, id=pid, command=command) except Exception as e: print(e) return json({ "status": 'error', 'error': 'failed to find command or parameter' }) data = request.json if "name" in data and data['name'] != parameter.name: try: parameter.name = data['name'] parameter.operator = operator await db_objects.update(parameter) updated_a_field = True except Exception as e: print(e) return json({ "status": 'error', 'error': 'parameter name must be unique across a command' }) if "required" in data and data['required'] != parameter.required: parameter.required = data['required'] updated_a_field = True if data['type']: if data['type'] != parameter.type: parameter.type = data['type'] updated_a_field = True if data['type'] == "String" and data['hint'] != parameter.hint: parameter.hint = data['hint'] if 'hint' in data else "" updated_a_field = True elif data['type'] == "Choice" and data['choices'] != parameter.choices: parameter.choices = data['choices'] if 'choices' in data else "" updated_a_field = True elif data['type'] == "ChooseMultiple" and data[ 'choices'] != parameter.choices: parameter.choices = data['choices'] if 'choices' in data else "" updated_a_field = True parameter.operator = operator # update the command since we just updated a parameter to it if updated_a_field: async with db_objects.atomic(): query = await db_model.command_query() command = await db_objects.get(query, id=cid) command.version = command.version + 1 await db_objects.update(command) await db_objects.update(parameter) return json({ 'status': 'success', **parameter.to_json(), 'new_cmd_version': command.version })
async def download_file_to_disk_func(data): # upload content blobs to be associated with filemeta id if "chunk_num" not in data: return {"status": "error", "error": "missing chunk_num"} if "chunk_data" not in data: return {"status": "error", "error": "missing chunk data"} try: query = await db_model.filemeta_query() file_meta = await db_objects.get(query, agent_file_id=data["file_id"]) except Exception as e: print(e) return {"status": "error", "error": "failed to get File info"} try: # print("trying to base64 decode chunk_data") if data["chunk_num"] <= file_meta.chunks_received: return { "status": "error", "error": "out of order or duplicate chunk" } chunk_data = base64.b64decode(data["chunk_data"]) f = open(file_meta.path, "ab") f.write(chunk_data) f.close() async with db_objects.atomic(): file_meta = await db_objects.get(query, agent_file_id=data["file_id"]) file_meta.chunks_received = file_meta.chunks_received + 1 if "host" in data and data[ "host"] is not None and data["host"] != "": file_meta.host = data["host"].encode("unicode-escape") if "full_path" in data and data[ "full_path"] is not None and data["full_path"] != "": file_meta.full_remote_path = data["full_path"].encode( "unicode-escape") if file_meta.file_browser is None: await add_upload_file_to_file_browser( file_meta.operation, file_meta.task, file_meta, { "host": file_meta.host, "full_path": file_meta.full_remote_path }) # print("received chunk num {}".format(data['chunk_num'])) if file_meta.chunks_received == file_meta.total_chunks: file_meta.complete = True contents = open(file_meta.path, "rb").read() file_meta.md5 = await hash_MD5(contents) file_meta.sha1 = await hash_SHA1(contents) if not file_meta.is_screenshot: await log_to_siem(file_meta.to_json(), mythic_object="file_download") await db_objects.update(file_meta) except Exception as e: print("Failed to save chunk to disk: " + str(e)) return {"status": "error", "error": "failed to store chunk: " + str(e)} return {"status": "success"}
async def update_command(request, user, id): updated_command = False try: query = await db_model.command_query() command = await db_objects.get(query, id=id) query = await db_model.operator_query() operator = await db_objects.get(query, username=user['username']) except Exception as e: print(e) return json({'status': 'error', 'error': 'failed to get command'}) if request.form: data = js.loads(request.form.get('json')) else: data = request.json if "description" in data and data['description'] != command.description: command.description = data['description'] updated_command = True if "needs_admin" in data and data['needs_admin'] != command.needs_admin: command.needs_admin = data['needs_admin'] updated_command = True if "help_cmd" in data and data['help_cmd'] != command.help_cmd: command.help_cmd = data['help_cmd'] updated_command = True if request.files: updated_command = True cmd_code = request.files['upload_file'][0].body cmd_file = open( "./app/payloads/{}/commands/{}".format(command.payload_type.ptype, command.cmd), "wb") # cmd_code = base64.b64decode(data['code']) cmd_file.write(cmd_code) cmd_file.close() elif "code" in data: updated_command = True cmd_file = open( "./app/payloads/{}/commands/{}".format(command.payload_type.ptype, command.cmd), "wb") cmd_code = base64.b64decode(data['code']) cmd_file.write(cmd_code) cmd_file.close() command.operator = operator await db_objects.update(command) if updated_command: async with db_objects.atomic(): query = await db_model.command_query() command = await db_objects.get(query, id=command.id) command.version = command.version + 1 await db_objects.update(command) return json({'status': 'success', **command.to_json()})
async def remove_command_parameter(request, user, cid, pid): try: command = await db_objects.get(Command, id=cid) parameter = await db_objects.get(CommandParameters, id=pid, command=command) except Exception as e: print(e) return json({'status': 'error', 'error': 'failed to find command or parameter'}) p_json = parameter.to_json() await db_objects.delete(parameter) # update the command since we just updated a parameter to it async with db_objects.atomic(): command = await db_objects.get(Command, id=cid) command.version = command.version + 1 print("deleted param") await db_objects.update(command) return json({'status': 'success', **p_json, 'new_cmd_version': command.version})
async def create_command_parameter(request, user, id): 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") try: query = await db_model.operator_query() operator = await db_objects.get(query, username=user['username']) query = await db_model.command_query() command = await db_objects.get(query, id=id) except Exception as e: return json({'status': 'error', 'error': 'failed to find command'}) data = request.json if "name" not in data: return json({'status': 'error', 'error': '"name" is required'}) if 'type' not in data: return json({'status': 'error', 'error': '"type" is a required parameter'}) if 'required' not in data: return json({'status': 'error', 'error': '"required" is a required parameter'}) if data['type'] == "String" and 'hint' not in data: return json({'status': 'error', 'error': "\"hint\" required if type is \"String\""}) if data['type'] == "Choice" and 'choices' not in data: return json({'status': 'error', 'error': "\"choices\" is required if type is \"Choice\""}) if data['type'] == "ChooseMultiple" and 'choices' not in data: return json({'status': 'error', 'error': "\"choices\" is required if type is \"ChooseMultiple\""}) if 'hint' not in data: data['hint'] = "" try: query = await db_model.commandparameters_query() try: param = await db_objects.get(query, **data, command=command, operator=operator) except Exception as e: param = await db_objects.create(CommandParameters, **data, command=command, operator=operator) async with db_objects.atomic(): query = await db_model.command_query() command = await db_objects.get(query, id=id) command.version = command.version + 1 await db_objects.update(command) return json({'status': 'success', **param.to_json(), 'new_cmd_version': command.version}) except Exception as e: print(e) return json({'status': 'error', 'error': 'failed to create parameter' + str(e)})
async def download_file_to_disk_func(data): # upload content blobs to be associated with filemeta id if 'chunk_num' not in data: return {'status': 'error', 'error': 'missing chunk_num'} if 'chunk_data' not in data: return {'status': 'error', 'error': 'missing chunk data'} try: query = await db_model.filemeta_query() file_meta = await db_objects.get(query, agent_file_id=data['file_id']) except Exception as e: print(e) return {'status': 'error', 'error': 'failed to get File info'} try: # print("trying to base64 decode chunk_data") chunk_data = base64.b64decode(data['chunk_data']) f = open(file_meta.path, 'ab') f.write(chunk_data) f.close() async with db_objects.atomic(): file_meta = await db_objects.get(query, agent_file_id=data['file_id']) file_meta.chunks_received = file_meta.chunks_received + 1 # print("received chunk num {}".format(data['chunk_num'])) if file_meta.chunks_received == file_meta.total_chunks: file_meta.complete = True await db_objects.update(file_meta) # if we ended up downloading a file from mac's screencapture utility, we need to fix it a bit f = open(file_meta.path, 'rb').read(8) if f == b"'PNGf'($": f = open(file_meta.path, 'rb').read() new_file = open(file_meta.path, 'wb') new_file.write(unhexlify(f[8:-2])) new_file.close() except Exception as e: print("Failed to save chunk to disk: " + str(e)) return {'status': 'error', 'error': 'failed to store chunk: ' + str(e)} return {'status': 'success'}