Skip to content

Commit

Permalink
Merge pull request #763 from BC-SECURITY/release/5.12.0
Browse files Browse the repository at this point in the history
v5.12.0 into main
  • Loading branch information
vinnybod authored Dec 14, 2024
2 parents 54ce418 + b459a47 commit 5aeb633
Show file tree
Hide file tree
Showing 7 changed files with 54 additions and 98 deletions.
9 changes: 8 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [5.12.0] - 2024-12-14

- Reduce the check-in tests that were adding an unncessary amount of time to the CI
- Allow Python 3.13 to be used
- Fix python install
- Support Empire for system-wide deployment (@D3vil0p3r)
- Paths specified in config.yaml where user does not have write permission will be fallback to ~/.empire directory and config.yaml updated as well (@D3vil0p3r)
- Invoke-Obfuscation is no longer copied to /usr/local/share
Expand Down Expand Up @@ -948,7 +953,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Updated shellcoderdi to newest version (@Cx01N)
- Added a Nim launcher (@Hubbl3)

[Unreleased]: https://github.com/BC-SECURITY/Empire-Sponsors/compare/v5.11.7...HEAD
[Unreleased]: https://github.com/BC-SECURITY/Empire-Sponsors/compare/v5.12.0...HEAD

[5.12.0]: https://github.com/BC-SECURITY/Empire-Sponsors/compare/v5.11.7...v5.12.0

[5.11.7]: https://github.com/BC-SECURITY/Empire-Sponsors/compare/v5.11.6...v5.11.7

Expand Down
2 changes: 1 addition & 1 deletion empire/server/common/empire.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@

from . import agents, credentials, listeners, stagers

VERSION = "5.11.7 BC Security Fork"
VERSION = "5.12.0 BC Security Fork"

log = logging.getLogger(__name__)

Expand Down
4 changes: 2 additions & 2 deletions empire/test/conftest.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import asyncio
import os
import shutil
import sys
Expand Down Expand Up @@ -57,7 +56,8 @@ def client():

# fix for pycharm debugger
# https://stackoverflow.com/a/77926544/5849681
yield TestClient(app, backend_options={"loop_factory": asyncio.new_event_loop})
# yield TestClient(app, backend_options={"loop_factory": asyncio.new_event_loop})
yield TestClient(app)

from empire.server.server import main

Expand Down
82 changes: 14 additions & 68 deletions empire/test/test_agent_checkins_api.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import asyncio
import logging
import time
from contextlib import contextmanager
from datetime import datetime, timedelta, timezone

import pytest
Expand All @@ -10,12 +8,6 @@
log = logging.getLogger(__name__)


@contextmanager
def timer():
start = time.perf_counter()
yield lambda: time.perf_counter() - start


@pytest.fixture(scope="function")
def agents(session_local, host, models):
agent_ids = []
Expand Down Expand Up @@ -67,9 +59,9 @@ async def _create_checkins(session_local, models, agent_ids):
)


agent_count = 10
time_delta = 5 # 17280 checkins per agent per day
days_back = 7
agent_count = 2
time_delta = 20 # 4320 checkins per agent per day
days_back = 3
end_time = datetime(2023, 1, 8, tzinfo=timezone.utc)
start_time = end_time - timedelta(days=days_back)

Expand All @@ -88,51 +80,6 @@ async def _create_checkin(session_local, models, agent_id):
db_2.add_all(checkins)


@pytest.mark.slow
def test_database_performance_checkins(models, host, agents, session_local):
# logging.basicConfig()
# logging.getLogger("sqlalchemy.engine").setLevel(logging.INFO)
# logging.getLogger("sqlalchemy.engine").propagate = True
# print(query.statement.compile(compile_kwargs={"literal_binds": True}))

with session_local() as db:
asyncio.run(_create_checkins(session_local, models, agents))

with timer() as t:
checkins = db.query(models.AgentCheckIn).count()
assert checkins >= (agent_count * 17280 * days_back)
log.info(f"Time to query {checkins} checkins count: {t():0.4f} seconds")

with timer() as t:
agents = db.query(models.Agent).count()
assert agents >= agent_count
log.info(f"Time to query {agents} agents count: {t():0.4f} seconds")
assert t() < 1

with timer() as t:
query = db.query(models.Agent)
query.all()
log.info(f"Time to query {agents} agents: {t():0.4f} seconds")
assert t() < 1

with timer() as t:
query = db.query(models.AgentCheckIn).limit(50000)
query.all()
log.info(f"Time to query {checkins} checkins: {t():0.4f} seconds")
assert t() < 6 # noqa: PLR2004

agents = db.query(models.Agent).all()

with timer() as t:
for a in agents:
name = a.name
lastseen_time = a.lastseen_time
stale = a.stale
log.info(f"{name} - {lastseen_time} - {stale}")
log.info(f"Time to query {agents} agents' dynamic fields: {t():0.4f} seconds")
assert t() < 0.1 * agent_count


def test_get_agent_checkins_agent_not_found(client, admin_auth_header):
response = client.get("/api/v2/agents/XYZ123/checkins", headers=admin_auth_header)

Expand All @@ -153,7 +100,7 @@ def test_get_agent_checkins_with_limit_and_page(
checkin_count = 10
assert response.status_code == status.HTTP_200_OK
assert len(response.json()["records"]) == checkin_count
assert response.json()["total"] > days_back * 17280
assert response.json()["total"] > days_back * 4320
assert response.json()["page"] == 1

page1 = response.json()["records"]
Expand All @@ -166,7 +113,7 @@ def test_get_agent_checkins_with_limit_and_page(
page_count = 2
assert response.status_code == status.HTTP_200_OK
assert len(response.json()["records"]) == checkin_count
assert response.json()["total"] > days_back * 17280
assert response.json()["total"] > days_back * 4320
assert response.json()["page"] == page_count

page2 = response.json()["records"]
Expand All @@ -178,18 +125,17 @@ def test_get_agent_checkins_with_limit_and_page(
def test_get_agent_checkins_multiple_agents(
client, admin_auth_header, agents, session_local, models
):
with_checkins = agents[:3]
asyncio.run(_create_checkins(session_local, models, with_checkins))
asyncio.run(_create_checkins(session_local, models, agents))

response = client.get(
"/api/v2/agents/checkins",
headers=admin_auth_header,
params={"agents": with_checkins[:2], "limit": 400000},
params={"agents": agents, "limit": 400000},
)

assert response.status_code == status.HTTP_200_OK
assert len(response.json()["records"]) == days_back * 17280 * 2
assert {r["agent_id"] for r in response.json()["records"]} == set(with_checkins[:2])
assert len(response.json()["records"]) == days_back * 4320 * agent_count
assert {r["agent_id"] for r in response.json()["records"]} == set(agents)


@pytest.mark.slow
Expand All @@ -199,7 +145,7 @@ def test_agent_checkins_aggregate(
if empire_config.database.use == "sqlite":
pytest.skip("sqlite not supported for checkin aggregation")

asyncio.run(_create_checkins(session_local, models, agents[:3]))
asyncio.run(_create_checkins(session_local, models, agents))

response = client.get(
"/api/v2/agents/checkins/aggregate",
Expand All @@ -209,7 +155,7 @@ def test_agent_checkins_aggregate(
assert response.status_code == status.HTTP_200_OK
assert response.elapsed.total_seconds() < 5 # noqa: PLR2004
assert response.json()["bucket_size"] == "day"
assert response.json()["records"][1]["count"] == 17280 * 3
assert response.json()["records"][1]["count"] == 4320 * agent_count

response = client.get(
"/api/v2/agents/checkins/aggregate",
Expand All @@ -220,7 +166,7 @@ def test_agent_checkins_aggregate(
assert response.status_code == status.HTTP_200_OK
assert response.elapsed.total_seconds() < 5 # noqa: PLR2004
assert response.json()["bucket_size"] == "hour"
assert response.json()["records"][1]["count"] == 720 * 3
assert response.json()["records"][1]["count"] == 180 * agent_count

response = client.get(
"/api/v2/agents/checkins/aggregate",
Expand All @@ -231,7 +177,7 @@ def test_agent_checkins_aggregate(
assert response.status_code == status.HTTP_200_OK
assert response.elapsed.total_seconds() < 5 # noqa: PLR2004
assert response.json()["bucket_size"] == "minute"
assert response.json()["records"][1]["count"] == 12 * 3
assert response.json()["records"][1]["count"] == 3 * agent_count

response = client.get(
"/api/v2/agents/checkins/aggregate",
Expand All @@ -246,7 +192,7 @@ def test_agent_checkins_aggregate(
assert response.status_code == status.HTTP_200_OK
assert response.elapsed.total_seconds() < 5 # noqa: PLR2004
assert response.json()["bucket_size"] == "second"
assert response.json()["records"][1]["count"] == 1 * 3
assert response.json()["records"][1]["count"] == 1 * agent_count

# Test start date and end date
response = client.get(
Expand Down
49 changes: 26 additions & 23 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "empire-bc-security-fork"
version = "5.11.7"
version = "5.12.0"
description = ""
authors = ["BC Security <[email protected]>"]
readme = "README.md"
Expand All @@ -13,7 +13,7 @@ packages = [
]

[tool.poetry.dependencies]
python = ">=3.10,<3.13"
python = ">=3.10,<3.14"
urllib3 = "^2.2.0"
requests = "^2.31.0"
iptools = "^0.7.0"
Expand Down
2 changes: 1 addition & 1 deletion setup/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ if ! command_exists pyenv; then
apt-get -y install build-essential gdb lcov pkg-config \
libbz2-dev libffi-dev libgdbm-dev libgdbm-compat-dev liblzma-dev \
libncurses5-dev libreadline6-dev libsqlite3-dev libssl-dev \
lzma lzma-dev tk-dev uuid-dev zlib1g-dev
lzma tk-dev uuid-dev zlib1g-dev
pyenv install 3.12.6
fi
Expand Down

0 comments on commit 5aeb633

Please sign in to comment.