Skip to content

Commit

Permalink
Merge pull request #224 from BC-SECURITY/dev
Browse files Browse the repository at this point in the history
Empire 3.2.3 Release
  • Loading branch information
Cx01N authored Jun 8, 2020
2 parents b90e2c9 + 7837c49 commit d6c8c9e
Show file tree
Hide file tree
Showing 313 changed files with 1,549 additions and 212 deletions.
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.2.2
3.2.3
17 changes: 12 additions & 5 deletions changelog
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
6/7/2020
------------
- Version 3.2.2 Master Release
- Added Invoke-Seatbelt module - #222 (@Cx01N)
- Added timezone awareness timestamps - #220 (@Vinnybod)
- Added MITRE ATT&CK techniques and software IDs to modules - #223 (@Cx01N)

5/25/2020
------------
- Version 3.2.2 Master Release
- Added Invoke-PrintDemon module (@Hubbl3, @Cx01N)
- Updated Mimikatz 2.2.0 20200519 Windows 10 2004 (build 19041) (@Cx01N)
- Fixed youtube URL in trollsploit/thunderstruck (@Gutters2Gardens)
- Added API endpoints for plugins (@Hubbl3)
- Fixed keylogger issue when writing to file (@Cx01N)
- Added Invoke-PrintDemon module - #210 (@Hubbl3, @Cx01N)
- Updated Mimikatz 2.2.0 20200519 Windows 10 2004 - #211 (build 19041) (@Cx01N)
- Fixed youtube URL in trollsploit/thunderstruck - #207(@Gutters2Gardens)
- Added API endpoints for plugins - #213 (@Hubbl3)
- Fixed keylogger issue when writing to file - #206 (@Cx01N)

5/10/2020
------------
Expand Down
25 changes: 25 additions & 0 deletions data/module_source/situational_awareness/host/Invoke-Seatbelt.ps1

Large diffs are not rendered by default.

198 changes: 87 additions & 111 deletions empire

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions lib/common/agents.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ def add_agent(self, sessionID, externalIP, delay, jitter, profile, killDate, wor
Add an agent to the internal cache and database.
"""

currentTime = helpers.get_datetime()
currentTime = helpers.getutcnow()
checkinTime = currentTime
lastSeenTime = currentTime

Expand All @@ -169,7 +169,7 @@ def add_agent(self, sessionID, externalIP, delay, jitter, profile, killDate, wor
signal = json.dumps({
'print': True,
'message': message,
'timestamp': checkinTime,
'timestamp': checkinTime.isoformat(),
'event_type': 'checkin'
})
dispatcher.send(signal, sender="agents/{}".format(sessionID))
Expand Down Expand Up @@ -923,7 +923,7 @@ def update_agent_lastseen_db(self, sessionID, current_time=None):
"""

if not current_time:
current_time = helpers.get_datetime()
current_time = helpers.getutcnow()
conn = self.get_db_connection()
try:
self.lock.acquire()
Expand Down Expand Up @@ -1067,7 +1067,7 @@ def add_agent_task_db(self, sessionID, taskName, task='',uid=None):
agentName = sessionID
# see if we were passed a name instead of an ID
nameid = self.get_agent_id_db(sessionID)
timestamp = helpers.get_datetime()
timestamp = helpers.getutcnow()

if nameid:
sessionID = nameid
Expand Down Expand Up @@ -1100,7 +1100,7 @@ def add_agent_task_db(self, sessionID, taskName, task='',uid=None):
if pk is None:
pk = 0
pk = (pk + 1) % 65536
cur.execute("INSERT INTO taskings (id, agent, data, user_id, time_stamp) VALUES(?, ?, ?, ?, ?)", [pk, sessionID, task[:100], uid, timestamp])
cur.execute("INSERT INTO taskings (id, agent, data, user_id, timestamp) VALUES(?, ?, ?, ?, ?)", [pk, sessionID, task[:100], uid, timestamp])

# Create result for data when it arrives
cur.execute("INSERT INTO results (id, agent, user_id) VALUES (?,?,?)", (pk, sessionID, uid))
Expand All @@ -1110,7 +1110,7 @@ def add_agent_task_db(self, sessionID, taskName, task='',uid=None):
cur.execute("UPDATE agents SET taskings=? WHERE session_id=?", [json.dumps(agent_tasks), sessionID])

# update last seen time for user
last_logon = helpers.get_datetime()
last_logon = helpers.getutcnow()
cur.execute("UPDATE users SET last_logon_time = ? WHERE id = ?",
(last_logon, uid))

Expand Down
43 changes: 18 additions & 25 deletions lib/common/empire.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from builtins import str
from builtins import range

VERSION = "3.2.2 BC-Security Fork"
VERSION = "3.2.3 BC-Security Fork"

from pydispatch import dispatcher

Expand Down Expand Up @@ -160,7 +160,7 @@ def handle_event(self, signal, sender):
# this should probably be set in the event itself but we can check
# here (and for most the time difference won't matter so it's fine)
if 'timestamp' not in signal_data:
signal_data['timestamp'] = helpers.get_datetime()
signal_data['timestamp'] = helpers.getutcnow().isoformat()

# if this is related to a task, set task_id; this is its own column in
# the DB (else the column will be set to None/null)
Expand Down Expand Up @@ -817,13 +817,9 @@ def do_list(self, line):
agentsToDisplay = []

for agent in allAgents:

# max check in -> delay + delay*jitter
intervalMax = (agent['delay'] + agent['delay'] * agent['jitter']) + 30

# get the agent last check in time
agentTime = time.mktime(time.strptime(agent['lastseen_time'], "%Y-%m-%d %H:%M:%S"))
if agentTime < time.mktime(time.localtime()) - intervalMax:
stale = helpers.is_stale(agent['lastseen_time', agent['delay'], agent['jitter']])

if not stale:
# if the last checkin time exceeds the limit, remove it
agentsToDisplay.append(agent)

Expand All @@ -838,9 +834,10 @@ def do_list(self, line):
# grab just the agents active within the specified window (in minutes)
agentsToDisplay = []
for agent in allAgents:
agentTime = time.mktime(time.strptime(agent['lastseen_time'], "%Y-%m-%d %H:%M:%S"))

if agentTime > time.mktime(time.localtime()) - (int(minutes) * 60):
diff = helpers.getutcnow() - agent['lastseen_time']
too_old = diff.total_seconds() > int(minutes) * 60

if not too_old:
agentsToDisplay.append(agent)

messages.display_agents(agentsToDisplay)
Expand Down Expand Up @@ -973,7 +970,7 @@ def do_report(self, line):
# Empire Log
cur.execute("""
SELECT
reporting.time_stamp,
reporting.timestamp,
event_type,
u.username,
substr(reporting.name, pos+1) as agent_name,
Expand All @@ -984,7 +981,7 @@ def do_report(self, line):
FROM
(
SELECT
time_stamp,
timestamp,
event_type,
name,
instr(name, '/') as pos,
Expand Down Expand Up @@ -1622,13 +1619,9 @@ def do_remove(self, line):

sessionID = agent['session_id']

# max check in -> delay + delay*jitter
intervalMax = (agent['delay'] + agent['delay'] * agent['jitter']) + 30
stale = helpers.is_stale(agent['lastseen_time'], agent['delay'], agent['jitter'])

# get the agent last check in time
agentTime = time.mktime(time.strptime(agent['lastseen_time'], "%Y-%m-%d %H:%M:%S"))

if agentTime < time.mktime(time.localtime()) - intervalMax:
if stale:
# if the last checkin time exceeds the limit, remove it
self.mainMenu.agents.remove_agent_db(sessionID)

Expand All @@ -1644,11 +1637,11 @@ def do_remove(self, line):
for agent in allAgents:

sessionID = agent['session_id']
# get the agent last check in time
agentTime = time.mktime(time.strptime(agent['lastseen_time'], "%Y-%m-%d %H:%M:%S"))
if agentTime < time.mktime(time.localtime()) - (int(minutes) * 60):

diff = helpers.getutcnow() - agent['lastseen_time']
too_old = diff.total_seconds() > int(minutes) * 60

if too_old:
# if the last checkin time exceeds the limit, remove it
self.mainMenu.agents.remove_agent_db(sessionID)

Expand Down
2 changes: 1 addition & 1 deletion lib/common/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def log_event(cur, name, event_type, message, timestamp, task_id=None):
queries of an agent's task and its result together.
"""
cur.execute(
"INSERT INTO reporting (name, event_type, message, time_stamp, taskID) VALUES (?,?,?,?,?)",
"INSERT INTO reporting (name, event_type, message, timestamp, taskID) VALUES (?,?,?,?,?)",
(
name,
event_type,
Expand Down
29 changes: 20 additions & 9 deletions lib/common/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@
import ipaddress
import simplejson as json

from datetime import datetime
from datetime import datetime, timezone

###############################################################
#
Expand Down Expand Up @@ -634,10 +634,12 @@ def get_listener_options(listenerName):

def get_datetime():
"""
Return the current date/time
Return the local current date/time
"""
return datetime.now().strftime("%Y-%m-%d %H:%M:%S")

def getutcnow():
return datetime.now(timezone.utc)

def utc_to_local(utc):
"""
Expand Down Expand Up @@ -752,27 +754,36 @@ def color(string, color=None):
return string


def is_stale(lastseen : datetime, delay: int, jitter: float):
"""Convenience function for calculating staleness"""
interval_max = (delay + delay * jitter) + 30
diff = getutcnow() - lastseen
stale = diff.total_seconds() > interval_max
return stale


def lastseen(stamp, delay, jitter):
"""
Colorize the Last Seen field based on measured delays
"""
try:
delta = datetime.now() - datetime.strptime(stamp, "%Y-%m-%d %H:%M:%S")
stamp_date = datetime.strptime(stamp, "%Y-%m-%d %H:%M:%S.%f%z")
delta = getutcnow() - stamp_date

# Set min threshold for delay/jitter
if delay < 1:
delay = 1
if jitter < 1:
jitter = 1

if delta.seconds > delay * (jitter + 1) * 7:
return color(stamp, "red")
elif delta.seconds > delay * (jitter + 1) * 3:
return color(stamp, "yellow")
if delta.total_seconds() > delay * (jitter + 1) * 7:
return color(stamp[:-13], "red")
elif delta.total_seconds() > delay * (jitter + 1) * 3:
return color(stamp[:-13], "yellow")
else:
return color(stamp, "green")
return color(stamp[:-13], "green")
except Exception:
return stamp
return stamp[:-13]


def unique(seq, idfun=None):
Expand Down
4 changes: 3 additions & 1 deletion lib/common/listeners.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
"""
from __future__ import print_function
from __future__ import absolute_import

from datetime import datetime
from builtins import filter
from builtins import str
from builtins import object
Expand Down Expand Up @@ -226,7 +228,7 @@ def start_listener(self, moduleName, listenerObject):
self.activeListeners[name] = {'moduleName': moduleName, 'options':listenerOptions}
pickledOptions = pickle.dumps(listenerObject.options)
cur = self.conn.cursor()
cur.execute("INSERT INTO listeners (name, module, listener_category, enabled, options) VALUES (?,?,?,?,?)", [name, moduleName, category, True, pickledOptions])
cur.execute("INSERT INTO listeners (name, module, listener_category, enabled, options, created_at) VALUES (?,?,?,?,?, ?)", [name, moduleName, category, True, pickledOptions, helpers.getutcnow()])
cur.close()

# dispatch this event
Expand Down
4 changes: 2 additions & 2 deletions lib/common/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def add_new_user(self, user_name, password):
"""
Add new user to cache
"""
last_logon = helpers.get_datetime()
last_logon = helpers.getutcnow()
conn = self.get_db_connection()
message = False

Expand Down Expand Up @@ -102,7 +102,7 @@ def disable_user(self, uid, disable):
return message

def user_login(self, user_name, password):
last_logon = helpers.get_datetime()
last_logon = helpers.getutcnow()
conn = self.get_db_connection()

try:
Expand Down
4 changes: 4 additions & 0 deletions lib/modules/powershell/code_execution/invoke_dllinjection.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ def __init__(self, mainMenu, params=[]):
'Description': ("Uses PowerSploit's Invoke-DLLInjection to inject "
" a Dll into the process ID of your choosing."),

'Software': 'S0194',

'Techniques': ['T1055', 'TA0001'],

'Background' : False,

'OutputExtension' : None,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ def __init__(self, mainMenu, params=[]):
'Description': ('Spawns a new, hidden PowerShell window that downloads'
'and executes a Metasploit payload. This relies on the'
'exploit/multi/scripts/web_delivery metasploit module.'),
'Software': '',
'Techniques': ['T1055', 'TA0001'],
'Background' : False,
'OutputExtension' : None,
'NeedsAdmin' : False,
Expand Down
6 changes: 5 additions & 1 deletion lib/modules/powershell/code_execution/invoke_ntsd.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ def __init__(self, mainMenu, params=[]):
'Author': ['james fitts'],

'Description': ("Use NT Symbolic Debugger to execute Empire launcher code"),


'Software': '',

'Techniques': ['T1127'],

'Background': True,

'OutputExtension': None,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ def __init__(self, mainMenu, params=[]):
"a DLL/EXE in to the PowerShell process or reflectively load a DLL in to a "
"remote process."),

'Software': 'S0194',

'Techniques': ['T1055', 'TA0001'],

'Background' : False,

'OutputExtension' : None,
Expand Down
4 changes: 4 additions & 0 deletions lib/modules/powershell/code_execution/invoke_shellcode.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ def __init__(self, mainMenu, params=[]):
"correct format and matches the architecture of the process "
"you're injecting into."),

'Software': 'S0194',

'Techniques': ['T1064'],

'Background' : True,

'OutputExtension' : None,
Expand Down
4 changes: 4 additions & 0 deletions lib/modules/powershell/code_execution/invoke_shellcodemsil.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ def __init__(self, mainMenu, params=[]):
'Note: Your shellcode must end in a ret (0xC3) and maintain proper stack '
'alignment or PowerShell will crash!'),

'Software': '',

'Techniques': ['T1064'],

'Background' : False,

'OutputExtension' : None,
Expand Down
4 changes: 4 additions & 0 deletions lib/modules/powershell/collection/ChromeDump.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ def __init__(self, mainMenu, params=[]):
# more verbose multi-line description of the module
'Description': ('This module will decrypt passwords saved in chrome and display them in the console.'),

'Software': '',

'Techniques': ['T1503'],

# True if the module needs to run in the background
'Background' : True,

Expand Down
4 changes: 4 additions & 0 deletions lib/modules/powershell/collection/FoxDump.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ def __init__(self, mainMenu, params=[]):
'Description': ('This module will dump any saved passwords from Firefox to the console. This should work for any version'
'of Firefox above version 32. This will only be successful if the master password is blank or has not been set.'),

'Software': '',

'Techniques': ['T1503'],

# True if the module needs to run in the background
'Background' : True,

Expand Down
4 changes: 4 additions & 0 deletions lib/modules/powershell/collection/SharpChromium.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ def __init__(self, mainMenu, params=[]):
# more verbose multi-line description of the module
'Description': ('This module will retrieve cookies, history, saved logins from Google Chrome, Microsoft Edge, and Microsoft Edge Beta.'),

'Software': '',

'Techniques': ['T1503'],

# True if the module needs to run in the background
'Background' : True,

Expand Down
Loading

0 comments on commit d6c8c9e

Please sign in to comment.