Skip to content

Commit

Permalink
Merge pull request #229 from BC-SECURITY/sponsors-dev
Browse files Browse the repository at this point in the history
Empire 4.1.1 Release
  • Loading branch information
vinnybod authored Sep 20, 2021
2 parents 04e8318 + 907e232 commit cf9b233
Show file tree
Hide file tree
Showing 50 changed files with 1,500 additions and 697 deletions.
4 changes: 3 additions & 1 deletion .github/workflows/dockerimage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v2
with:
submodules: 'recursive'
- name: Publish Docker
if: ${{ github.repository == 'BC-SECURITY/Empire' }}
uses: elgohr/[email protected]
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ BC Security presented updates to further evade Microsoft Antimalware Scan Interf
[DEF CON 27](https://github.com/BC-SECURITY/DEFCON27).

Empire relies heavily on the work from several other projects for its underlying functionality. We have tried to call
out a few of those people we've interacted with [heavily here](http://www.powershellempire.com/?page_id=2) and have
out a few of those people we've interacted with heavily [here](http://www.powershellempire.com/?page_id=2) and have
included author/reference link information in the source of each Empire module as appropriate. If we have failed to
properly cite existing or prior work, please let us know at [email protected].

Expand Down Expand Up @@ -90,10 +90,10 @@ Join us in [our Discord](https://discord.gg/P8PZPyf) to with any comments, quest
Contributions are more than welcome! The more people who contribute to the project the better Empire will be for everyone. Below are a few guidelines for submitting contributions.

* Submit pull requests to the [dev branch](https://github.com/BC-SECURITY/Empire/tree/dev). After testing, changes will be merged to master.
* Depending on what you're working on, base your module on [./lib/modules/powershell_template.py](empire/teamserver/lib/modules/powershell_template.py) or [./lib/modules/python_template.py](empire/teamserver/lib/modules/python_template.py). **Note** that for some modules you may need to massage the output to get it into a nicely displayable text format [with Out-String](https://github.com/PowerShellEmpire/Empire/blob/0cbdb165a29e4a65ad8dddf03f6f0e36c33a7350/lib/modules/situational_awareness/network/powerview/get_user.py#L111).
* Depending on what you're working on, base your module on [powershell_template.py](https://github.com/BC-SECURITY/Empire/blob/master/empire/server/modules/powershell_template.py) or [python_template.py](https://github.com/BC-SECURITY/Empire/blob/master/empire/server/modules/python_template.py). **Note** that for some modules you may need to massage the output to get it into a nicely displayable text format with [Out-String](https://github.com/PowerShellEmpire/Empire/blob/0cbdb165a29e4a65ad8dddf03f6f0e36c33a7350/lib/modules/situational_awareness/network/powerview/get_user.py#L111).
* Cite previous work in the **'Comments'** module section.
* If your script.ps1 logic is large, may be reused by multiple modules, or is updated often, consider implementing the logic in the appropriate **data/module_source/*** directory and [pulling the script contents into the module on tasking](https://github.com/PowerShellEmpire/Empire/blob/0cbdb165a29e4a65ad8dddf03f6f0e36c33a7350/lib/modules/situational_awareness/network/powerview/get_user.py#L85-L95).
* Use [approved PowerShell verbs](https://technet.microsoft.com/en-us/library/ms714428(v=vs.85).aspx) for any functions.
* Use [approved PowerShell verbs](https://docs.microsoft.com/en-us/powershell/scripting/developer/cmdlet/approved-verbs-for-windows-powershell-commands?view=powershell-7.1) for any functions.
* TEST YOUR MODULE! Be sure to run it from an Empire agent and test Python 3.x functionality before submitting a pull to ensure everything is working correctly.
* For additional guidelines for your PowerShell code itself, check out the [PowerSploit style guide](https://github.com/PowerShellMafia/PowerSploit/blob/master/README.md).

Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
4.1.0
4.1.1
12 changes: 12 additions & 0 deletions changelog
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
9/20/2021
------------
- Version 4.1.1 Master Release
- Add OutputFunction to dcsync_hashdump (@jamarir)
- Convert file operations to use with syntax (@jamarir)
- Added Invoke-IronPython3 and some OffensiveDLR fixes (@Cx01N)
- Fix for (#476) - String indices error ms16-032 & ms16-135 (@Cx01N)
- Fix help menu text on the interact menu (@archcloudlabs)
- Rework agent taskings in the client to not poll for a result (@Cx01N)
- Added Python agents to the external/generate_agent module (@Cx01N)
- Update add_sid_history module command (@ilanisme)

8/29/2021
------------
- Version 4.1.0 Master Release
Expand Down
10 changes: 10 additions & 0 deletions empire/client/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,13 @@ shortcuts:
params:
- name: LogFile
dynamic: true
ironpython:
whoami:
shell: whoami
ps:
shell: ps
csharp:
whoami:
shell: whoami
ps:
shell: ps
3 changes: 2 additions & 1 deletion empire/client/src/EmpireCliState.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,8 @@ def add_to_cached_results(self, data) -> None:
if menu_state.current_menu_name == 'InteractMenu' and menu_state.current_menu.selected == session_id:
if data['results'] is not None:
print(print_util.color('[*] Task ' + str(data['taskID']) + " results received"))
print(print_util.color(data['results']))
for line in data['results'].split('\n'):
print(print_util.color(line))
else:
self.cached_agent_results[session_id][data['taskID']] = data['results']

Expand Down
17 changes: 16 additions & 1 deletion empire/client/src/ShortcutHandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,35 @@ class ShortcutHandler:
def __init__(self):
shortcuts_raw = empire_config.yaml.get('shortcuts', {})
python: Dict[str, Shortcut] = {}
ironpython: Dict[str, Shortcut] = {}
powershell: Dict[str, Shortcut] = {}
csharp: Dict[str, Shortcut] = {}
for key, value in shortcuts_raw['python'].items():
try:
value['name'] = key
python[key] = Shortcut.from_json(json.loads(json.dumps(value)))
except TypeError as e:
print(print_util.color(f'Could not parse shortcut: {key}', color_name='red'))
for key, value in shortcuts_raw['ironpython'].items():
try:
value['name'] = key
ironpython[key] = Shortcut.from_json(json.loads(json.dumps(value)))
except TypeError as e:
print(print_util.color(f'Could not parse shortcut: {key}', color_name='red'))
for key, value in shortcuts_raw['powershell'].items():
try:
value['name'] = key
powershell[key] = Shortcut.from_json(json.loads(json.dumps(value)))
except TypeError as e:
print(print_util.color(f'Could not parse shortcut: {key}', color_name='red'))
self.shortcuts: Dict[str, Dict[str, Shortcut]] = {'python': python, 'powershell': powershell}
for key, value in shortcuts_raw['csharp'].items():
try:
value['name'] = key
csharp[key] = Shortcut.from_json(json.loads(json.dumps(value)))
except TypeError as e:
print(print_util.color(f'Could not parse shortcut: {key}', color_name='red'))
self.shortcuts: Dict[str, Dict[str, Shortcut]] = {'python': python, 'powershell': powershell,
'ironpython': ironpython, 'csharp': csharp}

def get(self, language: str, name: str) -> Shortcut:
return self.shortcuts.get(language, {}).get(name)
Expand Down
25 changes: 16 additions & 9 deletions empire/client/src/menus/InteractMenu.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import base64
import os
import textwrap
import threading
import time
from typing import List

from prompt_toolkit.completion import Completion
Expand Down Expand Up @@ -142,8 +140,8 @@ def upload(self, local_file_directory: str, destination_file_name: str) -> None:
Usage: upload <local_file_directory> [destination_file_name]
"""
file_name = os.path.basename(local_file_directory)
open_file = open(local_file_directory, 'rb')
file_data = base64.b64encode(open_file.read())
with open(local_file_directory, 'rb') as open_file:
file_data = base64.b64encode(open_file.read())

if destination_file_name:
file_name = destination_file_name
Expand Down Expand Up @@ -284,8 +282,12 @@ def history(self, number_tasks: int):
if 'agent' in response.keys():
tasks = response['agent']
for task in tasks:
print(print_util.color('[*] Task ' + str(task['taskID']) + " results received"))
print(print_util.color(task['results']))
if task.get('results'):
print(print_util.color(f'[*] Task {task["taskID"]} results received'))
for line in task.get('results', '').split('\n'):
print(print_util.color(line))
else:
print(print_util.color(f'[!] Task {task["taskID"]} No tasking results received'))
elif 'error' in response.keys():
print(print_util.color('[!] Error: ' + response['error']))

Expand All @@ -296,11 +298,16 @@ def view(self, task_id: str):
Usage: view <task_id>
"""
task = state.get_agent_task(self.session_id,task_id)
task = state.get_agent_task(self.session_id, task_id)
record_list = []
for key, value in task.items():
record_list.append([print_util.color(key, 'blue'), value])
table_util.print_table(record_list, 'View Task', colored_header=False, no_borders=True)
# If results exceed a certain length they break the table function
if key != 'results':
record_list.append([print_util.color(key, 'blue'), value])
table_util.print_table(record_list, 'View Task', colored_header=False, no_borders=True, end_space=False)
print(print_util.color(" results", "blue"))
for line in task['results'].split('\n'):
print(print_util.color(line))

def execute_shortcut(self, command_name: str, params: List[str]):
shortcut: Shortcut = shortcut_handler.get(self.agent_language, command_name)
Expand Down
2 changes: 1 addition & 1 deletion empire/client/src/menus/MainMenu.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ def help(self):
help_list.append(['usemodule', 'Use an Empire module.', 'usemodule <module_name>'])
help_list.append(['credentials', 'Add/display credentials to/from the database.', 'credentials'])
help_list.append(['admin', 'View admin menu', 'admin'])
help_list.append(['interact', 'Interact with active listeners.', 'interact <agent_name>'])
help_list.append(['interact', 'Interact with active agents.', 'interact <agent_name>'])
help_list.append(['sponsors', 'List of Empire sponsors.', 'sponsors'])

help_list.sort()
Expand Down
35 changes: 9 additions & 26 deletions empire/client/src/menus/UseModuleMenu.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import threading
import time

from prompt_toolkit.completion import Completion

from empire.client.src.EmpireCliState import state
from empire.client.src.MenuState import menu_state
from empire.client.src.menus.UseMenu import UseMenu
from empire.client.src.utils import print_util
from empire.client.src.utils.autocomplete_util import filtered_search_list, position_util
Expand Down Expand Up @@ -68,11 +66,14 @@ def execute(self):

response = state.execute_module(self.selected, post_body)
if 'success' in response.keys():
print(print_util.color(
'[*] Tasked ' + self.record_options['Agent']['Value'] + ' to run Task ' + str(response['taskID'])))
shell_return = threading.Thread(target=self.tasking_id_returns, args=[response['taskID']])
shell_return.daemon = True
shell_return.start()
if 'Agent' in post_body.keys():
print(print_util.color(
'[*] Tasked ' + self.record_options['Agent']['Value'] + ' to run Task ' + str(response['taskID'])))
menu_state.pop()
else:
print(print_util.color(
'[*] ' + str(response['msg'])))

elif 'error' in response.keys():
if response['error'].startswith('[!]'):
msg = response['error']
Expand All @@ -89,23 +90,5 @@ def generate(self):
"""
self.execute()

def tasking_id_returns(self, task_id: int):
"""
Polls for the tasks that have been queued.
Once found, will remove from the cache and display.
"""
count = 0
result = None
while result is None and count < 30 and not self.stop_threads:
# this may not work 100% of the time since there is a mix of agent session_id and names still.
result = state.cached_agent_results.get(self.record_options['Agent']['Value'], {}).get(task_id)
count += 1
time.sleep(1)

if result:
del state.cached_agent_results.get(self.record_options['Agent']['Value'], {})[task_id]

print(print_util.color(result))


use_module_menu = UseModuleMenu()
5 changes: 2 additions & 3 deletions empire/client/src/menus/UseStagerMenu.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,8 @@ def execute(self):
return
file_name = response[self.selected].get('OutFile').get('Value').split('/')[-1]
output_bytes = base64.b64decode(response[self.selected]['Output'])
file = open(f'empire/client/generated-stagers/{file_name}', 'wb')
file.write(output_bytes)
file.close()
with open(f'empire/client/generated-stagers/{file_name}', 'wb') as f:
f.write(output_bytes)
print(print_util.color(f'[*] {file_name} written to {os.path.abspath(file.name)}'))
else:
print(print_util.color(response[self.selected]['Output']))
Expand Down
11 changes: 7 additions & 4 deletions empire/client/src/utils/table_util.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
from datetime import datetime
from typing import List

from terminaltables import SingleTable

import empire.client.src.utils.print_util as print_utils


def print_table(data: List[List[str]] = None, title: str = '', colored_header: bool = True, no_borders: bool = False):
def print_table(data: List[List[str]] = None, title: str = '', colored_header: bool = True, no_borders: bool = False,
end_space: bool = True):
if data is None:
return

Expand All @@ -28,7 +28,10 @@ def print_table(data: List[List[str]] = None, title: str = '', colored_header: b

print('')
print(table.table)
print('')

if end_space:
print('')


def print_agent_table(data: List[List[str]] = None, formatting: List[List[str]] = None, title: str = ''):
if data is None:
Expand Down Expand Up @@ -59,4 +62,4 @@ def print_agent_table(data: List[List[str]] = None, formatting: List[List[str]]

print('')
print(table.table)
print('')
print('')
21 changes: 9 additions & 12 deletions empire/server/common/agents.py
Original file line number Diff line number Diff line change
Expand Up @@ -374,10 +374,8 @@ def save_module_file(self, sessionID, path, data):
os.makedirs(save_path)

# save the file out
f = open("%s/%s" % (save_path, filename), 'wb')

f.write(data)
f.close()
with open("%s/%s" % (save_path, filename), 'wb') as f:
f.write(data)
finally:
self.lock.release()

Expand Down Expand Up @@ -409,10 +407,9 @@ def save_agent_log(self, sessionID, data):
try:
self.lock.acquire()

f = open("%s/agent.log" % (save_path), 'a')
f.write("\n" + current_time + " : " + "\n")
f.write(data + "\n")
f.close()
with open("%s/agent.log" % (save_path), 'a') as f:
f.write("\n" + current_time + " : " + "\n")
f.write(data + "\n")
finally:

self.lock.release()
Expand Down Expand Up @@ -912,9 +909,8 @@ def add_agent_task_db(self, session_id, task_name, task='', module_name=None, ui

# write out the last tasked script to "LastTask" if in debug mode
if self.args and self.args.debug:
f = open('%s/LastTask' % (self.installPath), 'w')
f.write(task)
f.close()
with open('%s/LastTask' % (self.installPath), 'w') as f:
f.write(task)
finally:
self.lock.release()

Expand Down Expand Up @@ -1366,7 +1362,8 @@ def handle_agent_request(self, sessionID, language, stagingKey, update_lastseen=
for tasking in taskings:
input_full = tasking.input_full
if tasking.task_name == "TASK_CSHARP":
input_full = open(tasking.input_full.split("|")[0], "rb").read()
with open(tasking.input_full.split("|")[0], "rb") as f:
input_full = f.read()
input_full = base64.b64encode(input_full).decode("UTF-8")
input_full += tasking.input_full.split("|", maxsplit=1)[1]
all_task_packets += packets.build_task_packet(tasking.task_name, input_full, tasking.id)
Expand Down
11 changes: 5 additions & 6 deletions empire/server/common/credentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,10 +162,9 @@ def export_credentials(self, export_path=''):
print(helpers.color("[!] No credentials in the database."))
return

output_file = open(export_path, 'w')
output_file.write("CredID,CredType,Domain,Username,Password,Host,OS,SID,Notes\n")
for cred in creds:
output_file.write("\"%s\"\n" % ('","'.join([str(x) for x in cred])))
with open(export_path, 'w') as output_file:
output_file.write("CredID,CredType,Domain,Username,Password,Host,OS,SID,Notes\n")
for cred in creds:
output_file.write("\"%s\"\n" % ('","'.join([str(x) for x in cred])))

print("\n" + helpers.color("[*] Credentials exported to %s\n" % (export_path)))
output_file.close()
print("\n" + helpers.color("[*] Credentials exported to %s\n" % (export_path)))
Loading

0 comments on commit cf9b233

Please sign in to comment.