diff --git a/monkey/common/data/post_breach_consts.py b/monkey/common/data/post_breach_consts.py index dee4f67d0..1e36f9e20 100644 --- a/monkey/common/data/post_breach_consts.py +++ b/monkey/common/data/post_breach_consts.py @@ -1,3 +1,4 @@ POST_BREACH_COMMUNICATE_AS_NEW_USER = "Communicate as new user" POST_BREACH_BACKDOOR_USER = "Backdoor user" POST_BREACH_FILE_EXECUTION = "File execution" +POST_BREACH_SHELL_STARTUP_FILE_MODIFICATION = "Modify shell startup file" diff --git a/monkey/infection_monkey/post_breach/actions/modify_shell_startup_files.py b/monkey/infection_monkey/post_breach/actions/modify_shell_startup_files.py new file mode 100644 index 000000000..a2d92db6c --- /dev/null +++ b/monkey/infection_monkey/post_breach/actions/modify_shell_startup_files.py @@ -0,0 +1,32 @@ +from common.data.post_breach_consts import POST_BREACH_SHELL_STARTUP_FILE_MODIFICATION +from infection_monkey.post_breach.pba import PBA +from infection_monkey.utils.shell_startup_files_modification import\ + get_commands_to_modify_shell_startup_files +from infection_monkey.utils.environment import is_windows_os + + +class ModifyShellStartupFiles(PBA): + """ + This PBA attempts to modify shell startup files, + like ~/.profile, ~/.bashrc, ~/.bash_profile in linux, + and profile.ps1 in windows. + """ + + def __init__(self): + super(ModifyShellStartupFiles, self).__init__(name=POST_BREACH_SHELL_STARTUP_FILE_MODIFICATION) + + def run(self): + (cmds_for_linux, shell_startup_files_for_linux), windows_cmds = get_commands_to_modify_shell_startup_files() + + if is_windows_os(): + super(ModifyShellStartupFiles, self).__init__(name=POST_BREACH_SHELL_STARTUP_FILE_MODIFICATION, + linux_cmd=' '.join(linux_cmds), + windows_cmd=windows_cmds) + super(ModifyShellStartupFiles, self).run() + else: + for shell_startup_file in shell_startup_files_for_linux: + linux_cmds = ' '.join(cmds_for_linux).format(shell_startup_file) + super(ModifyShellStartupFiles, self).__init__(name=POST_BREACH_SHELL_STARTUP_FILE_MODIFICATION, + linux_cmd=linux_cmds, + windows_cmd=windows_cmds) + super(ModifyShellStartupFiles, self).run() diff --git a/monkey/infection_monkey/utils/linux/shell_startup_files_modification.py b/monkey/infection_monkey/utils/linux/shell_startup_files_modification.py new file mode 100644 index 000000000..f6f8c3ffd --- /dev/null +++ b/monkey/infection_monkey/utils/linux/shell_startup_files_modification.py @@ -0,0 +1,16 @@ +BASH_STARTUP_FILES = ["~/.bashrc", "~/.profile", "~/.bash_profile"] + + +def get_linux_commands_to_modify_shell_startup_files(): + return [ + 'if [ -f {0} ] ;', # does the file exist? + 'then', + 'echo \"# Succesfully modified {0}\" |', + 'tee -a', + '{0}', # add comment to file + '&&', + 'sed -i \'$d\' {0} ;', # remove last line of file + 'else', + 'echo \"{0} does not exist\" ; fi' # mention if file does not exist + ],\ + BASH_STARTUP_FILES diff --git a/monkey/infection_monkey/utils/shell_startup_files_modification.py b/monkey/infection_monkey/utils/shell_startup_files_modification.py new file mode 100644 index 000000000..c97ca34b7 --- /dev/null +++ b/monkey/infection_monkey/utils/shell_startup_files_modification.py @@ -0,0 +1,10 @@ +from infection_monkey.utils.linux.shell_startup_files_modification import\ + get_linux_commands_to_modify_shell_startup_files +from infection_monkey.utils.windows.shell_startup_files_modification import\ + get_windows_commands_to_modify_shell_startup_files + + +def get_commands_to_modify_shell_startup_files(): + linux_cmds = get_linux_commands_to_modify_shell_startup_files() + windows_cmds = get_windows_commands_to_modify_shell_startup_files() + return linux_cmds, windows_cmds diff --git a/monkey/infection_monkey/utils/windows/shell_startup_files_modification.py b/monkey/infection_monkey/utils/windows/shell_startup_files_modification.py new file mode 100644 index 000000000..efc9480d8 --- /dev/null +++ b/monkey/infection_monkey/utils/windows/shell_startup_files_modification.py @@ -0,0 +1,3 @@ +def get_windows_commands_to_modify_shell_startup_files(): + # TODO: add for powershell + return 'dir' diff --git a/monkey/monkey_island/cc/services/attack/attack_report.py b/monkey/monkey_island/cc/services/attack/attack_report.py index c7130158b..7f8576941 100644 --- a/monkey/monkey_island/cc/services/attack/attack_report.py +++ b/monkey/monkey_island/cc/services/attack/attack_report.py @@ -4,7 +4,7 @@ from monkey_island.cc.models import Monkey from monkey_island.cc.services.attack.technique_reports import T1210, T1197, T1110, T1075, T1003, T1059, T1086, T1082 from monkey_island.cc.services.attack.technique_reports import T1145, T1105, T1065, T1035, T1129, T1106, T1107, T1188 from monkey_island.cc.services.attack.technique_reports import T1090, T1041, T1222, T1005, T1018, T1016, T1021, T1064 -from monkey_island.cc.services.attack.technique_reports import T1136 +from monkey_island.cc.services.attack.technique_reports import T1136, T1156 from monkey_island.cc.services.attack.attack_config import AttackConfig from monkey_island.cc.database import mongo from monkey_island.cc.services.reporting.report_generation_synchronisation import safe_generate_attack_report @@ -37,7 +37,8 @@ TECHNIQUES = {'T1210': T1210.T1210, 'T1016': T1016.T1016, 'T1021': T1021.T1021, 'T1064': T1064.T1064, - 'T1136': T1136.T1136 + 'T1136': T1136.T1136, + 'T1156': T1156.T1156 } REPORT_NAME = 'new_report' diff --git a/monkey/monkey_island/cc/services/attack/attack_schema.py b/monkey/monkey_island/cc/services/attack/attack_schema.py index 177dc9eaa..c834faab3 100644 --- a/monkey/monkey_island/cc/services/attack/attack_schema.py +++ b/monkey/monkey_island/cc/services/attack/attack_schema.py @@ -71,6 +71,16 @@ SCHEMA = { "type": "object", "link": "https://attack.mitre.org/tactics/TA0003/", "properties": { + "T1156": { + "title": ".bash_profile and .bashrc", + "type": "bool", + "value": True, + "necessary": False, + "link": "https://attack.mitre.org/techniques/T1156", + "description": "Adversaries may abuse shell scripts by " + "inserting arbitrary shell commands to gain persistence, which " + "would be executed every time the user logs in or opens a new shell." + }, "T1136": { "title": "Create account", "type": "bool", diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1156.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1156.py new file mode 100644 index 000000000..96028865a --- /dev/null +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1156.py @@ -0,0 +1,37 @@ +from monkey_island.cc.services.attack.technique_reports import AttackTechnique +from monkey_island.cc.services.reporting.report import ReportService +from common.utils.attack_utils import ScanStatus +from common.data.post_breach_consts import POST_BREACH_SHELL_STARTUP_FILE_MODIFICATION + + +__author__ = "shreyamalviya" + + +class T1156(AttackTechnique): + tech_id = "T1156" + unscanned_msg = "Monkey did not try modifying shell startup files on the system." + scanned_msg = "Monkey tried modifying shell startup files on the system but failed." + used_msg = "Monkey modified shell startup files on the system." + + @staticmethod + def get_report_data(): + data = {'title': T1156.technique_title(), 'info': []} + + scanned_nodes = ReportService.get_scanned() + status = ScanStatus.UNSCANNED.value + + for node in scanned_nodes: + if node['pba_results'] != 'None': + for pba in node['pba_results']: + if pba['name'] == POST_BREACH_SHELL_STARTUP_FILE_MODIFICATION: + status = ScanStatus.USED.value if pba['result'][1]\ + else ScanStatus.SCANNED.value + data['info'].append({ + 'machine': { + 'hostname': pba['hostname'], + 'ips': node['ip_addresses'] + }, + 'result': pba['result'][0].replace('#', '') + }) + data.update(T1156.get_base_data_by_status(status)) + return data diff --git a/monkey/monkey_island/cc/services/config_schema.py b/monkey/monkey_island/cc/services/config_schema.py index b6668af38..a1e8bcb3d 100644 --- a/monkey/monkey_island/cc/services/config_schema.py +++ b/monkey/monkey_island/cc/services/config_schema.py @@ -160,6 +160,14 @@ SCHEMA = { "title": "Communicate as new user", "attack_techniques": ["T1136"] }, + { + "type": "string", + "enum": [ + "ModifyShellStartupFiles" + ], + "title": "Modify shell startup files", + "attack_techniques": ["T1156"] + } ], }, "finger_classes": { @@ -379,7 +387,8 @@ SCHEMA = { }, "default": [ "BackdoorUser", - "CommunicateAsNewUser" + "CommunicateAsNewUser", + "ModifyShellStartupFiles" ], "description": "List of actions the Monkey will run post breach" }, diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1156.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1156.js new file mode 100644 index 000000000..ce136284c --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1156.js @@ -0,0 +1,45 @@ +import React from 'react'; +import ReactTable from 'react-table'; +import {renderMachineFromSystemData, ScanStatus} from './Helpers'; +import MitigationsComponent from './MitigationsComponent'; + +class T1156 extends React.Component { + + constructor(props) { + super(props); + } + + static getColumns() { + return ([{ + columns: [ + { Header: 'Machine', + id: 'machine', + accessor: x => renderMachineFromSystemData(x.machine), + style: {'whiteSpace': 'unset'}}, + { Header: 'Result', + id: 'result', + accessor: x => x.result, + style: {'whiteSpace': 'unset'}} + ] + }]) + } + + render() { + return ( +