async def ws_payloadtypec2profile(request, ws): try: async with aiopg.create_pool(apfell.config['DB_POOL_CONNECT_STRING']) as pool: async with pool.acquire() as conn: async with conn.cursor() as cur: await cur.execute('LISTEN "newpayloadtypec2profile";') # BEFORE WE START GETTING NEW THINGS, UPDATE WITH ALL OF THE OLD DATA profiles = await db_objects.execute(PayloadTypeC2Profile.select()) for p in profiles: await ws.send(js.dumps(p.to_json())) await ws.send("") # now pull off any new payloads we got queued up while processing old data while True: try: msg = conn.notifies.get_nowait() id = (msg.payload) p = await db_objects.get(PayloadTypeC2Profile, id=id) await ws.send(js.dumps(p.to_json())) except asyncio.QueueEmpty as e: await asyncio.sleep(2) await ws.send("") # this is our test to see if the client is still there continue except Exception as e: print(e) return finally: pool.close()
async def delete_c2profile(request, info, user): try: info = unquote_plus(info) operation = await db_objects.get(Operation, name=user['current_operation']) profile = await db_objects.get(C2Profile, name=info, operation=operation) parameters = await db_objects.execute( C2ProfileParameters.select().where( C2ProfileParameters.c2_profile == profile)) ptypec2profile = await db_objects.execute( PayloadTypeC2Profile.select().where( PayloadTypeC2Profile.c2_profile == profile)) except Exception as e: print(e) return json({'status': 'error', 'error': 'failed to find C2 profile'}) try: # we will do this recursively because there can't be payloadtypec2profile mappings if the profile doesn't exist for p in parameters: await db_objects.delete(p, recursive=True) for p in ptypec2profile: await db_objects.delete(p, recursive=True) await db_objects.delete(profile, recursive=True) # remove it from disk shutil.rmtree("./app/c2_profiles/{}/{}".format(operation.name, info)) success = {'status': 'success'} updated_json = profile.to_json() return json({**success, **updated_json}) except Exception as e: return json({ 'status': 'error', 'error': 'failed to delete c2 profile' })
async def get_all_c2profiles_for_current_operation(request, user): if user['current_operation'] != "": try: operation = await db_objects.get(Operation, name=user['current_operation']) all_profiles = await db_objects.execute( C2Profile.select().where(C2Profile.operation == operation)) profiles = await db_objects.execute( PayloadTypeC2Profile.select( PayloadTypeC2Profile, C2Profile, PayloadType).join(C2Profile).switch( PayloadTypeC2Profile).join(PayloadType)) results = [] inter = {} for p in all_profiles: inter[p.name] = p.to_json() inter[p.name]['ptype'] = [ ] # start to keep track of which payload types this profile supports for p in profiles: if p.c2_profile.operation == operation: inter[p.c2_profile.name]['ptype'].append( p.payload_type.ptype) for k in inter.keys(): # make an array of dictionaries results.append(inter[k]) return json(results) except Exception as e: print(e) return json([""]) else: return json([""])
async def update_c2profile(request, info, user): name = unquote_plus(info) data = request.json payload_types = [] try: # TODO make sure the user has appropriate access to the c2_profile by checking operations scopes profile = await db_objects.get(C2Profile, name=name) except Exception as e: print(e) return json({'status': 'error', 'error': 'failed to find C2 Profile'}) try: if 'description' in data: profile.description = data['description'] if 'payload_types' in data: # We need to update the mapping in PayloadTypeC2Profile accordingly # We need to see which ones were there before, and either add or delete accordingly mapping = await db_objects.execute( PayloadTypeC2Profile.select().where( PayloadTypeC2Profile.c2_profile == profile)) # For each payload type, make sure it's real, and that it's in the mapping for m in mapping: map = await db_objects.get(PayloadType, id=m.payload_type) if map.ptype in data['payload_types']: # something we say this c2 profile supports is already listed, so remove it from our list to process del data['payload_types'][data['payload_types'].index( map.ptype)] # remove it from the array payload_types.append(map.ptype) else: # it was in our mapping, now it's not, so remove it from the database mapping await db_objects.delete(m) # if there's anyting left in data['payload_types'], it means we need to add it to the database for m in data['payload_types']: if await db_objects.count(PayloadType.select().where( PayloadType.ptype == m.strip())) != 1: return json({ 'status': 'error', 'error': m + ' is not a valid PayloadType. Perhaps you need to register it first?' }) payload = await db_objects.get(PayloadType, ptype=m.strip()) await db_objects.create(PayloadTypeC2Profile, c2_profile=profile, payload_type=payload) payload_types.append(m.strip()) success = {'status': 'success'} updated_json = profile.to_json() return json({ **success, **updated_json, 'payload_types': payload_types }) except Exception as e: print(e) return json({ 'status': 'error', 'error': 'failed to update C2 Profile' })
async def get_c2profiles_by_type_function(ptype, user_dict): try: payload_type = await db_objects.get(PayloadType, ptype=ptype) profiles = await db_objects.execute( PayloadTypeC2Profile.select().where( PayloadTypeC2Profile.payload_type == payload_type)) except Exception as e: print(e) raise Exception return [ p.to_json() for p in profiles if p.c2_profile.operation in user_dict['operations'] or user_dict['admin'] ]
async def get_all_c2profiles(request, user): # this syntax is atrocious for getting a pretty version of the results from a many-to-many join table) all_profiles = await db_objects.execute(C2Profile.select()) profiles = await db_objects.execute( PayloadTypeC2Profile.select(PayloadTypeC2Profile, C2Profile, PayloadType).join(C2Profile).switch( PayloadTypeC2Profile).join(PayloadType) ) results = [] inter = {} for p in all_profiles: # only show profiles for operations the user is part of # overall admins can see all operations if p.operation.name in user['operations'] or user['admin']: inter[p.name] = p.to_json() # create an empty array for ptypes that we'll populate in the next for loop inter[p.name]['ptype'] = [] for p in profiles: if p.c2_profile.name in inter: inter[p.c2_profile.name]['ptype'].append(p.payload_type.ptype) for k in inter.keys(): results.append(inter[k]) return json(results)
async def upload_c2_profile_payload_type_code(request, info, user): c2profile = unquote_plus(info) # we either get a file from the browser or somebody uploads it via a base64 encoded "code" field if request.form: data = js.loads(request.form.get('json')) else: data = request.json try: operation = await db_objects.get(Operation, name=user['current_operation']) profile = await db_objects.get(C2Profile, name=c2profile, operation=operation) registered_ptypes = await db_objects.execute( PayloadTypeC2Profile.select().where( PayloadTypeC2Profile.c2_profile == profile)) ptypes = [p.payload_type.ptype for p in registered_ptypes ] # just get an array of all the names except Exception as e: return json({ 'status': 'error', 'error': 'failed to find profile or operation' }) if "payload_type" not in data: return json({ 'status': 'error', 'error': 'must associate this code with a specific payload type' }) if data['payload_type'] not in ptypes and data['payload_type'] != "": return json({ 'status': 'error', 'error': 'trying to upload code for a payload time not registered with this c2 profile' }) try: if data['payload_type'] == "": data[ 'payload_type'] = "." # don't change directories and we'll still be in the main c2_profile directory if not os.path.exists("./app/c2_profiles/{}/{}/{}".format( operation.name, profile.name, data['payload_type'])): os.mkdir("./app/c2_profiles/{}/{}/{}".format( operation.name, profile.name, data['payload_type'])) if "code" in data and "file_name" in data: # get a base64 blob of the code and the filename to save it as in the right directory code = base64.b64decode(data['code']) code_file = open( "./app/c2_profiles/{}/{}/{}/{}".format(operation.name, profile.name, data['payload_type'], data['file_name']), 'wb') code_file.write(code) code_file.close() elif request.files: code = request.files['upload_file'][0].body code_file = open( "./app/c2_profiles/{}/{}/{}/{}".format( operation.name, profile.name, data['payload_type'], request.files['upload_file'][0].name), "wb") code_file.write(code) code_file.close() for i in range(1, int(request.form.get('file_length'))): code = request.files['upload_file_' + str(i)][0].body code_file = open( "./app/c2_profiles/{}/{}/{}/{}".format( operation.name, profile.name, data['payload_type'], request.files['upload_file_' + str(i)][0].name), "wb") code_file.write(code) code_file.close() return json({'status': 'success', **profile.to_json()}) except Exception as e: print(e) return json({ 'status': 'error', 'error': 'failed to write code to file: ' + str(e) })
async def export_command_list(request, user, ptype): payload_type = unquote_plus(ptype) try: payload_ptype = await db_objects.get(PayloadType, ptype=payload_type) operation = await db_objects.get(Operation, 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) commands = await db_objects.execute( Command.select().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'] params = await db_objects.execute(CommandParameters.select().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 attacks = await db_objects.execute( ATTACKCommand.select().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 artifacts = await db_objects.execute( ArtifactTemplate.select().where(ArtifactTemplate.command == c)) artifact_list = [] for a in artifacts: a_json = { "command_parameter": a.command_parameter, "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 profiles = await db_objects.execute( PayloadTypeC2Profile.select().where( PayloadTypeC2Profile.payload_type == payload_ptype).join( C2Profile).where(C2Profile.operation == operation)) profiles_dict = {} for p in profiles: files = [] for profile_file in glob.iglob( "./app/c2_profiles/{}/{}/{}/*".format( operation.name, 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 load_transforms = await db_objects.execute(Transform.select().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 create_transforms = await db_objects.execute(Transform.select().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}]})