Example #1
0
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
Example #3
0
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
Example #4
0
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]
Example #6
0
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
Example #7
0
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()