Skip to content

Commit

Permalink
Merge pull request #462 from BC-SECURITY/release/v4.8.1
Browse files Browse the repository at this point in the history
v4.8.1 into sponsors-dev
  • Loading branch information
Cx01N authored Oct 30, 2022
2 parents 75a68cf + 8e41b38 commit c1ed132
Show file tree
Hide file tree
Showing 9 changed files with 356 additions and 169 deletions.
7 changes: 7 additions & 0 deletions .github/workflows/lint-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ jobs:
python-version: [ '3.8', '3.9', '3.10' ]
steps:
- uses: actions/checkout@v2
if: ${{ github.repository == 'BC-SECURITY/Empire' }}
with:
submodules: 'recursive'
# token is only needed in sponsors repo because of private submodules
# don't use token in public repo because prs from forks cannot access secrets
- uses: actions/checkout@v2
if: ${{ github.repository == 'BC-SECURITY/Empire-Sponsors' }}
with:
submodules: 'recursive'
token: ${{ secrets.RELEASE_TOKEN }}
Expand Down
15 changes: 14 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [4.8.1] - 2022-10-30

- Added container structure test to CI (@Vinnybod)
- Added a fallback checkout that doesn't use a token (@Vinnybod)
- Revamped README.md (@Cx01N)
- Simplified Dockerfile install process (@lavafroth)
- Fixed crashing issue with IronPython agent (@Cx01N)
- Fixed infinite loop output stream for csharpserver plugin (@dwilson5)
- Fixed querying stale and active agents (@lavafroth)

## [4.8.0] - 2022-08-30

- Updated compiler to .NET SDK 6.0 (@Hubbl3)

## [4.7.3] - 2022-08-20
Expand Down Expand Up @@ -295,7 +306,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/v4.8.0...HEAD
[Unreleased]: https://github.com/BC-SECURITY/Empire-Sponsors/compare/v4.8.1...HEAD

[4.8.1]: https://github.com/BC-SECURITY/Empire-Sponsors/compare/v4.8.0...v4.8.1

[4.8.0]: https://github.com/BC-SECURITY/Empire-Sponsors/compare/v4.7.3...v4.8.0

Expand Down
46 changes: 21 additions & 25 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -20,45 +20,41 @@ LABEL maintainer="bc-security"
LABEL description="Dockerfile for Empire server and client. https://bc-security.gitbook.io/empire-wiki/quickstart/installation#docker"

# env setup
ENV STAGING_KEY=RANDOM
ENV DEBIAN_FRONTEND=noninteractive
ENV STAGING_KEY=RANDOM DEBIAN_FRONTEND=noninteractive DOTNET_CLI_TELEMETRY_OPTOUT=1

# set the def shell for ENV
SHELL ["/bin/bash", "-c"]

RUN apt-get update && \
apt-get -y install \
sudo \
python3-dev \
python3-pip \
apt-transport-https \
xclip \
zip \
&& rm -rf /var/lib/apt/lists/*

RUN wget https://packages.microsoft.com/config/debian/10/packages-microsoft-prod.deb && \
sudo dpkg -i packages-microsoft-prod.deb && \
sudo apt-get update && \
sudo apt-get install -y powershell \
&& rm -rf /var/lib/apt/lists/*

RUN wget https://packages.microsoft.com/config/debian/10/packages-microsoft-prod.deb -O packages-microsoft-prod.deb && \
sudo dpkg -i packages-microsoft-prod.deb && \
sudo apt-get update && \
sudo apt-get install -y apt-transport-https dotnet-sdk-6.0 \
RUN wget -q https://packages.microsoft.com/config/debian/10/packages-microsoft-prod.deb && \
dpkg -i packages-microsoft-prod.deb && \
apt-get update && \
apt-get install -qq \
--no-install-recommends \
apt-transport-https \
dotnet-sdk-6.0 \
libicu-dev \
powershell \
python3-dev \
python3-pip \
sudo \
xclip \
zip \
&& rm -rf /var/lib/apt/lists/*

WORKDIR /empire

COPY pyproject.toml /empire
COPY pyproject.toml poetry.lock /empire/

RUN pip install poetry \
--disable-pip-version-check && \
poetry config virtualenvs.create false && \
poetry install --no-root

COPY . /empire

RUN mkdir -p /usr/local/share/powershell/Modules && \
cp -r ./empire/server/powershell/Invoke-Obfuscation /usr/local/share/powershell/Modules

RUN sudo pip install poetry && sudo poetry config virtualenvs.create false && sudo poetry install

RUN yes | ./ps-empire server --reset
RUN rm -rf /empire/empire/server/data/empire*

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 @@ -46,7 +46,7 @@
)
from .events import log_event

VERSION = "4.8.0 BC Security Fork"
VERSION = "4.8.1 BC Security Fork"


class MainMenu(cmd.Cmd):
Expand Down
93 changes: 52 additions & 41 deletions empire/server/database/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
String,
Text,
UniqueConstraint,
func,
)
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.hybrid import hybrid_property
Expand All @@ -24,8 +25,8 @@


class User(Base):
__tablename__ = 'users'
id = Column(Integer, Sequence('user_id_seq'), primary_key=True)
__tablename__ = "users"
id = Column(Integer, Sequence("user_id_seq"), primary_key=True)
username = Column(String(255), nullable=False)
password = Column(String(255), nullable=False)
api_token = Column(String(50))
Expand All @@ -35,12 +36,11 @@ class User(Base):
notes = Column(Text)

def __repr__(self):
return "<User(username='%s')>" % (
self.username)
return "<User(username='%s')>" % (self.username)


class Listener(Base):
__tablename__ = 'listeners'
__tablename__ = "listeners"
id = Column(Integer, Sequence("listener_id_seq"), primary_key=True)
name = Column(String(255), nullable=False, unique=True)
module = Column(String(255), nullable=False)
Expand All @@ -51,8 +51,7 @@ class Listener(Base):
created_at = Column(UtcDateTime, nullable=False, default=utcnow())

def __repr__(self):
return "<Listener(name='%s')>" % (
self.name)
return "<Listener(name='%s')>" % (self.name)

def __getitem__(self, key):
return self.__dict__[key]
Expand All @@ -62,7 +61,7 @@ def __setitem__(self, key, value):


class Host(Base):
__tablename__ = 'hosts'
__tablename__ = "hosts"
id = Column(Integer, Sequence("host_id_seq"), primary_key=True)
name = Column(String(255), nullable=False)
internal_ip = Column(String(255))
Expand All @@ -71,10 +70,10 @@ class Host(Base):


class Agent(Base):
__tablename__ = 'agents'
__tablename__ = "agents"
id = Column(Integer, Sequence("agent_id_seq"), primary_key=True)
name = Column(String(255), nullable=False)
host_id = Column(Integer, ForeignKey('hosts.id'))
host_id = Column(Integer, ForeignKey("hosts.id"))
host = relationship(Host, lazy="joined")
listener = Column(String(255), nullable=False)
session_id = Column(String(255), nullable=False, unique=True)
Expand Down Expand Up @@ -107,13 +106,20 @@ class Agent(Base):
killed = Column(Boolean, nullable=False)
proxy = Column(PickleType)

@hybrid_property # todo @stale.expression
@hybrid_property
def stale(self):
return is_stale(self.lastseen_time, self.delay, self.jitter)

@stale.expression
def stale(cls):
threshold = 30 + cls.delay + cls.delay * cls.jitter
seconds_elapsed = (
func.julianday(utcnow()) - func.julianday(cls.lastseen_time)
) * 86400.0
return seconds_elapsed > threshold

def __repr__(self):
return "<Agent(name='%s')>" % (
self.name)
return "<Agent(name='%s')>" % (self.name)

def __getitem__(self, key):
return self.__dict__[key]
Expand All @@ -123,29 +129,33 @@ def __setitem__(self, key, value):


class AgentFile(Base):
__tablename__ = 'agent_files'
__tablename__ = "agent_files"
id = Column(Integer, primary_key=True)
session_id = Column(String(50))
name = Column(Text, nullable=False)
path = Column(Text, nullable=False)
is_file = Column(Boolean, nullable=False)
parent_id = Column(Integer, ForeignKey('agent_files.id', ondelete='CASCADE'), nullable=True)
parent_id = Column(
Integer, ForeignKey("agent_files.id", ondelete="CASCADE"), nullable=True
)


class HostProcess(Base):
__tablename__ = 'host_processes'
host_id = Column(String(255), ForeignKey('hosts.id'), primary_key=True)
__tablename__ = "host_processes"
host_id = Column(String(255), ForeignKey("hosts.id"), primary_key=True)
process_id = Column(Integer, primary_key=True)
process_name = Column(Text)
architecture = Column(String(255))
user = Column(String(255))
agent = relationship(Agent,
lazy="joined",
primaryjoin="and_(Agent.process_id==foreign(HostProcess.process_id), Agent.host_id==foreign(HostProcess.host_id), Agent.killed == False)")
agent = relationship(
Agent,
lazy="joined",
primaryjoin="and_(Agent.process_id==foreign(HostProcess.process_id), Agent.host_id==foreign(HostProcess.host_id), Agent.killed == False)",
)


class Config(Base):
__tablename__ = 'config'
__tablename__ = "config"
staging_key = Column(String(255), primary_key=True)
install_path = Column(Text, nullable=False)
ip_whitelist = Column(Text, nullable=False)
Expand All @@ -157,8 +167,7 @@ class Config(Base):
obfuscate_command = Column(Text, nullable=False)

def __repr__(self):
return "<Config(staging_key='%s')>" % (
self.staging_key)
return "<Config(staging_key='%s')>" % (self.staging_key)

def __getitem__(self, key):
return self.__dict__[key]
Expand All @@ -168,7 +177,7 @@ def __setitem__(self, key, value):


class Credential(Base):
__tablename__ = 'credentials'
__tablename__ = "credentials"
id = Column(Integer, Sequence("credential_id_seq"), primary_key=True)
credtype = Column(String(255))
domain = Column(Text)
Expand All @@ -180,8 +189,7 @@ class Credential(Base):
notes = Column(Text)

def __repr__(self):
return "<Credential(id='%s')>" % (
self.id)
return "<Credential(id='%s')>" % (self.id)

def __getitem__(self, key):
return self.__dict__[key]
Expand All @@ -196,41 +204,41 @@ class TaskingStatus(enum.Enum):


class Tasking(Base):
__tablename__ = 'taskings'
__tablename__ = "taskings"
id = Column(Integer, primary_key=True)
agent_id = Column(String(255), ForeignKey('agents.session_id'), primary_key=True)
agent_id = Column(String(255), ForeignKey("agents.session_id"), primary_key=True)
agent = relationship(Agent, lazy="joined", innerjoin=True)
input = Column(Text)
input_full = deferred(Column(Text))
output = Column(Text, nullable=True)
# In most cases, this isn't needed and will match output. However, with the filter feature, we want to store
# a copy of the original output if it gets modified by a filter.
original_output = deferred(Column(Text, nullable=True))
user_id = Column(Integer, ForeignKey('users.id'), nullable=False)
user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
user = relationship(User)
created_at = Column(UtcDateTime, default=utcnow(), nullable=False)
updated_at = Column(UtcDateTime, default=utcnow(), onupdate=utcnow(), nullable=False)
updated_at = Column(
UtcDateTime, default=utcnow(), onupdate=utcnow(), nullable=False
)
module_name = Column(Text)
task_name = Column(Text)
status = Column(Enum(TaskingStatus))

def __repr__(self):
return "<Tasking(id='%s')>" % (
self.id)
return "<Tasking(id='%s')>" % (self.id)


class Reporting(Base):
__tablename__ = 'reporting'
__tablename__ = "reporting"
id = Column(Integer, Sequence("reporting_id_seq"), primary_key=True)
name = Column(String(255), nullable=False)
event_type = Column(String(255))
message = Column(Text)
timestamp = Column(UtcDateTime, default=utcnow(), nullable=False)
taskID = Column(Integer, ForeignKey('taskings.id'))
taskID = Column(Integer, ForeignKey("taskings.id"))

def __repr__(self):
return "<Reporting(id='%s')>" % (
self.id)
return "<Reporting(id='%s')>" % (self.id)


class Keyword(Base):
Expand All @@ -239,8 +247,7 @@ class Keyword(Base):
replacement = Column(String(255))

def __repr__(self):
return "<Function(id='%s')>" % (
self.id)
return "<Function(id='%s')>" % (self.id)


class Module(Base):
Expand All @@ -256,14 +263,18 @@ class Profile(Base):
category = Column(String(255))
data = Column(Text, nullable=False)
created_at = Column(UtcDateTime, nullable=False, default=utcnow())
updated_at = Column(UtcDateTime, default=utcnow(), onupdate=utcnow(), nullable=False)
updated_at = Column(
UtcDateTime, default=utcnow(), onupdate=utcnow(), nullable=False
)


class Bypass(Base):
__tablename__= "bypasses"
__tablename__ = "bypasses"
id = Column(Integer, Sequence("bypass_seq"), primary_key=True)
name = Column(String(255), unique=True)
code = Column(Text)
language = Column(String(255))
created_at = Column(UtcDateTime, nullable=False, default=utcnow())
updated_at = Column(UtcDateTime, default=utcnow(), onupdate=utcnow(), nullable=False)
updated_at = Column(
UtcDateTime, default=utcnow(), onupdate=utcnow(), nullable=False
)
6 changes: 5 additions & 1 deletion empire/server/plugins/csharpserver.plugin
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,11 @@ class Plugin(Plugin):

def thread_csharp_responses(self):
while True:
output = self.csharpserver_proc.stdout.readline().rstrip()
output = self.csharpserver_proc.stdout.readline()
if not output:
print(helpers.color("[!] csharpserver output stream closed"))
return
output = output.rstrip()
if output:
print(helpers.color("[*] " + output.decode("UTF-8")))

Expand Down
Loading

0 comments on commit c1ed132

Please sign in to comment.