def test_delete_session(new_session): """ Given a session, when the session_dao.delete_session method is called, check the session was removed from the database correctly. """ try: session_dao.delete_session(new_session.uid) except Exception as e: pytest.fail("session_dao.delete_session returned an exception: " + str(e)) assert session_dao.get_session(new_session.uid) is None
def test_api_session_remove_unauthenticated(app_client, new_user, new_session): """ Given an unauthenticated user and a session, when a POST request is sent to /api/session/remove, check that a HTTP 403 forbidden status is returned and the session is not removed. """ res = app_client.post( '/api/session/remove', data={'session_uid': new_session.uid}, follow_redirects=True, headers={"Content-Type": "application/x-www-form-urlencoded"}) assert res.status_code == 403 assert session_dao.get_session(new_session.uid) is not None
def test_update_session_status(app_client, new_session): """ Given a session, when the session_dao.update_session_status is called, check that the 'online' attribute of session metadata is correctly updated in the database. """ # toggle online/offline status prev_status = new_session.online new_status = False if new_session.online else True session_dao.update_session_status(new_session.uid, new_status) # check if it was updated correctly session = session_dao.get_session(new_session.uid) assert session is not None assert session.online == new_status
def test_payload_secure_connection(app_client, new_user): """ Given an instance of the C2 socket server and an instance of a dummy payload, when the payload attempts to connect to the server, check that a secure connection is established. This is a multi-step process which involves the following: 1) TCP connection 2) Diffie-Hellman IKE to generate a secure 256 bit symmetric key, 3) Payload sends server info about the client machine 4) Server creates a new session thread to handle the connection with the client, and stores the session metadata in the database. """ # attempt connection try: payload = dummy_payload.Payload(host='0.0.0.0', port='1337', gui='1', owner=new_user.username) except Exception as e: pytest.fail(f"Connection failed: {e}") # check 256 bit key generated by Diffie-Hellman IKE successfully, matches on client and server assert payload.key is not None assert len(payload.key) == 32 # check session thread created correctly time.sleep(2) session_threads = c2.sessions.get(new_user.username) assert session_threads is not None assert isinstance(session_threads, dict) assert len(session_threads) == 1 uid = list(session_threads.keys())[0] session_thread = session_threads[uid] assert isinstance(session_thread, SessionThread) # check session metadata stored in database session_metadata = session_dao.get_session(uid) assert session_metadata is not None assert isinstance(session_metadata, Session)
def test_api_session_remove(app_client, new_user, new_session): """ Given a user and a session, when a POST request is sent to /api/session/remove with a valid session UID, check the session metadata is correctly removed from the database. """ login(app_client, new_user.username, 'test_password') # create dummy session dummy_session = SessionThread(id=1, c2=c2, connection=None) dummy_session.info = dict(new_session.serialize()) c2.sessions[new_user.username] = {new_session.uid: dummy_session} # save session uid because new_session will be deleted uid = new_session.uid res = app_client.post( '/api/session/remove', data={'session_uid': uid}, follow_redirects=True, headers={"Content-Type": "application/x-www-form-urlencoded"}) assert res.status_code == 200 assert session_dao.get_session(uid) is None assert uid not in c2.sessions[new_user.username]
def test_handle_session(app_client, new_user): """ Given a new user, when a new user is created via session_dao.handle_session function, then check the session metadata is stored in the database correctly. """ # add test session (without uid) uid = md5(bytes(getrandbits(10))).hexdigest() input_session_dict = { "online": True, "joined": datetime.utcnow(), "last_online": datetime.utcnow(), "public_ip": '1.2.3.4', "local_ip": '192.1.1.168', "mac_address": '00:0A:95:9D:68:16', "username": '******', "administrator": True, "platform": 'linux2', "device": 'test_device', "architecture": 'x32', "latitude": 0.00, "longitude": 0.00, "owner": new_user.username, } try: output_session_dict = session_dao.handle_session(input_session_dict) except Exception as e: pytest.fail("dao.handle_session exception handling new session: " + str(e)) # check server assigned uid assert 'uid' in output_session_dict uid = output_session_dict['uid'] # run tests session = session_dao.get_session(uid) assert session.owner == new_user.username assert session.uid == uid assert session.online is True assert (datetime.utcnow() - session.joined).seconds <= 5 assert (datetime.utcnow() - session.last_online).seconds <= 5 assert session.public_ip == '1.2.3.4' assert session.local_ip == '192.1.1.168' assert session.mac_address == '00:0A:95:9D:68:16' assert session.username == 'test_user' assert session.administrator is True assert session.platform == 'linux2' assert session.device == 'test_device' assert session.architecture == 'x32' assert session.longitude == 0.00 assert session.latitude == 0.00 # add test session (with uid) uid = md5(bytes(getrandbits(10))).hexdigest() input_session_dict = { "uid": uid, "online": True, "joined": datetime.utcnow(), "last_online": datetime.utcnow(), "public_ip": '5.6.7.8', "local_ip": '192.1.1.168', "mac_address": '00:0A:95:9D:68:16', "username": '******', "administrator": True, "platform": 'linux2', "device": 'test_device', "architecture": 'x32', "latitude": 0.00, "longitude": 0.00, "owner": new_user.username, } try: output_session_dict = session_dao.handle_session(input_session_dict) except Exception as e: pytest.fail( "dao.handle_session exception handling existing session: " + str(e)) # run tests session = session_dao.get_session(uid) assert session.owner == new_user.username assert session.uid == uid assert session.online is True assert (datetime.utcnow() - session.joined).seconds <= 5 assert (datetime.utcnow() - session.last_online).seconds <= 5 assert session.public_ip == '5.6.7.8' assert session.local_ip == '192.1.1.168' assert session.mac_address == '00:0A:95:9D:68:16' assert session.username == 'test_user' assert session.administrator is True assert session.platform == 'linux2' assert session.device == 'test_device' assert session.architecture == 'x32' assert session.longitude == 0.00 assert session.latitude == 0.00
def test_payload_connection(app_client, new_user): """ Given an instance of the C2 socket server and an instance of a dummy payload, when the payload attempts to connect to the server, check that a secure connection is established. This is a multi-step process which involves the following: 1) TCP connection 2) Diffie-Hellman IKE to generate a secure 256 bit symmetric key, 3) Payload sends server info about the client machine 4) Server creates a new session thread to handle the connection with the client, 5) Session metadata is stored the database 6) Client/server can now send AES-256-CBC encrypted messages over the network """ # attempt connection try: payload = dummy_payload_for_testing.Payload(host='0.0.0.0', port='1337', gui='1', owner=new_user.username) payload_process = Process(target=payload.run) payload_process.start() except Exception as e: pytest.fail(f"Connection failed: {e}") # check 256 bit key generated by Diffie-Hellman IKE successfully, matches on client and server assert payload.key is not None assert len(payload.key) == 32 # check session thread created correctly time.sleep(2) session_threads = c2.sessions.get(new_user.username) assert session_threads is not None assert isinstance(session_threads, dict) assert len(session_threads) == 1 uid = list(session_threads.keys())[0] session_thread = session_threads[uid] assert isinstance(session_thread, SessionThread) # check session metadata stored in database session_metadata = session_dao.get_session(uid) assert session_metadata is not None assert isinstance(session_metadata, Session) # test send/receive data between client/server command = 'echo hello world' try: # store issued task in database task = task_dao.handle_task({ 'task': command, 'session': session_thread.info.get('uid') }) # send task and get response session_thread.send_task(task) response = session_thread.recv_task() # update task record with result in database result_dict = task_dao.handle_task(response) result = str(result_dict['result']).encode() # if end-to-end encryption and remote command execution has worked, response will be 'hello world' assert result == b'hello world\n' except Exception as e: pytest.fail(f"Session command raised exception: {e}") finally: # kill payload session_thread.kill() payload_process.terminate()