Skip to content

Commit

Permalink
Merge pull request #202 from BC-SECURITY/sponsors-dev
Browse files Browse the repository at this point in the history
4.0.2 Release
  • Loading branch information
Cx01N authored Aug 17, 2021
2 parents 886e513 + b71ce77 commit ce332b5
Show file tree
Hide file tree
Showing 58 changed files with 2,519 additions and 2,069 deletions.
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
4.0.1
4.0.2
16 changes: 16 additions & 0 deletions changelog
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
8/16/2021
------------
- Version 4.0.2 Master Release
- Added socketio messages to screenshot/download/upload (@Cx01N)
- Added help message when no input is given to empire.py (@Cx01N)
- Fixed missing slash for module directories (@Cx01N)
- Fixed modules Get-SQLServerLoginDefaultPw and PortScan (@jamarir)
- Fixed formatting bug in the options table on the listener menu (@Vinnybod)
- Fixed querying retain-last-value config parameters (@ilanisme)
- Fixed invalid concat on keylogs (@Cx01N)
- Fixed mimikatz command and added suggested values (@Cx01N)
- Fixed misc bugs (@Vinnybod)
- Updated suggested values for stagers and reformatted code (@Cx01N)
- Updated editlistener menu (@Vinnybod)
- Removed client suppression for job started taskings (@Cx01N)

7/19/2021
------------
- Version 4.0.1 Master Release
Expand Down
3 changes: 3 additions & 0 deletions empire/arguments.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,6 @@
help='Start the RESTful API with the specified password instead of pulling from empire.db')

args = parent_parser.parse_args()

if parent_parser.parse_args().subparser_name == None:
parent_parser.print_help()
28 changes: 18 additions & 10 deletions empire/client/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
from empire.client.src.menus.MainMenu import main_menu
from empire.client.src.menus.PluginMenu import plugin_menu
from empire.client.src.menus.ShellMenu import shell_menu
from empire.client.src.menus.EditListenerMenu import edit_listener_menu
from empire.client.src.menus.UseListenerMenu import use_listener_menu
from empire.client.src.menus.UseModuleMenu import use_module_menu
from empire.client.src.menus.UsePluginMenu import use_plugin_menu
Expand Down Expand Up @@ -90,6 +91,7 @@ def __init__(self) -> None:
'ListenerMenu': listener_menu,
'UseCredentialMenu': use_credential_menu,
'UseListenerMenu': use_listener_menu,
'EditListenerMenu': edit_listener_menu,
'UseStagerMenu': use_stager_menu,
'AgentMenu': agent_menu,
'UseModuleMenu': use_module_menu,
Expand Down Expand Up @@ -220,25 +222,25 @@ def parse_command_line(self, text: str, cmd_line: List[str], resource_file=False
return

# Switch Menus
if text == 'main':
if text.strip() == 'main':
state.get_modules()
state.get_listeners()
print_util.title(state.empire_version, len(state.modules), len(state.listeners),
len(state.get_active_agents()))
menu_state.push(self.menus['MainMenu'])
elif text == 'listeners':
elif text.strip() == 'listeners':
menu_state.push(self.menus['ListenerMenu'])
elif text == 'chat':
elif text.strip() == 'chat':
menu_state.push(self.menus['ChatMenu'])
elif menu_state.current_menu_name == 'ChatMenu':
menu_state.current_menu.send_chat(text)
elif text == 'agents':
elif text.strip() == 'agents':
menu_state.push(self.menus['AgentMenu'])
elif text == 'credentials':
elif text.strip() == 'credentials':
menu_state.push(self.menus['CredentialMenu'])
elif text == 'plugins':
elif text.strip() == 'plugins':
menu_state.push(self.menus['PluginMenu'])
elif text == 'admin':
elif text.strip() == 'admin':
menu_state.push(self.menus['AdminMenu'])
elif cmd_line[0] == 'uselistener' and len(cmd_line) > 1:
if cmd_line[1] in state.listener_types:
Expand Down Expand Up @@ -274,7 +276,13 @@ def parse_command_line(self, text: str, cmd_line: List[str], resource_file=False
menu_state.push(self.menus['UseModuleMenu'], selected=cmd_line[1])
else:
print(f'No module {cmd_line[1]}')
elif text == 'shell':
elif cmd_line[0] == 'editlistener' and len(cmd_line) > 1:
if menu_state.current_menu_name == 'ListenerMenu':
if cmd_line[1] in state.listeners:
menu_state.push(self.menus['EditListenerMenu'], selected=cmd_line[1])
else:
print(f'No listener {cmd_line[1]}')
elif text.strip() == 'shell':
if menu_state.current_menu_name == 'InteractMenu':
menu_state.push(self.menus['ShellMenu'], selected=menu_state.current_menu.selected)
else:
Expand All @@ -284,9 +292,9 @@ def parse_command_line(self, text: str, cmd_line: List[str], resource_file=False
menu_state.push(self.menus['InteractMenu'], selected=menu_state.current_menu.selected)
else:
menu_state.current_menu.shell(menu_state.current_menu.selected, text)
elif text == 'back':
elif text.strip() == 'back':
menu_state.pop()
elif text == 'exit':
elif text.strip() == 'exit':
if resource_file:
raise CliExitException
choice = input(print_util.color("[>] Exit? [y/N] ", "red"))
Expand Down
30 changes: 25 additions & 5 deletions empire/client/src/EmpireCliState.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,12 +134,10 @@ 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:
if 'Job started:' not in data['results']:
print(print_util.color('[*] Task ' + str(data['taskID']) + " results received"))
print(print_util.color(data['results']))
print(print_util.color('[*] Task ' + str(data['taskID']) + " results received"))
print(print_util.color(data['results']))
else:
if 'Job started:' not in data['results']:
self.cached_agent_results[session_id][data['taskID']] = data['results']
self.cached_agent_results[session_id][data['taskID']] = data['results']

def add_plugin_cache(self, data) -> None:
"""
Expand Down Expand Up @@ -200,6 +198,28 @@ def kill_listener(self, listener_name: str):

return response.json()

def disable_listener(self, listener_name: str):
response = requests.put(url=f'{self.host}:{self.port}/api/listeners/{listener_name}/disable',
verify=False,
params={'token': self.token})
self.get_listeners()
return response.json()

def enable_listener(self, listener_name: str):
response = requests.put(url=f'{self.host}:{self.port}/api/listeners/{listener_name}/enable',
verify=False,
params={'token': self.token})
self.get_listeners()
return response.json()

def edit_listener(self, listener_name: str, option_name, option_value):
response = requests.put(url=f'{self.host}:{self.port}/api/listeners/{listener_name}/edit',
json={'option_name': option_name, 'option_value': option_value},
verify=False,
params={'token': self.token})

return response.json()

def get_listener_types(self):
response = requests.get(url=f'{self.host}:{self.port}/api/listeners/types',
verify=False,
Expand Down
124 changes: 124 additions & 0 deletions empire/client/src/menus/EditListenerMenu.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import textwrap

from prompt_toolkit.completion import Completion

from empire.client.src.EmpireCliState import state
from empire.client.src.menus.UseMenu import UseMenu
from empire.client.src.utils import print_util, table_util
from empire.client.src.utils.autocomplete_util import filtered_search_list, position_util
from empire.client.src.utils.cli_util import register_cli_commands, command


@register_cli_commands
class EditListenerMenu(UseMenu):
def __init__(self):
super().__init__(display_name='editlistener', selected='', record=None, record_options=None)

def autocomplete(self):
return self._cmd_registry + super().autocomplete()

def get_completions(self, document, complete_event, cmd_line, word_before_cursor):
yield from super().get_completions(document, complete_event, cmd_line, word_before_cursor)

def on_enter(self, **kwargs) -> bool:
if 'selected' not in kwargs:
return False
else:
self.use(kwargs['selected'])
self.info()
self.options()
return True

def use(self, name: str) -> None:
"""
Use the selected listener
Usage: use <name>
"""
if name not in state.listeners:
return None

self.selected = name
listener = state.listeners[self.selected]
self.record_options = listener['options']
self.record = state.get_listener_options(listener['module'])['listenerinfo']

@command
def set(self, key: str, value: str):
"""
Edit a field for the current record
Usage: set <key> <value>
"""
if not state.listeners[self.selected]['enabled']:
if value.startswith("\"") and value.endswith("\""):
value = value[1:-1]
if key in self.record_options:
response = state.edit_listener(self.selected, key, value)
if 'success' in response.keys():
state.listeners[self.selected]['options'][key]['Value'] = value
print(print_util.color(f'[*] Updated listener {self.selected}: {key} to {value}'))
elif 'error' in response.keys():
print(print_util.color('[!] Error: ' + response['error']))
else:
print(print_util.color(f'Could not find field: {key}'))
else:
print(print_util.color(f'[!] Listener must be disabled before edits'))

@command
def unset(self, key: str):
"""
Unset a record option.
Usage: unset <key>
"""
if key in self.record_options:
if self.record_options[key]['Required']:
print(print_util.color(f'[!] Cannot unset required field'))
return
else:
self.set(key, '')
else:
print(print_util.color(f'Could not find field: {key}'))

@command
def kill(self) -> None:
"""
Kill the selected listener
Usage: kill
"""
response = state.kill_listener(self.selected)
if 'success' in response.keys():
print(print_util.color('[*] Listener ' + self.selected + ' killed'))
elif 'error' in response.keys():
print(print_util.color('[!] Error: ' + response['error']))

@command
def enable(self) -> None:
"""
Enable the selected listener
Usage: enable
"""
response = state.enable_listener(self.selected)
if 'success' in response.keys():
print(print_util.color('[*] Listener ' + self.selected + ' enabled'))
elif 'error' in response.keys():
print(print_util.color('[!] Error: ' + response['error']))

@command
def disable(self) -> None:
"""
Disable the selected listener
Usage: disable
"""
response = state.disable_listener(self.selected)
if 'success' in response.keys():
print(print_util.color('[*] Listener ' + self.selected + ' disabled'))
elif 'error' in response.keys():
print(print_util.color('[!] Error: ' + response['error']))


edit_listener_menu = EditListenerMenu()
69 changes: 56 additions & 13 deletions empire/client/src/menus/ListenerMenu.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from empire.client.src.EmpireCliState import state
from empire.client.src.menus.Menu import Menu
from empire.client.src.utils import table_util, date_util
from empire.client.src.utils import table_util, date_util, print_util
from empire.client.src.utils.autocomplete_util import filtered_search_list, position_util
from empire.client.src.utils.cli_util import register_cli_commands, command

Expand All @@ -19,9 +19,12 @@ def autocomplete(self):
return self._cmd_registry + super().autocomplete()

def get_completions(self, document, complete_event, cmd_line, word_before_cursor):
if cmd_line[0] in ['kill', 'options'] and position_util(cmd_line, 2, word_before_cursor):
if cmd_line[0] in ['kill', 'options', 'enable', 'disable'] and position_util(cmd_line, 2, word_before_cursor):
for listener in filtered_search_list(word_before_cursor, state.listeners.keys()):
yield Completion(listener, start_position=-len(word_before_cursor))
elif cmd_line[0] == 'editlistener' and position_util(cmd_line, 2, word_before_cursor):
for listener in filtered_search_list(word_before_cursor, sorted(state.listeners.keys())):
yield Completion(listener, start_position=-len(word_before_cursor))
elif position_util(cmd_line, 1, word_before_cursor):
yield from super().get_completions(document, complete_event, cmd_line, word_before_cursor)

Expand All @@ -36,9 +39,9 @@ def list(self) -> None:
Usage: list
"""
listener_list = list(map(lambda x: [x['ID'], x['name'], x['module'], x['listener_category'], date_util.humanize_datetime(x['created_at'])],
listener_list = list(map(lambda x: [x['ID'], x['name'], x['module'], x['listener_category'], date_util.humanize_datetime(x['created_at']), x['enabled']],
state.listeners.values()))
listener_list.insert(0, ['ID', 'Name', 'Module', 'Listener Category', 'Created At'])
listener_list.insert(0, ['ID', 'Name', 'Module', 'Listener Category', 'Created At', 'Enabled'])

table_util.print_table(listener_list, 'Listeners List')

Expand All @@ -52,17 +55,17 @@ def options(self, listener_name: str) -> None:
if listener_name not in state.listeners:
return None

listener_list = []

record_list = []
for key, value in state.listeners[listener_name]['options'].items():
values = list(map(lambda x: '\n'.join(textwrap.wrap(str(x), width=40)), value.values()))
values.reverse()
temp = [key] + values
listener_list.append(temp)
name = key
record_value = print_util.text_wrap(value.get('Value', ''))
required = print_util.text_wrap(value.get('Required', ''))
description = print_util.text_wrap(value.get('Description', ''))
record_list.append([name, record_value, required, description])

listener_list.insert(0, ['Name', 'Value', 'Required', 'Description'])
record_list.insert(0, ['Name', 'Value', 'Required', 'Description'])

table_util.print_table(listener_list, listener_name)
table_util.print_table(record_list, 'Record Options')

@command
def kill(self, listener_name: str) -> None:
Expand All @@ -71,7 +74,47 @@ def kill(self, listener_name: str) -> None:
Usage: kill <listener_name>
"""
state.kill_listener(listener_name)
response = state.kill_listener(listener_name)
if 'success' in response.keys():
print(print_util.color('[*] Listener ' + listener_name + ' killed'))
elif 'error' in response.keys():
print(print_util.color('[!] Error: ' + response['error']))

@command
def enable(self, listener_name: str) -> None:
"""
Enable the selected listener
Usage: enable <listener_name>
"""
response = state.enable_listener(listener_name)
if 'success' in response.keys():
print(print_util.color('[*] Listener ' + listener_name + ' enabled'))
elif 'error' in response.keys():
print(print_util.color('[!] Error: ' + response['error']))

@command
def disable(self, listener_name: str) -> None:
"""
Disable the selected listener
Usage: disable <listener_name>
"""
response = state.disable_listener(listener_name)
if 'success' in response.keys():
print(print_util.color('[*] Listener ' + listener_name + ' disabled'))
elif 'error' in response.keys():
print(print_util.color('[!] Error: ' + response['error']))

@command
def editlistener(self, listener_name: str) -> None:
"""
Edit the selected listener
Usage: editlistener <listener_name>
"""
# Empty so the menu can see the option and usage
pass


listener_menu = ListenerMenu()
Loading

0 comments on commit ce332b5

Please sign in to comment.