From a9c763cd9cfa8552dadeb07981dbac2164080c7d Mon Sep 17 00:00:00 2001 From: Shreya Date: Fri, 12 Jun 2020 02:44:17 +0530 Subject: [PATCH 01/37] Add linux PBA + report components --- monkey/common/data/post_breach_consts.py | 1 + .../actions/modify_shell_startup_files.py | 32 +++++++++++++ .../linux/shell_startup_files_modification.py | 16 +++++++ .../utils/shell_startup_files_modification.py | 10 +++++ .../shell_startup_files_modification.py | 3 ++ .../cc/services/attack/attack_report.py | 5 ++- .../cc/services/attack/attack_schema.py | 10 +++++ .../attack/technique_reports/T1156.py | 37 +++++++++++++++ .../cc/services/config_schema.py | 11 ++++- .../src/components/attack/techniques/T1156.js | 45 +++++++++++++++++++ 10 files changed, 167 insertions(+), 3 deletions(-) create mode 100644 monkey/infection_monkey/post_breach/actions/modify_shell_startup_files.py create mode 100644 monkey/infection_monkey/utils/linux/shell_startup_files_modification.py create mode 100644 monkey/infection_monkey/utils/shell_startup_files_modification.py create mode 100644 monkey/infection_monkey/utils/windows/shell_startup_files_modification.py create mode 100644 monkey/monkey_island/cc/services/attack/technique_reports/T1156.py create mode 100644 monkey/monkey_island/cc/ui/src/components/attack/techniques/T1156.js 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 ( +
+
{this.props.data.message}
+
+ {this.props.data.status === ScanStatus.USED ? + : ''} + +
+ ); + } + } + + export default T1156; From e2d35ca2674f6b48ea49bb03d2fdf99cbfa3cdde Mon Sep 17 00:00:00 2001 From: Shreya Date: Sat, 13 Jun 2020 19:37:01 +0530 Subject: [PATCH 02/37] Simpler bash commands for linux PBA --- .../utils/linux/shell_startup_files_modification.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/monkey/infection_monkey/utils/linux/shell_startup_files_modification.py b/monkey/infection_monkey/utils/linux/shell_startup_files_modification.py index f6f8c3ffd..8c54b9168 100644 --- a/monkey/infection_monkey/utils/linux/shell_startup_files_modification.py +++ b/monkey/infection_monkey/utils/linux/shell_startup_files_modification.py @@ -3,14 +3,11 @@ 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 + 'echo \"# Succesfully modified {0}\"', + '3<{0} 3<&- |', # check for existence of file + 'tee -a', # append to file + '{0}', '&&', - 'sed -i \'$d\' {0} ;', # remove last line of file - 'else', - 'echo \"{0} does not exist\" ; fi' # mention if file does not exist + 'sed -i \'$d\' {0}', # remove last line of file ],\ BASH_STARTUP_FILES From dfa34e602f9fd89e01f13c5b1b466d1a9e1d1adf Mon Sep 17 00:00:00 2001 From: Shreya Date: Sat, 13 Jun 2020 21:09:19 +0530 Subject: [PATCH 03/37] Started T1504 implementation Add to `attack_schema.py`, `attack_report.py` Add report `T1504.js` --- .../cc/services/attack/attack_report.py | 5 ++- .../cc/services/attack/attack_schema.py | 27 +++++++++++ .../src/components/attack/techniques/T1504.js | 45 +++++++++++++++++++ 3 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 monkey/monkey_island/cc/ui/src/components/attack/techniques/T1504.js diff --git a/monkey/monkey_island/cc/services/attack/attack_report.py b/monkey/monkey_island/cc/services/attack/attack_report.py index 7f8576941..b2ad3234a 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, T1156 +from monkey_island.cc.services.attack.technique_reports import T1136, T1156, T1504 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 @@ -38,7 +38,8 @@ TECHNIQUES = {'T1210': T1210.T1210, 'T1021': T1021.T1021, 'T1064': T1064.T1064, 'T1136': T1136.T1136, - 'T1156': T1156.T1156 + 'T1156': T1156.T1156, + 'T1504': T1504.T1504 } 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 c834faab3..7ef15a509 100644 --- a/monkey/monkey_island/cc/services/attack/attack_schema.py +++ b/monkey/monkey_island/cc/services/attack/attack_schema.py @@ -89,6 +89,33 @@ SCHEMA = { "link": "https://attack.mitre.org/techniques/T1136", "description": "Adversaries with a sufficient level of access " "may create a local system, domain, or cloud tenant account." + }, + "T1504": { + "title": "PowerShell profile", + "type": "bool", + "value": True, + "necessary": False, + "link": "https://attack.mitre.org/techniques/T1504", + "description": "Adversaries may gain persistence and elevate privileges " + "in certain situations by abusing PowerShell profiles which " + "are scripts that run when PowerShell starts." + } + } + }, + "privilege_escalation": { + "title": "Privilege escalation", + "type": "object", + "link": "https://attack.mitre.org/tactics/TA0004/", + "properties": { + "T1504": { + "title": "PowerShell profile", + "type": "bool", + "value": True, + "necessary": False, + "link": "https://attack.mitre.org/techniques/T1504", + "description": "Adversaries may gain persistence and elevate privileges " + "in certain situations by abusing PowerShell profiles which " + "are scripts that run when PowerShell starts." } } }, diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1504.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1504.js new file mode 100644 index 000000000..f85bbffd2 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1504.js @@ -0,0 +1,45 @@ +import React from 'react'; +import ReactTable from 'react-table'; +import {renderMachineFromSystemData, ScanStatus} from './Helpers'; +import MitigationsComponent from './MitigationsComponent'; + +class T1504 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 ( +
+
{this.props.data.message}
+
+ {this.props.data.status === ScanStatus.USED ? + : ''} + +
+ ); + } + } + + export default T1504; From 3fe4dd679bc5d829a59c141c91848bcc4e29ad0a Mon Sep 17 00:00:00 2001 From: Shreya Date: Mon, 15 Jun 2020 17:42:11 +0530 Subject: [PATCH 04/37] Pass empty string to linux_cmds if OS is windows --- .../post_breach/actions/modify_shell_startup_files.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index a2d92db6c..a526acad6 100644 --- a/monkey/infection_monkey/post_breach/actions/modify_shell_startup_files.py +++ b/monkey/infection_monkey/post_breach/actions/modify_shell_startup_files.py @@ -20,7 +20,7 @@ class ModifyShellStartupFiles(PBA): if is_windows_os(): super(ModifyShellStartupFiles, self).__init__(name=POST_BREACH_SHELL_STARTUP_FILE_MODIFICATION, - linux_cmd=' '.join(linux_cmds), + linux_cmd='', # windows so won't matter windows_cmd=windows_cmds) super(ModifyShellStartupFiles, self).run() else: From 1b040dc874d1ed614b7bb6eb9cda39da312b2ce1 Mon Sep 17 00:00:00 2001 From: Shreya Date: Mon, 15 Jun 2020 17:44:28 +0530 Subject: [PATCH 05/37] Add windows PBA --- .../windows/shell_startup_files_modification.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/monkey/infection_monkey/utils/windows/shell_startup_files_modification.py b/monkey/infection_monkey/utils/windows/shell_startup_files_modification.py index efc9480d8..15e44b832 100644 --- a/monkey/infection_monkey/utils/windows/shell_startup_files_modification.py +++ b/monkey/infection_monkey/utils/windows/shell_startup_files_modification.py @@ -1,3 +1,12 @@ +SHELL_STARTUP_FILE = '$Profile' + + def get_windows_commands_to_modify_shell_startup_files(): - # TODO: add for powershell - return 'dir' + return [ + 'powershell.exe', # run with powershell + 'Add-Content {0} '.format(SHELL_STARTUP_FILE), + '\"# Successfully modified {0}\" ;'.format(SHELL_STARTUP_FILE), # add line to $profile + 'cat {0} | Select -last 1 ;'.format(SHELL_STARTUP_FILE), # print last line of $profile + '$OldProfile = cat {0} | Select -skiplast 1 ;'.format(SHELL_STARTUP_FILE), + 'Set-Content {0} -Value $OldProfile ;'.format(SHELL_STARTUP_FILE) # remove last line of $profile +] From 8bb5096addf22e6aaf0d581f338c157fd981ffa5 Mon Sep 17 00:00:00 2001 From: Shreya Date: Mon, 15 Jun 2020 17:45:23 +0530 Subject: [PATCH 06/37] Add T1504 report data + modify T1156 report data --- .../attack/technique_reports/T1156.py | 19 +++++----- .../attack/technique_reports/T1504.py | 38 +++++++++++++++++++ 2 files changed, 48 insertions(+), 9 deletions(-) create mode 100644 monkey/monkey_island/cc/services/attack/technique_reports/T1504.py diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1156.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1156.py index 96028865a..b618e743a 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1156.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1156.py @@ -24,14 +24,15 @@ class T1156(AttackTechnique): 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('#', '') - }) + if 'powershell.exe' not in pba['command']: + 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/attack/technique_reports/T1504.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1504.py new file mode 100644 index 000000000..585599c86 --- /dev/null +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1504.py @@ -0,0 +1,38 @@ +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 T1504(AttackTechnique): + tech_id = "T1504" + 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': T1504.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: + if 'powershell.exe' in pba['command']: + 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(T1504.get_base_data_by_status(status)) + return data From ef6bb52302b4b2549942d9cd0983813d47883f83 Mon Sep 17 00:00:00 2001 From: Shreya Date: Mon, 15 Jun 2020 17:54:44 +0530 Subject: [PATCH 07/37] Remove Privilege escalation/T1504 in attack_schema Shows it twice in ATT&CK matrix in the configuration, but shows it only once in the ATT&CK matrix in the report section. --- .../cc/services/attack/attack_schema.py | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/monkey/monkey_island/cc/services/attack/attack_schema.py b/monkey/monkey_island/cc/services/attack/attack_schema.py index 7ef15a509..99e8dcfd2 100644 --- a/monkey/monkey_island/cc/services/attack/attack_schema.py +++ b/monkey/monkey_island/cc/services/attack/attack_schema.py @@ -102,23 +102,6 @@ SCHEMA = { } } }, - "privilege_escalation": { - "title": "Privilege escalation", - "type": "object", - "link": "https://attack.mitre.org/tactics/TA0004/", - "properties": { - "T1504": { - "title": "PowerShell profile", - "type": "bool", - "value": True, - "necessary": False, - "link": "https://attack.mitre.org/techniques/T1504", - "description": "Adversaries may gain persistence and elevate privileges " - "in certain situations by abusing PowerShell profiles which " - "are scripts that run when PowerShell starts." - } - } - }, "defence_evasion": { "title": "Defence evasion", "type": "object", From 58a0a67244b7576199a59461118c76e40362f5ad Mon Sep 17 00:00:00 2001 From: Shreya Date: Mon, 15 Jun 2020 17:58:46 +0530 Subject: [PATCH 08/37] Add T1504 to config_schema --- monkey/monkey_island/cc/services/config_schema.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkey/monkey_island/cc/services/config_schema.py b/monkey/monkey_island/cc/services/config_schema.py index a1e8bcb3d..e37f3a75f 100644 --- a/monkey/monkey_island/cc/services/config_schema.py +++ b/monkey/monkey_island/cc/services/config_schema.py @@ -166,7 +166,7 @@ SCHEMA = { "ModifyShellStartupFiles" ], "title": "Modify shell startup files", - "attack_techniques": ["T1156"] + "attack_techniques": ["T1156", "T1504"] } ], }, From 6d98f95d4c63b74c28b493c0861958262e3bca60 Mon Sep 17 00:00:00 2001 From: Shreya Date: Mon, 15 Jun 2020 18:26:05 +0530 Subject: [PATCH 09/37] Make used/scanned/unscanned messages descriptive --- .../cc/services/attack/technique_reports/T1156.py | 6 +++--- .../cc/services/attack/technique_reports/T1504.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1156.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1156.py index b618e743a..9ceb2c027 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1156.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1156.py @@ -9,9 +9,9 @@ __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." + unscanned_msg = "Monkey did not try modifying Linux's shell startup files on the system." + scanned_msg = "Monkey tried modifying Linux's shell startup files on the system but failed." + used_msg = "Monkey modified Linux's shell startup files on the system." @staticmethod def get_report_data(): diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1504.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1504.py index 585599c86..34e25323e 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1504.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1504.py @@ -9,9 +9,9 @@ __author__ = "shreyamalviya" class T1504(AttackTechnique): tech_id = "T1504" - 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." + unscanned_msg = "Monkey did not try modifying Window's shell startup files on the system." + scanned_msg = "Monkey tried modifying Window's shell startup files on the system but failed." + used_msg = "Monkey modified Window's shell startup files on the system." @staticmethod def get_report_data(): From 60207e3a794948d75f4a984b66cf69f44e11b1e4 Mon Sep 17 00:00:00 2001 From: Shreya Date: Wed, 17 Jun 2020 02:09:02 +0530 Subject: [PATCH 10/37] Change file locations --- .../linux/shell_startup_files_modification.py | 0 .../shell_startup_files}/shell_startup_files_modification.py | 4 ++-- .../windows/shell_startup_files_modification.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename monkey/infection_monkey/{utils => post_breach/shell_startup_files}/linux/shell_startup_files_modification.py (100%) rename monkey/infection_monkey/{utils => post_breach/shell_startup_files}/shell_startup_files_modification.py (62%) rename monkey/infection_monkey/{utils => post_breach/shell_startup_files}/windows/shell_startup_files_modification.py (98%) diff --git a/monkey/infection_monkey/utils/linux/shell_startup_files_modification.py b/monkey/infection_monkey/post_breach/shell_startup_files/linux/shell_startup_files_modification.py similarity index 100% rename from monkey/infection_monkey/utils/linux/shell_startup_files_modification.py rename to monkey/infection_monkey/post_breach/shell_startup_files/linux/shell_startup_files_modification.py diff --git a/monkey/infection_monkey/utils/shell_startup_files_modification.py b/monkey/infection_monkey/post_breach/shell_startup_files/shell_startup_files_modification.py similarity index 62% rename from monkey/infection_monkey/utils/shell_startup_files_modification.py rename to monkey/infection_monkey/post_breach/shell_startup_files/shell_startup_files_modification.py index c97ca34b7..bc83ec499 100644 --- a/monkey/infection_monkey/utils/shell_startup_files_modification.py +++ b/monkey/infection_monkey/post_breach/shell_startup_files/shell_startup_files_modification.py @@ -1,6 +1,6 @@ -from infection_monkey.utils.linux.shell_startup_files_modification import\ +from infection_monkey.post_breach.shell_startup_files.linux.shell_startup_files_modification import\ get_linux_commands_to_modify_shell_startup_files -from infection_monkey.utils.windows.shell_startup_files_modification import\ +from infection_monkey.post_breach.shell_startup_files.windows.shell_startup_files_modification import\ get_windows_commands_to_modify_shell_startup_files diff --git a/monkey/infection_monkey/utils/windows/shell_startup_files_modification.py b/monkey/infection_monkey/post_breach/shell_startup_files/windows/shell_startup_files_modification.py similarity index 98% rename from monkey/infection_monkey/utils/windows/shell_startup_files_modification.py rename to monkey/infection_monkey/post_breach/shell_startup_files/windows/shell_startup_files_modification.py index 15e44b832..44315df4b 100644 --- a/monkey/infection_monkey/utils/windows/shell_startup_files_modification.py +++ b/monkey/infection_monkey/post_breach/shell_startup_files/windows/shell_startup_files_modification.py @@ -9,4 +9,4 @@ def get_windows_commands_to_modify_shell_startup_files(): 'cat {0} | Select -last 1 ;'.format(SHELL_STARTUP_FILE), # print last line of $profile '$OldProfile = cat {0} | Select -skiplast 1 ;'.format(SHELL_STARTUP_FILE), 'Set-Content {0} -Value $OldProfile ;'.format(SHELL_STARTUP_FILE) # remove last line of $profile -] + ] From 0c60ad16aed66d1b2fae83b6a0cfb81fe09a7094 Mon Sep 17 00:00:00 2001 From: Shreya Date: Wed, 17 Jun 2020 11:49:03 +0530 Subject: [PATCH 11/37] Code design changes --- .../actions/modify_shell_startup_files.py | 42 ++++++++++++------- monkey/infection_monkey/post_breach/pba.py | 11 ++--- 2 files changed, 32 insertions(+), 21 deletions(-) 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 index a526acad6..8417849db 100644 --- a/monkey/infection_monkey/post_breach/actions/modify_shell_startup_files.py +++ b/monkey/infection_monkey/post_breach/actions/modify_shell_startup_files.py @@ -1,6 +1,6 @@ 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\ +from infection_monkey.post_breach.shell_startup_files.shell_startup_files_modification import\ get_commands_to_modify_shell_startup_files from infection_monkey.utils.environment import is_windows_os @@ -12,21 +12,31 @@ class ModifyShellStartupFiles(PBA): and profile.ps1 in windows. """ - def __init__(self): - super(ModifyShellStartupFiles, self).__init__(name=POST_BREACH_SHELL_STARTUP_FILE_MODIFICATION) - def run(self): + [pba.run() for pba in self.modify_shell_startup_PBA_list()] + + def modify_shell_startup_PBA_list(self): + return ShellStartupPBAGenerator.get_modify_shell_startup_pbas() + + +class ShellStartupPBAGenerator(): + def get_modify_shell_startup_pbas(): (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='', # windows so won't matter - 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() + pbas = [ModifyShellStartupFile(linux_cmds='', windows_cmds=windows_cmds)] + + for shell_startup_file in shell_startup_files_for_linux: + linux_cmds = ' '.join(cmds_for_linux).format(shell_startup_file) + pbas.append(ModifyShellStartupFile(linux_cmds=linux_cmds, windows_cmds='')) + + return pbas + + +class ModifyShellStartupFile(PBA): + def __init__(self, linux_cmds, windows_cmds): + super(ModifyShellStartupFile, self).__init__(name=POST_BREACH_SHELL_STARTUP_FILE_MODIFICATION, + linux_cmd=linux_cmds, + windows_cmd=windows_cmds) + + def run(self): + super(ModifyShellStartupFile, self).run() diff --git a/monkey/infection_monkey/post_breach/pba.py b/monkey/infection_monkey/post_breach/pba.py index 3d8da9dab..e5a91b733 100644 --- a/monkey/infection_monkey/post_breach/pba.py +++ b/monkey/infection_monkey/post_breach/pba.py @@ -57,11 +57,12 @@ class PBA(Plugin): """ Runs post breach action command """ - exec_funct = self._execute_default - result = exec_funct() - if self.scripts_were_used_successfully(result): - T1064Telem(ScanStatus.USED, "Scripts were used to execute %s post breach action." % self.name).send() - PostBreachTelem(self, result).send() + if self.command: + exec_funct = self._execute_default + result = exec_funct() + if self.scripts_were_used_successfully(result): + T1064Telem(ScanStatus.USED, "Scripts were used to execute %s post breach action." % self.name).send() + PostBreachTelem(self, result).send() def is_script(self): """ From e5f92d29b55e09b6cf12fd30d2c6322fc2fbe8bb Mon Sep 17 00:00:00 2001 From: Shreya Date: Sat, 20 Jun 2020 16:47:08 +0530 Subject: [PATCH 12/37] Add startup files for fish, zsh, dash, ksh, sh, csh, tcsh --- .../linux/shell_startup_files_modification.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/monkey/infection_monkey/post_breach/shell_startup_files/linux/shell_startup_files_modification.py b/monkey/infection_monkey/post_breach/shell_startup_files/linux/shell_startup_files_modification.py index 8c54b9168..745caf6c8 100644 --- a/monkey/infection_monkey/post_breach/shell_startup_files/linux/shell_startup_files_modification.py +++ b/monkey/infection_monkey/post_breach/shell_startup_files/linux/shell_startup_files_modification.py @@ -1,4 +1,12 @@ -BASH_STARTUP_FILES = ["~/.bashrc", "~/.profile", "~/.bash_profile"] +STARTUP_FILES = [ + "~/.profile", # bash, dash, ksh, sh + "~/.bashrc", "~/.bash_profile", # bash + "~/.config/fish/config.fish", # fish + "~/.zshrc", "~/.zshenv", "~/.zprofile", # zsh + "~/.kshrc", # ksh + "~/.tcshrc", # tcsh + "~/.cshrc", # csh + ] def get_linux_commands_to_modify_shell_startup_files(): @@ -10,4 +18,4 @@ def get_linux_commands_to_modify_shell_startup_files(): '&&', 'sed -i \'$d\' {0}', # remove last line of file ],\ - BASH_STARTUP_FILES + STARTUP_FILES From 8d2aaac65f2056b3001e09d28c91753e800acf13 Mon Sep 17 00:00:00 2001 From: Shreya Date: Sat, 20 Jun 2020 23:30:32 +0530 Subject: [PATCH 13/37] Fix + make linux PBA commands cleaner --- .../post_breach/actions/modify_shell_startup_files.py | 3 --- .../linux/shell_startup_files_modification.py | 10 ++++------ 2 files changed, 4 insertions(+), 9 deletions(-) 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 index 8417849db..09063fa2d 100644 --- a/monkey/infection_monkey/post_breach/actions/modify_shell_startup_files.py +++ b/monkey/infection_monkey/post_breach/actions/modify_shell_startup_files.py @@ -37,6 +37,3 @@ class ModifyShellStartupFile(PBA): super(ModifyShellStartupFile, self).__init__(name=POST_BREACH_SHELL_STARTUP_FILE_MODIFICATION, linux_cmd=linux_cmds, windows_cmd=windows_cmds) - - def run(self): - super(ModifyShellStartupFile, self).run() diff --git a/monkey/infection_monkey/post_breach/shell_startup_files/linux/shell_startup_files_modification.py b/monkey/infection_monkey/post_breach/shell_startup_files/linux/shell_startup_files_modification.py index 745caf6c8..552904506 100644 --- a/monkey/infection_monkey/post_breach/shell_startup_files/linux/shell_startup_files_modification.py +++ b/monkey/infection_monkey/post_breach/shell_startup_files/linux/shell_startup_files_modification.py @@ -11,11 +11,9 @@ STARTUP_FILES = [ def get_linux_commands_to_modify_shell_startup_files(): return [ - 'echo \"# Succesfully modified {0}\"', - '3<{0} 3<&- |', # check for existence of file - 'tee -a', # append to file - '{0}', - '&&', - 'sed -i \'$d\' {0}', # remove last line of file + '3<{0} 3<&- &&', # check for existence of file + 'echo \"# Succesfully modified {0}\" |', + 'tee -a {0} &&', # append to file + 'sed -i \'$d\' {0}', # remove last line of file (undo changes) ],\ STARTUP_FILES From 7459105bbcfbbd512ea7eab6e4e2dbff8231ae23 Mon Sep 17 00:00:00 2001 From: Shreya Date: Sun, 21 Jun 2020 00:43:15 +0530 Subject: [PATCH 14/37] Extend linux PBA for all users on system TODO: ATT&CK report stuff (mongo search + show only bash file modification info) TODO: Windows --- .../actions/modify_shell_startup_files.py | 10 +++--- .../linux/shell_startup_files_modification.py | 34 ++++++++++++++----- 2 files changed, 32 insertions(+), 12 deletions(-) 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 index 09063fa2d..38c82bf02 100644 --- a/monkey/infection_monkey/post_breach/actions/modify_shell_startup_files.py +++ b/monkey/infection_monkey/post_breach/actions/modify_shell_startup_files.py @@ -21,13 +21,15 @@ class ModifyShellStartupFiles(PBA): class ShellStartupPBAGenerator(): def get_modify_shell_startup_pbas(): - (cmds_for_linux, shell_startup_files_for_linux), windows_cmds = get_commands_to_modify_shell_startup_files() + (cmds_for_linux, shell_startup_files_for_linux, usernames_for_linux), windows_cmds =\ + get_commands_to_modify_shell_startup_files() pbas = [ModifyShellStartupFile(linux_cmds='', windows_cmds=windows_cmds)] - for shell_startup_file in shell_startup_files_for_linux: - linux_cmds = ' '.join(cmds_for_linux).format(shell_startup_file) - pbas.append(ModifyShellStartupFile(linux_cmds=linux_cmds, windows_cmds='')) + for username in usernames_for_linux: + for shell_startup_file in shell_startup_files_for_linux: + linux_cmds = ' '.join(cmds_for_linux).format(shell_startup_file).format(username) + pbas.append(ModifyShellStartupFile(linux_cmds=linux_cmds, windows_cmds='')) return pbas diff --git a/monkey/infection_monkey/post_breach/shell_startup_files/linux/shell_startup_files_modification.py b/monkey/infection_monkey/post_breach/shell_startup_files/linux/shell_startup_files_modification.py index 552904506..b4d498296 100644 --- a/monkey/infection_monkey/post_breach/shell_startup_files/linux/shell_startup_files_modification.py +++ b/monkey/infection_monkey/post_breach/shell_startup_files/linux/shell_startup_files_modification.py @@ -1,12 +1,30 @@ +import subprocess + + +HOME_DIR = "/home/" + +# get list of usernames +USERS = subprocess.check_output( + "cut -d: -f1,3 /etc/passwd | egrep ':[0-9]{4}$' | cut -d: -f1", + shell=True + ).decode().split('\n')[:-1] + +# get list of paths of different shell startup files with place for username STARTUP_FILES = [ - "~/.profile", # bash, dash, ksh, sh - "~/.bashrc", "~/.bash_profile", # bash - "~/.config/fish/config.fish", # fish - "~/.zshrc", "~/.zshenv", "~/.zprofile", # zsh - "~/.kshrc", # ksh - "~/.tcshrc", # tcsh - "~/.cshrc", # csh + file_path.format(HOME_DIR) for file_path in + [ + "{0}{{0}}/.profile", # bash, dash, ksh, sh + "{0}{{0}}/.bashrc", # bash + "{0}{{0}}/.bash_profile", + "{0}{{0}}/.config/fish/config.fish", # fish + "{0}{{0}}/.zshrc", # zsh + "{0}{{0}}/.zshenv", + "{0}{{0}}/.zprofile", + "{0}{{0}}/.kshrc", # ksh + "{0}{{0}}/.tcshrc", # tcsh + "{0}{{0}}/.cshrc", # csh ] +] def get_linux_commands_to_modify_shell_startup_files(): @@ -16,4 +34,4 @@ def get_linux_commands_to_modify_shell_startup_files(): 'tee -a {0} &&', # append to file 'sed -i \'$d\' {0}', # remove last line of file (undo changes) ],\ - STARTUP_FILES + STARTUP_FILES, USERS From 6f6bfca9f9e2f6c7b79d8456f11c201421bed64e Mon Sep 17 00:00:00 2001 From: Shreya Date: Mon, 22 Jun 2020 17:58:12 +0530 Subject: [PATCH 15/37] Use mongo search for report data (For linux, shows only bash startup files in ATT&CK report) --- .../attack/technique_reports/T1156.py | 42 +++++++++---------- .../attack/technique_reports/T1504.py | 42 +++++++++---------- 2 files changed, 42 insertions(+), 42 deletions(-) diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1156.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1156.py index 9ceb2c027..a1719c909 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1156.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1156.py @@ -1,5 +1,5 @@ from monkey_island.cc.services.attack.technique_reports import AttackTechnique -from monkey_island.cc.services.reporting.report import ReportService +from monkey_island.cc.database import mongo from common.utils.attack_utils import ScanStatus from common.data.post_breach_consts import POST_BREACH_SHELL_STARTUP_FILE_MODIFICATION @@ -9,30 +9,30 @@ __author__ = "shreyamalviya" class T1156(AttackTechnique): tech_id = "T1156" - unscanned_msg = "Monkey did not try modifying Linux's shell startup files on the system." - scanned_msg = "Monkey tried modifying Linux's shell startup files on the system but failed." - used_msg = "Monkey modified Linux's shell startup files on the system." + unscanned_msg = "Monkey did not try modifying bash startup files on the system." + scanned_msg = "Monkey tried modifying bash startup files on the system but failed." + used_msg = "Monkey modified bash startup files on the system." + + query = [{'$match': {'telem_category': 'post_breach', + 'data.name': POST_BREACH_SHELL_STARTUP_FILE_MODIFICATION, + 'data.command': {'$regex': 'bash'}}}, + {'$project': {'_id': 0, + 'machine': {'hostname': '$data.hostname', + 'ips': ['$data.ip']}, + 'result': '$data.result'}}] @staticmethod def get_report_data(): data = {'title': T1156.technique_title(), 'info': []} - scanned_nodes = ReportService.get_scanned() - status = ScanStatus.UNSCANNED.value + bash_modification_info = list(mongo.db.telemetry.aggregate(T1156.query)) - 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: - if 'powershell.exe' not in pba['command']: - 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)) + status = [] + for pba_node in bash_modification_info: + status.append(pba_node['result'][1]) + status = (ScanStatus.USED.value if any(status) else ScanStatus.SCANNED.value)\ + if status else ScanStatus.UNSCANNED.value + + data.update(T1156.get_base_data_by_status(status)) + data.update({'info': bash_modification_info}) return data diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1504.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1504.py index 34e25323e..396067f17 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1504.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1504.py @@ -1,5 +1,5 @@ from monkey_island.cc.services.attack.technique_reports import AttackTechnique -from monkey_island.cc.services.reporting.report import ReportService +from monkey_island.cc.database import mongo from common.utils.attack_utils import ScanStatus from common.data.post_breach_consts import POST_BREACH_SHELL_STARTUP_FILE_MODIFICATION @@ -9,30 +9,30 @@ __author__ = "shreyamalviya" class T1504(AttackTechnique): tech_id = "T1504" - unscanned_msg = "Monkey did not try modifying Window's shell startup files on the system." - scanned_msg = "Monkey tried modifying Window's shell startup files on the system but failed." - used_msg = "Monkey modified Window's shell startup files on the system." + unscanned_msg = "Monkey did not try modifying powershell startup files on the system." + scanned_msg = "Monkey tried modifying powershell startup files on the system but failed." + used_msg = "Monkey modified powershell startup files on the system." + + query = [{'$match': {'telem_category': 'post_breach', + 'data.name': POST_BREACH_SHELL_STARTUP_FILE_MODIFICATION, + 'data.command': {'$regex': 'powershell'}}}, + {'$project': {'_id': 0, + 'machine': {'hostname': '$data.hostname', + 'ips': ['$data.ip']}, + 'result': '$data.result'}}] @staticmethod def get_report_data(): data = {'title': T1504.technique_title(), 'info': []} - scanned_nodes = ReportService.get_scanned() - status = ScanStatus.UNSCANNED.value + powershell_profile_modification_info = list(mongo.db.telemetry.aggregate(T1504.query)) - 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: - if 'powershell.exe' in pba['command']: - 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(T1504.get_base_data_by_status(status)) + status = [] + for pba_node in powershell_profile_modification_info: + status.append(pba_node['result'][1]) + status = (ScanStatus.USED.value if any(status) else ScanStatus.SCANNED.value)\ + if status else ScanStatus.UNSCANNED.value + + data.update(T1504.get_base_data_by_status(status)) + data.update({'info': powershell_profile_modification_info}) return data From 7efeff3ff07099adc54b17e3f93c07917a452a1f Mon Sep 17 00:00:00 2001 From: Shreya Date: Mon, 22 Jun 2020 18:30:06 +0530 Subject: [PATCH 16/37] Modify linux PBA so it doesn't give errors when running on windows --- .../linux/shell_startup_files_modification.py | 58 ++++++++++--------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/monkey/infection_monkey/post_breach/shell_startup_files/linux/shell_startup_files_modification.py b/monkey/infection_monkey/post_breach/shell_startup_files/linux/shell_startup_files_modification.py index b4d498296..8a1ed7246 100644 --- a/monkey/infection_monkey/post_breach/shell_startup_files/linux/shell_startup_files_modification.py +++ b/monkey/infection_monkey/post_breach/shell_startup_files/linux/shell_startup_files_modification.py @@ -1,37 +1,39 @@ import subprocess - - -HOME_DIR = "/home/" - -# get list of usernames -USERS = subprocess.check_output( - "cut -d: -f1,3 /etc/passwd | egrep ':[0-9]{4}$' | cut -d: -f1", - shell=True - ).decode().split('\n')[:-1] - -# get list of paths of different shell startup files with place for username -STARTUP_FILES = [ - file_path.format(HOME_DIR) for file_path in - [ - "{0}{{0}}/.profile", # bash, dash, ksh, sh - "{0}{{0}}/.bashrc", # bash - "{0}{{0}}/.bash_profile", - "{0}{{0}}/.config/fish/config.fish", # fish - "{0}{{0}}/.zshrc", # zsh - "{0}{{0}}/.zshenv", - "{0}{{0}}/.zprofile", - "{0}{{0}}/.kshrc", # ksh - "{0}{{0}}/.tcshrc", # tcsh - "{0}{{0}}/.cshrc", # csh - ] -] +from infection_monkey.utils.environment import is_windows_os def get_linux_commands_to_modify_shell_startup_files(): + if is_windows_os(): + return '', [], [] + + HOME_DIR = "/home/" + + # get list of usernames + USERS = subprocess.check_output( + "cut -d: -f1,3 /etc/passwd | egrep ':[0-9]{4}$' | cut -d: -f1", + shell=True + ).decode().split('\n')[:-1] + + # get list of paths of different shell startup files with place for username + STARTUP_FILES = [ + file_path.format(HOME_DIR) for file_path in + [ + "{0}{{0}}/.profile", # bash, dash, ksh, sh + "{0}{{0}}/.bashrc", # bash + "{0}{{0}}/.bash_profile", + "{0}{{0}}/.config/fish/config.fish", # fish + "{0}{{0}}/.zshrc", # zsh + "{0}{{0}}/.zshenv", + "{0}{{0}}/.zprofile", + "{0}{{0}}/.kshrc", # ksh + "{0}{{0}}/.tcshrc", # tcsh + "{0}{{0}}/.cshrc", # csh + ] + ] + return [ '3<{0} 3<&- &&', # check for existence of file 'echo \"# Succesfully modified {0}\" |', 'tee -a {0} &&', # append to file 'sed -i \'$d\' {0}', # remove last line of file (undo changes) - ],\ - STARTUP_FILES, USERS + ], STARTUP_FILES, USERS From f21dbde27d4e644fb7ea8071422449ffff12f540 Mon Sep 17 00:00:00 2001 From: Shreya Date: Mon, 22 Jun 2020 21:32:41 +0530 Subject: [PATCH 17/37] Extend windows PBA for all users on system --- .../actions/modify_shell_startup_files.py | 11 ++++--- .../shell_startup_files_modification.py | 31 ++++++++++++++----- 2 files changed, 30 insertions(+), 12 deletions(-) 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 index 38c82bf02..095c7cb11 100644 --- a/monkey/infection_monkey/post_breach/actions/modify_shell_startup_files.py +++ b/monkey/infection_monkey/post_breach/actions/modify_shell_startup_files.py @@ -2,7 +2,6 @@ from common.data.post_breach_consts import POST_BREACH_SHELL_STARTUP_FILE_MODIFI from infection_monkey.post_breach.pba import PBA from infection_monkey.post_breach.shell_startup_files.shell_startup_files_modification import\ get_commands_to_modify_shell_startup_files -from infection_monkey.utils.environment import is_windows_os class ModifyShellStartupFiles(PBA): @@ -21,10 +20,14 @@ class ModifyShellStartupFiles(PBA): class ShellStartupPBAGenerator(): def get_modify_shell_startup_pbas(): - (cmds_for_linux, shell_startup_files_for_linux, usernames_for_linux), windows_cmds =\ - get_commands_to_modify_shell_startup_files() + (cmds_for_linux, shell_startup_files_for_linux, usernames_for_linux),\ + (cmds_for_windows, shell_startup_files_per_user_for_windows) = get_commands_to_modify_shell_startup_files() - pbas = [ModifyShellStartupFile(linux_cmds='', windows_cmds=windows_cmds)] + pbas = [] + + for startup_file_per_user in shell_startup_files_per_user_for_windows: + windows_cmds = ' '.join(cmds_for_windows).format(startup_file_per_user) + pbas.append(ModifyShellStartupFile(linux_cmds='', windows_cmds=['powershell.exe', windows_cmds])) for username in usernames_for_linux: for shell_startup_file in shell_startup_files_for_linux: diff --git a/monkey/infection_monkey/post_breach/shell_startup_files/windows/shell_startup_files_modification.py b/monkey/infection_monkey/post_breach/shell_startup_files/windows/shell_startup_files_modification.py index 44315df4b..a9116c221 100644 --- a/monkey/infection_monkey/post_breach/shell_startup_files/windows/shell_startup_files_modification.py +++ b/monkey/infection_monkey/post_breach/shell_startup_files/windows/shell_startup_files_modification.py @@ -1,12 +1,27 @@ -SHELL_STARTUP_FILE = '$Profile' +import subprocess +from infection_monkey.utils.environment import is_windows_os def get_windows_commands_to_modify_shell_startup_files(): + if not is_windows_os(): + return '', [] + + # get powershell startup file path + SHELL_STARTUP_FILE = subprocess.check_output('powershell $Profile').decode().split("\r\n")[0] + SHELL_STARTUP_FILE_PATH_COMPONENTS = SHELL_STARTUP_FILE.split("\\") + + # get list of usernames + USERS = subprocess.check_output('dir C:\\Users /b', shell=True).decode().split("\r\n")[:-1] + + STARTUP_FILES_PER_USER = ['\\'.join(SHELL_STARTUP_FILE_PATH_COMPONENTS[:2] + + [user] + + SHELL_STARTUP_FILE_PATH_COMPONENTS[3:]) + for user in USERS] + return [ - 'powershell.exe', # run with powershell - 'Add-Content {0} '.format(SHELL_STARTUP_FILE), - '\"# Successfully modified {0}\" ;'.format(SHELL_STARTUP_FILE), # add line to $profile - 'cat {0} | Select -last 1 ;'.format(SHELL_STARTUP_FILE), # print last line of $profile - '$OldProfile = cat {0} | Select -skiplast 1 ;'.format(SHELL_STARTUP_FILE), - 'Set-Content {0} -Value $OldProfile ;'.format(SHELL_STARTUP_FILE) # remove last line of $profile - ] + 'Add-Content {0}', + '\"# Successfully modified {0}\" ;', # add line to $profile + 'cat {0} | Select -last 1 ;', # print last line of $profile + '$OldProfile = cat {0} | Select -skiplast 1 ;', + 'Set-Content {0} -Value $OldProfile ;' # remove last line of $profile + ], STARTUP_FILES_PER_USER From 53e6f893c69a9130b681f676582f434a69c713cb Mon Sep 17 00:00:00 2001 From: Shreya Date: Wed, 24 Jun 2020 13:58:52 +0530 Subject: [PATCH 18/37] Disabled prop-types warning in eslint (Accidentally force-pushed over the previous commit changing this) --- .travis.yml | 2 +- monkey/monkey_island/cc/ui/.eslintrc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index c7b12ca86..6640812b4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -65,7 +65,7 @@ script: - cd monkey_island/cc/ui - npm ci # See https://docs.npmjs.com/cli/ci.html - eslint ./src --quiet # Test for errors -- JS_WARNINGS_AMOUNT_UPPER_LIMIT=490 +- JS_WARNINGS_AMOUNT_UPPER_LIMIT=90 - eslint ./src --max-warnings $JS_WARNINGS_AMOUNT_UPPER_LIMIT # Test for max warnings after_success: diff --git a/monkey/monkey_island/cc/ui/.eslintrc b/monkey/monkey_island/cc/ui/.eslintrc index c784bd178..ff1695a1c 100644 --- a/monkey/monkey_island/cc/ui/.eslintrc +++ b/monkey/monkey_island/cc/ui/.eslintrc @@ -53,7 +53,7 @@ "react/jsx-uses-react": 1, "react/jsx-uses-vars": 1, "react/jsx-key": 1, - "react/prop-types": 1, + "react/prop-types": 0, "react/no-unescaped-entities": 1, "react/no-unknown-property": [1, { "ignore": ["class"] }], "react/no-string-refs": 1, From 45c5546f1796d870c2a528a3c98439cab65d10c9 Mon Sep 17 00:00:00 2001 From: Shreya Date: Wed, 3 Jun 2020 02:36:17 +0530 Subject: [PATCH 19/37] Add "Hidden files" PBA feature TODO: winAPI --- monkey/common/data/post_breach_consts.py | 1 + .../post_breach/actions/hide_files.py | 31 +++++++++++++++ monkey/infection_monkey/utils/hidden_files.py | 32 ++++++++++++++++ .../utils/linux/hidden_files.py | 32 ++++++++++++++++ .../utils/windows/hidden_files.py | 38 +++++++++++++++++++ 5 files changed, 134 insertions(+) create mode 100644 monkey/infection_monkey/post_breach/actions/hide_files.py create mode 100644 monkey/infection_monkey/utils/hidden_files.py create mode 100644 monkey/infection_monkey/utils/linux/hidden_files.py create mode 100644 monkey/infection_monkey/utils/windows/hidden_files.py diff --git a/monkey/common/data/post_breach_consts.py b/monkey/common/data/post_breach_consts.py index 1e36f9e20..27167228e 100644 --- a/monkey/common/data/post_breach_consts.py +++ b/monkey/common/data/post_breach_consts.py @@ -2,3 +2,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" +POST_BREACH_HIDDEN_FILES = "Hide files and directories" diff --git a/monkey/infection_monkey/post_breach/actions/hide_files.py b/monkey/infection_monkey/post_breach/actions/hide_files.py new file mode 100644 index 000000000..0a325b574 --- /dev/null +++ b/monkey/infection_monkey/post_breach/actions/hide_files.py @@ -0,0 +1,31 @@ +import time +from common.data.post_breach_consts import POST_BREACH_HIDDEN_FILES +from infection_monkey.post_breach.pba import PBA +from infection_monkey.telemetry.post_breach_telem import PostBreachTelem +from infection_monkey.utils.hidden_files import\ + [get_commands_to_hide_files, + get_commands_to_hide_folders] as CREATE_HIDDEN,\ + cleanup_hidden_files,\ + # get_winAPI_commands +from infection_monkey.utils.environment import is_windows_os + + +class HiddenFiles(PBA): + """ + This PBA attempts to create hidden files and folders. + """ + + def __init__(self): + pass + + def run(self): + for method_to_create in CREATE_HIDDEN: + linux_cmds, windows_cmds = method_to_create() + super(HiddenFiles, self).__init__(name=POST_BREACH_HIDDEN_FILES, + linux_cmd=' '.join(linux_cmds), + window_cmd=windows_cmds) + # if is_windows_os(): + # get_winAPI_commands() + # PostBreachTelem(???) + time.sleep(10) # detection time for AV software + cleanup_hidden_files(is_windows_os()) diff --git a/monkey/infection_monkey/utils/hidden_files.py b/monkey/infection_monkey/utils/hidden_files.py new file mode 100644 index 000000000..cad96d188 --- /dev/null +++ b/monkey/infection_monkey/utils/hidden_files.py @@ -0,0 +1,32 @@ +from infection_monkey.utils.linux.hidden_files import\ + get_linux_commands_to_hide_files,\ + get_linux_commands_to_hide_folders,\ + get_linux_commands_to_delete +from infection_monkey.utils.windows.hidden_files import\ + get_windows_commands_to_hide_files,\ + get_windows_commands_to_hide_folders,\ + # get_winAPI_commands_to_hide_files,\ + get_windows_commands_to_delete +from infection_monkey.utils.environment import is_windows_os + + +def get_commands_to_hide_files(): + linux_cmds = get_linux_commands_to_hide_files() + windows_cmds = get_windows_commands_to_hide_files() + return linux_cmds, windows_cmds + + +def get_commands_to_hide_folders(): + linux_cmds = get_linux_commands_to_hide_folders() + windows_cmds = get_windows_commands_to_hide_folders() + return linux_cmds, windows_cmds + + +# def get_winAPI_commands(): +# winAPI_command = get_winAPI_commands_to_hide_files() +# return winAPI_command + + +def cleanup_hidden_files(is_windows=is_windows_os()): + get_windows_commands_to_delete() if is_windows \ + else get_linux_commands_to_delete() diff --git a/monkey/infection_monkey/utils/linux/hidden_files.py b/monkey/infection_monkey/utils/linux/hidden_files.py new file mode 100644 index 000000000..41d555c84 --- /dev/null +++ b/monkey/infection_monkey/utils/linux/hidden_files.py @@ -0,0 +1,32 @@ +HIDDEN_FILE = '/var/tmp/.monkey-hidden-file' +HIDDEN_FOLDER = '/var/tmp/.monkey-hidden-folder' + + +def get_linux_commands_to_hide_files(): + return [ + 'touch', # create file + HIDDEN_FILE, + '; echo \"Successfully created hidden file\" >', # write to + HIDDEN_FILE + ] + + +def get_linux_commands_to_hide_folders(): + return [ + 'mkdir', # make directory + HIDDEN_FOLDER, + '; touch', # create file + '{}/{}'.format(HIDDEN_FOLDER, 'some-file'), # random file in hidden folder + '; echo \"Successfully created hidden folder\" >', # write to + '{}/{}'.format(HIDDEN_FOLDER, 'some-file') # random file in hidden folder + ] + + +def get_linux_commands_to_delete(): + return [ + 'rm', # remove + '-r', # delete recursively + '-f', # force delete + HIDDEN_FILE, + HIDDEN_FOLDER + ] diff --git a/monkey/infection_monkey/utils/windows/hidden_files.py b/monkey/infection_monkey/utils/windows/hidden_files.py new file mode 100644 index 000000000..bff198fef --- /dev/null +++ b/monkey/infection_monkey/utils/windows/hidden_files.py @@ -0,0 +1,38 @@ +HIDDEN_FILE = 'C:\\monkey-hidden-file' +HIDDEN_FOLDER = 'C:\\monkey-hidden-folder' + + +def get_windows_commands_to_hide_files(): + return [ + 'echo Successfully created hidden file >', # create text file + HIDDEN_FILE, + '&& attrib', # change file attributes + '+h', # make hidden + HIDDEN_FILE + ] + + +def get_windows_commands_to_hide_folders(): + return [ + 'mkdir', # make directory + HIDDEN_FOLDER, + '&& attrib', # change file attributes + '+h', # make hidden + HIDDEN_FOLDER, + '&& echo Successfully created hidden folder >' + '{}\{}'.format(HIDDEN_FOLDER, 'some-file') + ] + + +# def get_winAPI_commands_to_hide_files(): +# pass + + +def get_windows_commands_to_delete(): + return [ + 'del', # delete file + '/f', # force delete + HIDDEN_FILE, + '&& rmdir', # delete folder + HIDDEN_FOLDER + ] From 1d952a47818462ce9cc4f5484d605167575f35e6 Mon Sep 17 00:00:00 2001 From: Shreya Date: Thu, 4 Jun 2020 23:05:06 +0530 Subject: [PATCH 20/37] PBA stuff --- .../post_breach/actions/hide_files.py | 28 +++++++++++++------ monkey/infection_monkey/utils/hidden_files.py | 17 ++++++----- .../utils/windows/hidden_files.py | 28 +++++++++++++++++-- 3 files changed, 55 insertions(+), 18 deletions(-) diff --git a/monkey/infection_monkey/post_breach/actions/hide_files.py b/monkey/infection_monkey/post_breach/actions/hide_files.py index 0a325b574..ee5a7add9 100644 --- a/monkey/infection_monkey/post_breach/actions/hide_files.py +++ b/monkey/infection_monkey/post_breach/actions/hide_files.py @@ -3,29 +3,39 @@ from common.data.post_breach_consts import POST_BREACH_HIDDEN_FILES from infection_monkey.post_breach.pba import PBA from infection_monkey.telemetry.post_breach_telem import PostBreachTelem from infection_monkey.utils.hidden_files import\ - [get_commands_to_hide_files, - get_commands_to_hide_folders] as CREATE_HIDDEN,\ + get_commands_to_hide_files,\ + get_commands_to_hide_folders,\ cleanup_hidden_files,\ - # get_winAPI_commands + get_winAPI_to_hide_files from infection_monkey.utils.environment import is_windows_os +CREATE_HIDDEN = [get_commands_to_hide_files, + get_commands_to_hide_folders] + + class HiddenFiles(PBA): """ This PBA attempts to create hidden files and folders. """ def __init__(self): - pass + super(HiddenFiles, self).__init__(name=POST_BREACH_HIDDEN_FILES) def run(self): + # create hidden files and folders for method_to_create in CREATE_HIDDEN: linux_cmds, windows_cmds = method_to_create() super(HiddenFiles, self).__init__(name=POST_BREACH_HIDDEN_FILES, linux_cmd=' '.join(linux_cmds), - window_cmd=windows_cmds) - # if is_windows_os(): - # get_winAPI_commands() - # PostBreachTelem(???) - time.sleep(10) # detection time for AV software + windows_cmd=windows_cmds) + super(HiddenFiles, self).run() + if is_windows_os(): # use winAPI + result, status = get_winAPI_to_hide_files() + PostBreachTelem(self, (result, status)).send() + + # detection time for AV software + time.sleep(10) + + # cleanup hidden files and folders cleanup_hidden_files(is_windows_os()) diff --git a/monkey/infection_monkey/utils/hidden_files.py b/monkey/infection_monkey/utils/hidden_files.py index cad96d188..186c03fd0 100644 --- a/monkey/infection_monkey/utils/hidden_files.py +++ b/monkey/infection_monkey/utils/hidden_files.py @@ -1,3 +1,4 @@ +import subprocess from infection_monkey.utils.linux.hidden_files import\ get_linux_commands_to_hide_files,\ get_linux_commands_to_hide_folders,\ @@ -5,8 +6,9 @@ from infection_monkey.utils.linux.hidden_files import\ from infection_monkey.utils.windows.hidden_files import\ get_windows_commands_to_hide_files,\ get_windows_commands_to_hide_folders,\ - # get_winAPI_commands_to_hide_files,\ - get_windows_commands_to_delete + get_winAPI_to_hide_files,\ + get_windows_commands_to_delete,\ + get_winAPI_to_delete_files from infection_monkey.utils.environment import is_windows_os @@ -22,11 +24,12 @@ def get_commands_to_hide_folders(): return linux_cmds, windows_cmds -# def get_winAPI_commands(): -# winAPI_command = get_winAPI_commands_to_hide_files() -# return winAPI_command +def get_winAPI_to_hide_files(): + get_winAPI_to_hide_files() def cleanup_hidden_files(is_windows=is_windows_os()): - get_windows_commands_to_delete() if is_windows \ - else get_linux_commands_to_delete() + if is_windows: + get_winAPI_to_delete_files() + subprocess.run(get_windows_commands_to_delete() if is_windows + else get_linux_commands_to_delete()) diff --git a/monkey/infection_monkey/utils/windows/hidden_files.py b/monkey/infection_monkey/utils/windows/hidden_files.py index bff198fef..157e09f45 100644 --- a/monkey/infection_monkey/utils/windows/hidden_files.py +++ b/monkey/infection_monkey/utils/windows/hidden_files.py @@ -1,4 +1,8 @@ +import win32file + + HIDDEN_FILE = 'C:\\monkey-hidden-file' +HIDDEN_FILE_WINAPI = 'C:\\monkey-hidden-file-winAPI' HIDDEN_FOLDER = 'C:\\monkey-hidden-folder' @@ -24,8 +28,28 @@ def get_windows_commands_to_hide_folders(): ] -# def get_winAPI_commands_to_hide_files(): -# pass +def get_winAPI_to_hide_files(): + try: + fileAccess = win32file.GENERIC_READ | win32file.GENERIC_WRITE # read-write access + fileCreation = win32file.CREATE_ALWAYS # overwrite existing file + fileFlags = win32file.FILE_ATTRIBUTE_HIDDEN # make hidden + + hiddenFile = win32file.CreateFile(HIDDEN_FILE_WINAPI, + fileAccess, + 0, + None, + fileCreation, + fileFlags, + 0) + + return "Created hidden file: {}".format(HIDDEN_FILE_WINAPI), True + + except Exception as err: + return str(err), False + + +def get_winAPI_to_delete_files(): + win32file.DeleteFile(HIDDEN_FILE_WINAPI) def get_windows_commands_to_delete(): From 2b9d54408abd74cb46754ffd0779001f17596ada Mon Sep 17 00:00:00 2001 From: Shreya Date: Thu, 4 Jun 2020 23:29:27 +0530 Subject: [PATCH 21/37] Tweak PBA logic Don't need to use winAPI to delete file --- monkey/infection_monkey/utils/hidden_files.py | 5 +---- monkey/infection_monkey/utils/windows/hidden_files.py | 10 ++-------- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/monkey/infection_monkey/utils/hidden_files.py b/monkey/infection_monkey/utils/hidden_files.py index 186c03fd0..cf37a0b1a 100644 --- a/monkey/infection_monkey/utils/hidden_files.py +++ b/monkey/infection_monkey/utils/hidden_files.py @@ -7,8 +7,7 @@ from infection_monkey.utils.windows.hidden_files import\ get_windows_commands_to_hide_files,\ get_windows_commands_to_hide_folders,\ get_winAPI_to_hide_files,\ - get_windows_commands_to_delete,\ - get_winAPI_to_delete_files + get_windows_commands_to_delete from infection_monkey.utils.environment import is_windows_os @@ -29,7 +28,5 @@ def get_winAPI_to_hide_files(): def cleanup_hidden_files(is_windows=is_windows_os()): - if is_windows: - get_winAPI_to_delete_files() subprocess.run(get_windows_commands_to_delete() if is_windows else get_linux_commands_to_delete()) diff --git a/monkey/infection_monkey/utils/windows/hidden_files.py b/monkey/infection_monkey/utils/windows/hidden_files.py index 157e09f45..0a527d167 100644 --- a/monkey/infection_monkey/utils/windows/hidden_files.py +++ b/monkey/infection_monkey/utils/windows/hidden_files.py @@ -1,6 +1,3 @@ -import win32file - - HIDDEN_FILE = 'C:\\monkey-hidden-file' HIDDEN_FILE_WINAPI = 'C:\\monkey-hidden-file-winAPI' HIDDEN_FOLDER = 'C:\\monkey-hidden-folder' @@ -29,6 +26,7 @@ def get_windows_commands_to_hide_folders(): def get_winAPI_to_hide_files(): + import win32file try: fileAccess = win32file.GENERIC_READ | win32file.GENERIC_WRITE # read-write access fileCreation = win32file.CREATE_ALWAYS # overwrite existing file @@ -43,20 +41,16 @@ def get_winAPI_to_hide_files(): 0) return "Created hidden file: {}".format(HIDDEN_FILE_WINAPI), True - except Exception as err: return str(err), False -def get_winAPI_to_delete_files(): - win32file.DeleteFile(HIDDEN_FILE_WINAPI) - - def get_windows_commands_to_delete(): return [ 'del', # delete file '/f', # force delete HIDDEN_FILE, + HIDDEN_FILE_WINAPI, '&& rmdir', # delete folder HIDDEN_FOLDER ] From 15ac77056a88638394417a684012590361a40aad Mon Sep 17 00:00:00 2001 From: Shreya Date: Fri, 5 Jun 2020 17:43:08 +0530 Subject: [PATCH 22/37] PBA changes: Linux --- monkey/infection_monkey/utils/linux/hidden_files.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/monkey/infection_monkey/utils/linux/hidden_files.py b/monkey/infection_monkey/utils/linux/hidden_files.py index 41d555c84..028edf4a1 100644 --- a/monkey/infection_monkey/utils/linux/hidden_files.py +++ b/monkey/infection_monkey/utils/linux/hidden_files.py @@ -6,7 +6,8 @@ def get_linux_commands_to_hide_files(): return [ 'touch', # create file HIDDEN_FILE, - '; echo \"Successfully created hidden file\" >', # write to + '; echo \"Successfully created hidden file: {}\" |'.format(HIDDEN_FILE), # output + 'tee -a', # and write to file HIDDEN_FILE ] @@ -17,7 +18,8 @@ def get_linux_commands_to_hide_folders(): HIDDEN_FOLDER, '; touch', # create file '{}/{}'.format(HIDDEN_FOLDER, 'some-file'), # random file in hidden folder - '; echo \"Successfully created hidden folder\" >', # write to + '; echo \"Successfully created hidden folder: {}\" |'.format(HIDDEN_FOLDER), # output + 'tee -a', # and write to file '{}/{}'.format(HIDDEN_FOLDER, 'some-file') # random file in hidden folder ] From 49350aa303b5df5b25b81a16778b93bd13012bfa Mon Sep 17 00:00:00 2001 From: Shreya Date: Fri, 5 Jun 2020 18:21:15 +0530 Subject: [PATCH 23/37] PBA changes: Windows --- .../infection_monkey/utils/windows/hidden_files.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/monkey/infection_monkey/utils/windows/hidden_files.py b/monkey/infection_monkey/utils/windows/hidden_files.py index 0a527d167..e188f1bc1 100644 --- a/monkey/infection_monkey/utils/windows/hidden_files.py +++ b/monkey/infection_monkey/utils/windows/hidden_files.py @@ -5,11 +5,13 @@ HIDDEN_FOLDER = 'C:\\monkey-hidden-folder' def get_windows_commands_to_hide_files(): return [ - 'echo Successfully created hidden file >', # create text file + 'type NUL >', # create empty file HIDDEN_FILE, '&& attrib', # change file attributes '+h', # make hidden - HIDDEN_FILE + HIDDEN_FILE, + 'echo Successfully created hidden file: {0} > {0}'.format(HIDDEN_FILE), + '&& type {}'.format(HIDDEN_FILE) ] @@ -20,8 +22,9 @@ def get_windows_commands_to_hide_folders(): '&& attrib', # change file attributes '+h', # make hidden HIDDEN_FOLDER, - '&& echo Successfully created hidden folder >' - '{}\{}'.format(HIDDEN_FOLDER, 'some-file') + '&& echo Successfully created hidden folder: {} >'.format(HIDDEN_FOLDER), + '{}\\{}'.format(HIDDEN_FOLDER, 'some-file'), + '&& type {}'.format(HIDDEN_FOLDER, 'some-file') ] @@ -40,7 +43,7 @@ def get_winAPI_to_hide_files(): fileFlags, 0) - return "Created hidden file: {}".format(HIDDEN_FILE_WINAPI), True + return "Succesfully created hidden file: {}".format(HIDDEN_FILE_WINAPI), True except Exception as err: return str(err), False From 0f6fcc799ca193987c468c744763935a0d32ae59 Mon Sep 17 00:00:00 2001 From: Shreya Date: Fri, 5 Jun 2020 22:09:36 +0530 Subject: [PATCH 24/37] Add report components, link to matrix --- .../cc/services/attack/attack_report.py | 3 +- .../cc/services/attack/attack_schema.py | 9 ++++ .../attack/technique_reports/T1158.py | 38 ++++++++++++++ .../cc/services/config_schema.py | 5 ++ .../src/components/attack/techniques/T1158.js | 49 +++++++++++++++++++ 5 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 monkey/monkey_island/cc/services/attack/technique_reports/T1158.py create mode 100644 monkey/monkey_island/cc/ui/src/components/attack/techniques/T1158.js diff --git a/monkey/monkey_island/cc/services/attack/attack_report.py b/monkey/monkey_island/cc/services/attack/attack_report.py index b2ad3234a..882cb2b32 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, T1156, T1504 +from monkey_island.cc.services.attack.technique_reports import T1136, T1156, T1504, T1158 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 @@ -40,6 +40,7 @@ TECHNIQUES = {'T1210': T1210.T1210, 'T1136': T1136.T1136, 'T1156': T1156.T1156, 'T1504': T1504.T1504 + 'T1158': T1158.T1158 } 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 99e8dcfd2..3df8078da 100644 --- a/monkey/monkey_island/cc/services/attack/attack_schema.py +++ b/monkey/monkey_island/cc/services/attack/attack_schema.py @@ -99,6 +99,15 @@ SCHEMA = { "description": "Adversaries may gain persistence and elevate privileges " "in certain situations by abusing PowerShell profiles which " "are scripts that run when PowerShell starts." + "T1158": { + "title": "Hidden Files and Directories", + "type": "bool", + "value": True, + "necessary": False, + "link": "https://attack.mitre.org/techniques/T1158", + "description": "Adversaries can hide files and folders on the system " + "and evade a typical user or system analysis that does not " + "incorporate investigation of hidden files." } } }, diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1158.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1158.py new file mode 100644 index 000000000..b222d1eb5 --- /dev/null +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1158.py @@ -0,0 +1,38 @@ +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_HIDDEN_FILES + + +__author__ = "shreyamalviya" + + +class T1158(AttackTechnique): + tech_id = "T1158" + unscanned_msg = "Monkey did not try creating hidden files or folders." + scanned_msg = "Monkey tried creating hidden files and folders on the system but failed." + used_msg = "Monkey created hidden files and folders on the system." + + @staticmethod + def get_report_data(): + data = {'title': T1158.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_HIDDEN_FILES: + status = ScanStatus.USED.value if pba['result'][1]\ + else ScanStatus.SCANNED.value + data['info'].append({ + 'machine': { + 'hostname': pba['hostname'], + 'ips': node['ip_addresses'] + }, + 'type': 'Folder' if 'folder' in pba['command'] else 'File', + 'result': pba['result'][0] + }) + data.update(T1158.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 e37f3a75f..92b842757 100644 --- a/monkey/monkey_island/cc/services/config_schema.py +++ b/monkey/monkey_island/cc/services/config_schema.py @@ -167,6 +167,10 @@ SCHEMA = { ], "title": "Modify shell startup files", "attack_techniques": ["T1156", "T1504"] + "HiddenFiles" + ], + "title": "Hidden files and directories", + "attack_techniques": ["T1158"] } ], }, @@ -389,6 +393,7 @@ SCHEMA = { "BackdoorUser", "CommunicateAsNewUser", "ModifyShellStartupFiles" + "HiddenFiles" ], "description": "List of actions the Monkey will run post breach" }, diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1158.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1158.js new file mode 100644 index 000000000..9d41a50c4 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1158.js @@ -0,0 +1,49 @@ +import React from 'react'; +import ReactTable from 'react-table'; +import {renderMachineFromSystemData, ScanStatus} from './Helpers'; +import MitigationsComponent from './MitigationsComponent'; + +class T1158 extends React.Component { + + constructor(props) { + super(props); + } + + static getColumns() { + return ([{ + columns: [ + { Header: 'Machine', + id: 'machine', + accessor: x => renderMachineFromSystemData(x.machine), + style: {'whiteSpace': 'unset'}}, + { Header: 'File/Folder', + id: 'type', + accessor: x => x.type, + style: {'whiteSpace': 'unset'}, width: 160}, + { Header: 'Result', + id: 'result', + accessor: x => x.result, + style: {'whiteSpace': 'unset'}} + ] + }]) + } + + render() { + return ( +
+
{this.props.data.message}
+
+ {this.props.data.status === ScanStatus.USED ? + : ''} + +
+ ); + } +} + +export default T1158; From 80c8a42bd0b8f9d6937aafe21a2ccd9a086048ff Mon Sep 17 00:00:00 2001 From: Shreya Date: Fri, 5 Jun 2020 22:17:46 +0530 Subject: [PATCH 25/37] Mentioning 'type' doesn't seem necessary --- .../cc/services/attack/technique_reports/T1158.py | 1 - .../cc/ui/src/components/attack/techniques/T1158.js | 4 ---- 2 files changed, 5 deletions(-) diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1158.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1158.py index b222d1eb5..d0818c07f 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1158.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1158.py @@ -31,7 +31,6 @@ class T1158(AttackTechnique): 'hostname': pba['hostname'], 'ips': node['ip_addresses'] }, - 'type': 'Folder' if 'folder' in pba['command'] else 'File', 'result': pba['result'][0] }) data.update(T1158.get_base_data_by_status(status)) diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1158.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1158.js index 9d41a50c4..9fbf010de 100644 --- a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1158.js +++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1158.js @@ -16,10 +16,6 @@ class T1158 extends React.Component { id: 'machine', accessor: x => renderMachineFromSystemData(x.machine), style: {'whiteSpace': 'unset'}}, - { Header: 'File/Folder', - id: 'type', - accessor: x => x.type, - style: {'whiteSpace': 'unset'}, width: 160}, { Header: 'Result', id: 'result', accessor: x => x.result, From 6b4e90e6d02c4aa5102eeeab864a10fac7685093 Mon Sep 17 00:00:00 2001 From: Shreya Date: Sun, 7 Jun 2020 18:45:22 +0530 Subject: [PATCH 26/37] PBA tweaks: Windows --- monkey/infection_monkey/utils/hidden_files.py | 4 -- .../utils/windows/hidden_files.py | 50 ++++++++++++------- 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/monkey/infection_monkey/utils/hidden_files.py b/monkey/infection_monkey/utils/hidden_files.py index cf37a0b1a..bf464209b 100644 --- a/monkey/infection_monkey/utils/hidden_files.py +++ b/monkey/infection_monkey/utils/hidden_files.py @@ -23,10 +23,6 @@ def get_commands_to_hide_folders(): return linux_cmds, windows_cmds -def get_winAPI_to_hide_files(): - get_winAPI_to_hide_files() - - def cleanup_hidden_files(is_windows=is_windows_os()): subprocess.run(get_windows_commands_to_delete() if is_windows else get_linux_commands_to_delete()) diff --git a/monkey/infection_monkey/utils/windows/hidden_files.py b/monkey/infection_monkey/utils/windows/hidden_files.py index e188f1bc1..7740669f1 100644 --- a/monkey/infection_monkey/utils/windows/hidden_files.py +++ b/monkey/infection_monkey/utils/windows/hidden_files.py @@ -1,30 +1,40 @@ -HIDDEN_FILE = 'C:\\monkey-hidden-file' -HIDDEN_FILE_WINAPI = 'C:\\monkey-hidden-file-winAPI' -HIDDEN_FOLDER = 'C:\\monkey-hidden-folder' +HIDDEN_FILE = "%temp%\\monkey-hidden-file" +HIDDEN_FILE_WINAPI = "%temp%\\monkey-hidden-file-winAPI" +HIDDEN_FOLDER = "%temp%\\monkey-hidden-folder" def get_windows_commands_to_hide_files(): return [ - 'type NUL >', # create empty file + 'echo', + 'Successfully created hidden file: {}'.format(HIDDEN_FILE), # create empty file + '>', HIDDEN_FILE, - '&& attrib', # change file attributes + '&&', + 'attrib', # change file attributes '+h', # make hidden HIDDEN_FILE, - 'echo Successfully created hidden file: {0} > {0}'.format(HIDDEN_FILE), - '&& type {}'.format(HIDDEN_FILE) + '&&', + 'type', + HIDDEN_FILE ] def get_windows_commands_to_hide_folders(): return [ - 'mkdir', # make directory - HIDDEN_FOLDER, - '&& attrib', # change file attributes - '+h', # make hidden - HIDDEN_FOLDER, - '&& echo Successfully created hidden folder: {} >'.format(HIDDEN_FOLDER), + 'mkdir', + HIDDEN_FOLDER, # make directory + '&&', + 'attrib', + '+h', + HIDDEN_FOLDER, # change file attributes + '&&', + 'echo', + 'Successfully created hidden folder: {}'.format(HIDDEN_FOLDER), + '>', '{}\\{}'.format(HIDDEN_FOLDER, 'some-file'), - '&& type {}'.format(HIDDEN_FOLDER, 'some-file') + '&&', + 'type', + '{}\\{}'.format(HIDDEN_FOLDER, 'some-file') ] @@ -37,11 +47,11 @@ def get_winAPI_to_hide_files(): hiddenFile = win32file.CreateFile(HIDDEN_FILE_WINAPI, fileAccess, - 0, - None, + 0, # sharing mode: 0 => can't be shared + None, # security attributes fileCreation, fileFlags, - 0) + 0) # template file return "Succesfully created hidden file: {}".format(HIDDEN_FILE_WINAPI), True except Exception as err: @@ -51,9 +61,11 @@ def get_winAPI_to_hide_files(): def get_windows_commands_to_delete(): return [ 'del', # delete file - '/f', # force delete + '-Force', # force delete HIDDEN_FILE, HIDDEN_FILE_WINAPI, - '&& rmdir', # delete folder + '&&', + 'rmdir', # delete folder + '-Force', HIDDEN_FOLDER ] From eea5352084e7a0355a972187baac91f26272f460 Mon Sep 17 00:00:00 2001 From: Shreya Date: Sun, 7 Jun 2020 20:21:09 +0530 Subject: [PATCH 27/37] Little changes based on review --- monkey/infection_monkey/post_breach/actions/hide_files.py | 8 ++++---- monkey/infection_monkey/utils/linux/hidden_files.py | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/monkey/infection_monkey/post_breach/actions/hide_files.py b/monkey/infection_monkey/post_breach/actions/hide_files.py index ee5a7add9..1111f3cf4 100644 --- a/monkey/infection_monkey/post_breach/actions/hide_files.py +++ b/monkey/infection_monkey/post_breach/actions/hide_files.py @@ -10,8 +10,8 @@ from infection_monkey.utils.hidden_files import\ from infection_monkey.utils.environment import is_windows_os -CREATE_HIDDEN = [get_commands_to_hide_files, - get_commands_to_hide_folders] +HIDDEN_FSO_CREATION_COMMANDS = [get_commands_to_hide_files, + get_commands_to_hide_folders] class HiddenFiles(PBA): @@ -24,8 +24,8 @@ class HiddenFiles(PBA): def run(self): # create hidden files and folders - for method_to_create in CREATE_HIDDEN: - linux_cmds, windows_cmds = method_to_create() + for function_to_get_commands in HIDDEN_FSO_CREATION_COMMANDS: + linux_cmds, windows_cmds = function_to_get_commands() super(HiddenFiles, self).__init__(name=POST_BREACH_HIDDEN_FILES, linux_cmd=' '.join(linux_cmds), windows_cmd=windows_cmds) diff --git a/monkey/infection_monkey/utils/linux/hidden_files.py b/monkey/infection_monkey/utils/linux/hidden_files.py index 028edf4a1..26b96b16c 100644 --- a/monkey/infection_monkey/utils/linux/hidden_files.py +++ b/monkey/infection_monkey/utils/linux/hidden_files.py @@ -6,7 +6,8 @@ def get_linux_commands_to_hide_files(): return [ 'touch', # create file HIDDEN_FILE, - '; echo \"Successfully created hidden file: {}\" |'.format(HIDDEN_FILE), # output + '&&' + 'echo \"Successfully created hidden file: {}\" |'.format(HIDDEN_FILE), # output 'tee -a', # and write to file HIDDEN_FILE ] From 87bfe41c50ff3c36c65c6d6b7fad9f7ef0610608 Mon Sep 17 00:00:00 2001 From: Shreya Date: Sun, 21 Jun 2020 01:06:45 +0530 Subject: [PATCH 28/37] Linux: change location of hidden file/folder --- .../utils/linux/hidden_files.py | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/monkey/infection_monkey/utils/linux/hidden_files.py b/monkey/infection_monkey/utils/linux/hidden_files.py index 26b96b16c..ca03e8809 100644 --- a/monkey/infection_monkey/utils/linux/hidden_files.py +++ b/monkey/infection_monkey/utils/linux/hidden_files.py @@ -1,35 +1,35 @@ -HIDDEN_FILE = '/var/tmp/.monkey-hidden-file' -HIDDEN_FOLDER = '/var/tmp/.monkey-hidden-folder' +HIDDEN_FILE = '$HOME/.monkey-hidden-file' +HIDDEN_FOLDER = '$HOME/.monkey-hidden-folder' def get_linux_commands_to_hide_files(): return [ - 'touch', # create file + 'touch', # create file HIDDEN_FILE, '&&' 'echo \"Successfully created hidden file: {}\" |'.format(HIDDEN_FILE), # output - 'tee -a', # and write to file + 'tee -a', # and write to file HIDDEN_FILE ] def get_linux_commands_to_hide_folders(): return [ - 'mkdir', # make directory + 'mkdir', # make directory HIDDEN_FOLDER, '; touch', # create file - '{}/{}'.format(HIDDEN_FOLDER, 'some-file'), # random file in hidden folder + '{}/{}'.format(HIDDEN_FOLDER, 'some-file'), # random file in hidden folder '; echo \"Successfully created hidden folder: {}\" |'.format(HIDDEN_FOLDER), # output - 'tee -a', # and write to file - '{}/{}'.format(HIDDEN_FOLDER, 'some-file') # random file in hidden folder + 'tee -a', # and write to file + '{}/{}'.format(HIDDEN_FOLDER, 'some-file') # random file in hidden folder ] def get_linux_commands_to_delete(): return [ - 'rm', # remove - '-r', # delete recursively - '-f', # force delete + 'rm', # remove + '-r', # delete recursively + '-f', # force delete HIDDEN_FILE, HIDDEN_FOLDER ] From a98f321ed074f14b04768ce72b15d4baf7837ca8 Mon Sep 17 00:00:00 2001 From: Shreya Date: Sun, 21 Jun 2020 01:23:53 +0530 Subject: [PATCH 29/37] Windows: change location of hidden file/folder + add system attribute --- .../utils/windows/hidden_files.py | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/monkey/infection_monkey/utils/windows/hidden_files.py b/monkey/infection_monkey/utils/windows/hidden_files.py index 7740669f1..ce1bf3450 100644 --- a/monkey/infection_monkey/utils/windows/hidden_files.py +++ b/monkey/infection_monkey/utils/windows/hidden_files.py @@ -1,6 +1,6 @@ -HIDDEN_FILE = "%temp%\\monkey-hidden-file" -HIDDEN_FILE_WINAPI = "%temp%\\monkey-hidden-file-winAPI" -HIDDEN_FOLDER = "%temp%\\monkey-hidden-folder" +HIDDEN_FILE = "%homepath%\\monkey-hidden-file" +HIDDEN_FILE_WINAPI = "%homepath%\\monkey-hidden-file-winAPI" +HIDDEN_FOLDER = "%homepath%\\monkey-hidden-folder" def get_windows_commands_to_hide_files(): @@ -10,8 +10,9 @@ def get_windows_commands_to_hide_files(): '>', HIDDEN_FILE, '&&', - 'attrib', # change file attributes - '+h', # make hidden + 'attrib', # change file attributes + '+h', # hidden attribute + '+s', # system attribute HIDDEN_FILE, '&&', 'type', @@ -25,7 +26,8 @@ def get_windows_commands_to_hide_folders(): HIDDEN_FOLDER, # make directory '&&', 'attrib', - '+h', + '+h', # hidden attribute + '+s', # system attribute HIDDEN_FOLDER, # change file attributes '&&', 'echo', @@ -60,12 +62,12 @@ def get_winAPI_to_hide_files(): def get_windows_commands_to_delete(): return [ - 'del', # delete file - '-Force', # force delete + 'del', # delete file + '-Force', # force delete HIDDEN_FILE, HIDDEN_FILE_WINAPI, '&&', - 'rmdir', # delete folder + 'rmdir', # delete folder '-Force', HIDDEN_FOLDER ] From d0dc305a3390335a3457defef087b6fb04c4a8c8 Mon Sep 17 00:00:00 2001 From: Shreya Date: Sun, 21 Jun 2020 01:28:13 +0530 Subject: [PATCH 30/37] Remove detection time for AV software --- monkey/infection_monkey/post_breach/actions/hide_files.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/monkey/infection_monkey/post_breach/actions/hide_files.py b/monkey/infection_monkey/post_breach/actions/hide_files.py index 1111f3cf4..eadd31e61 100644 --- a/monkey/infection_monkey/post_breach/actions/hide_files.py +++ b/monkey/infection_monkey/post_breach/actions/hide_files.py @@ -34,8 +34,5 @@ class HiddenFiles(PBA): result, status = get_winAPI_to_hide_files() PostBreachTelem(self, (result, status)).send() - # detection time for AV software - time.sleep(10) - # cleanup hidden files and folders cleanup_hidden_files(is_windows_os()) From 2dbf798c4a94d254c7f1bd97f716de67988fffe9 Mon Sep 17 00:00:00 2001 From: Shreya Date: Sun, 21 Jun 2020 20:07:12 +0530 Subject: [PATCH 31/37] Linux: fix hidden file/folder deletion issue --- monkey/infection_monkey/utils/hidden_files.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkey/infection_monkey/utils/hidden_files.py b/monkey/infection_monkey/utils/hidden_files.py index bf464209b..ee1281cd7 100644 --- a/monkey/infection_monkey/utils/hidden_files.py +++ b/monkey/infection_monkey/utils/hidden_files.py @@ -25,4 +25,4 @@ def get_commands_to_hide_folders(): def cleanup_hidden_files(is_windows=is_windows_os()): subprocess.run(get_windows_commands_to_delete() if is_windows - else get_linux_commands_to_delete()) + else ' '.join(get_linux_commands_to_delete())) From 3819041632dbb2c11c4352885ce5086e3f3686d7 Mon Sep 17 00:00:00 2001 From: Shreya Date: Mon, 22 Jun 2020 02:09:25 +0530 Subject: [PATCH 32/37] PBA command modifications --- .../post_breach/actions/hide_files.py | 1 - monkey/infection_monkey/utils/hidden_files.py | 3 ++- .../utils/linux/hidden_files.py | 7 +++---- .../utils/windows/hidden_files.py | 18 +++++++++++++----- 4 files changed, 18 insertions(+), 11 deletions(-) diff --git a/monkey/infection_monkey/post_breach/actions/hide_files.py b/monkey/infection_monkey/post_breach/actions/hide_files.py index eadd31e61..da9caca6c 100644 --- a/monkey/infection_monkey/post_breach/actions/hide_files.py +++ b/monkey/infection_monkey/post_breach/actions/hide_files.py @@ -1,4 +1,3 @@ -import time from common.data.post_breach_consts import POST_BREACH_HIDDEN_FILES from infection_monkey.post_breach.pba import PBA from infection_monkey.telemetry.post_breach_telem import PostBreachTelem diff --git a/monkey/infection_monkey/utils/hidden_files.py b/monkey/infection_monkey/utils/hidden_files.py index ee1281cd7..2c629af39 100644 --- a/monkey/infection_monkey/utils/hidden_files.py +++ b/monkey/infection_monkey/utils/hidden_files.py @@ -25,4 +25,5 @@ def get_commands_to_hide_folders(): def cleanup_hidden_files(is_windows=is_windows_os()): subprocess.run(get_windows_commands_to_delete() if is_windows - else ' '.join(get_linux_commands_to_delete())) + else ' '.join(get_linux_commands_to_delete()), + shell=True) diff --git a/monkey/infection_monkey/utils/linux/hidden_files.py b/monkey/infection_monkey/utils/linux/hidden_files.py index ca03e8809..468318cf8 100644 --- a/monkey/infection_monkey/utils/linux/hidden_files.py +++ b/monkey/infection_monkey/utils/linux/hidden_files.py @@ -17,9 +17,9 @@ def get_linux_commands_to_hide_folders(): return [ 'mkdir', # make directory HIDDEN_FOLDER, - '; touch', # create file + '&& touch', # create file '{}/{}'.format(HIDDEN_FOLDER, 'some-file'), # random file in hidden folder - '; echo \"Successfully created hidden folder: {}\" |'.format(HIDDEN_FOLDER), # output + '&& echo \"Successfully created hidden folder: {}\" |'.format(HIDDEN_FOLDER), # output 'tee -a', # and write to file '{}/{}'.format(HIDDEN_FOLDER, 'some-file') # random file in hidden folder ] @@ -28,8 +28,7 @@ def get_linux_commands_to_hide_folders(): def get_linux_commands_to_delete(): return [ 'rm', # remove - '-r', # delete recursively - '-f', # force delete + '-rf', # force delete recursively HIDDEN_FILE, HIDDEN_FOLDER ] diff --git a/monkey/infection_monkey/utils/windows/hidden_files.py b/monkey/infection_monkey/utils/windows/hidden_files.py index ce1bf3450..3ffad48f5 100644 --- a/monkey/infection_monkey/utils/windows/hidden_files.py +++ b/monkey/infection_monkey/utils/windows/hidden_files.py @@ -1,6 +1,11 @@ -HIDDEN_FILE = "%homepath%\\monkey-hidden-file" -HIDDEN_FILE_WINAPI = "%homepath%\\monkey-hidden-file-winAPI" -HIDDEN_FOLDER = "%homepath%\\monkey-hidden-folder" +import os + + +HOME_PATH = os.path.expanduser("~") + +HIDDEN_FILE = HOME_PATH + "\\monkey-hidden-file" +HIDDEN_FOLDER = HOME_PATH + "\\monkey-hidden-folder" +HIDDEN_FILE_WINAPI = HOME_PATH + "\\monkey-hidden-file-winAPI" def get_windows_commands_to_hide_files(): @@ -62,12 +67,15 @@ def get_winAPI_to_hide_files(): def get_windows_commands_to_delete(): return [ + 'powershell.exe', 'del', # delete file - '-Force', # force delete + '-Force', HIDDEN_FILE, + ',', HIDDEN_FILE_WINAPI, - '&&', + ';', 'rmdir', # delete folder '-Force', + '-Recurse', HIDDEN_FOLDER ] From 37d37b6f9f7b700afbb374566583bf97c3c0c8d8 Mon Sep 17 00:00:00 2001 From: Shreya Date: Mon, 22 Jun 2020 02:09:47 +0530 Subject: [PATCH 33/37] Fix status being sent in report data --- .../cc/services/attack/technique_reports/T1158.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1158.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1158.py index d0818c07f..f3615c2ff 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1158.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1158.py @@ -18,14 +18,13 @@ class T1158(AttackTechnique): data = {'title': T1158.technique_title(), 'info': []} scanned_nodes = ReportService.get_scanned() - status = ScanStatus.UNSCANNED.value + status = [] for node in scanned_nodes: if node['pba_results'] != 'None': for pba in node['pba_results']: if pba['name'] == POST_BREACH_HIDDEN_FILES: - status = ScanStatus.USED.value if pba['result'][1]\ - else ScanStatus.SCANNED.value + status.append(pba['result'][1]) data['info'].append({ 'machine': { 'hostname': pba['hostname'], @@ -33,5 +32,7 @@ class T1158(AttackTechnique): }, 'result': pba['result'][0] }) - data.update(T1158.get_base_data_by_status(status)) + status = (ScanStatus.USED.value if any(status) else ScanStatus.SCANNED.value)\ + if status else ScanStatus.UNSCANNEDvalue + data.update(T1158.get_base_data_by_status(status)) return data From a91e65e49a061c62e6f26961bf59e38ea071133b Mon Sep 17 00:00:00 2001 From: Shreya Date: Mon, 22 Jun 2020 14:25:36 +0530 Subject: [PATCH 34/37] Use mongo search for report data --- .../attack/technique_reports/T1158.py | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1158.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1158.py index f3615c2ff..a90ee6e1f 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1158.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1158.py @@ -1,5 +1,5 @@ from monkey_island.cc.services.attack.technique_reports import AttackTechnique -from monkey_island.cc.services.reporting.report import ReportService +from monkey_island.cc.database import mongo from common.utils.attack_utils import ScanStatus from common.data.post_breach_consts import POST_BREACH_HIDDEN_FILES @@ -13,26 +13,25 @@ class T1158(AttackTechnique): scanned_msg = "Monkey tried creating hidden files and folders on the system but failed." used_msg = "Monkey created hidden files and folders on the system." + query = [{'$match': {'telem_category': 'post_breach', + 'data.name': POST_BREACH_HIDDEN_FILES}}, + {'$project': {'_id': 0, + 'machine': {'hostname': '$data.hostname', + 'ips': ['$data.ip']}, + 'result': '$data.result'}}] + @staticmethod def get_report_data(): data = {'title': T1158.technique_title(), 'info': []} - scanned_nodes = ReportService.get_scanned() - status = [] + hidden_file_info = list(mongo.db.telemetry.aggregate(T1158.query)) - for node in scanned_nodes: - if node['pba_results'] != 'None': - for pba in node['pba_results']: - if pba['name'] == POST_BREACH_HIDDEN_FILES: - status.append(pba['result'][1]) - data['info'].append({ - 'machine': { - 'hostname': pba['hostname'], - 'ips': node['ip_addresses'] - }, - 'result': pba['result'][0] - }) + status = [] + for pba_node in hidden_file_info: + status.append(pba_node['result'][1]) status = (ScanStatus.USED.value if any(status) else ScanStatus.SCANNED.value)\ - if status else ScanStatus.UNSCANNEDvalue + if status else ScanStatus.UNSCANNED.value + data.update(T1158.get_base_data_by_status(status)) + data.update({'info': hidden_file_info}) return data From 6b750928236adb7d3589413522d2ac095b63e54e Mon Sep 17 00:00:00 2001 From: Shreya Date: Wed, 24 Jun 2020 15:15:45 +0530 Subject: [PATCH 35/37] Small fixes after rebasing --- monkey/monkey_island/cc/services/attack/attack_report.py | 2 +- monkey/monkey_island/cc/services/attack/attack_schema.py | 1 + monkey/monkey_island/cc/services/config_schema.py | 6 +++++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/monkey/monkey_island/cc/services/attack/attack_report.py b/monkey/monkey_island/cc/services/attack/attack_report.py index 882cb2b32..16e6e51a1 100644 --- a/monkey/monkey_island/cc/services/attack/attack_report.py +++ b/monkey/monkey_island/cc/services/attack/attack_report.py @@ -39,7 +39,7 @@ TECHNIQUES = {'T1210': T1210.T1210, 'T1064': T1064.T1064, 'T1136': T1136.T1136, 'T1156': T1156.T1156, - 'T1504': T1504.T1504 + 'T1504': T1504.T1504, 'T1158': T1158.T1158 } diff --git a/monkey/monkey_island/cc/services/attack/attack_schema.py b/monkey/monkey_island/cc/services/attack/attack_schema.py index 3df8078da..04c63a850 100644 --- a/monkey/monkey_island/cc/services/attack/attack_schema.py +++ b/monkey/monkey_island/cc/services/attack/attack_schema.py @@ -99,6 +99,7 @@ SCHEMA = { "description": "Adversaries may gain persistence and elevate privileges " "in certain situations by abusing PowerShell profiles which " "are scripts that run when PowerShell starts." + }, "T1158": { "title": "Hidden Files and Directories", "type": "bool", diff --git a/monkey/monkey_island/cc/services/config_schema.py b/monkey/monkey_island/cc/services/config_schema.py index 92b842757..30425dc1d 100644 --- a/monkey/monkey_island/cc/services/config_schema.py +++ b/monkey/monkey_island/cc/services/config_schema.py @@ -167,6 +167,10 @@ SCHEMA = { ], "title": "Modify shell startup files", "attack_techniques": ["T1156", "T1504"] + }, + { + "type": "string", + "enum": [ "HiddenFiles" ], "title": "Hidden files and directories", @@ -392,7 +396,7 @@ SCHEMA = { "default": [ "BackdoorUser", "CommunicateAsNewUser", - "ModifyShellStartupFiles" + "ModifyShellStartupFiles", "HiddenFiles" ], "description": "List of actions the Monkey will run post breach" From 971a102eb6d066a228d2fb92f810f83084ebd2ae Mon Sep 17 00:00:00 2001 From: Shreya Date: Wed, 24 Jun 2020 15:19:07 +0530 Subject: [PATCH 36/37] Change order of techniques in ATT&CK matrix T1158: Hidden files before T1504: Powershell profile --- .../cc/services/attack/attack_schema.py | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/monkey/monkey_island/cc/services/attack/attack_schema.py b/monkey/monkey_island/cc/services/attack/attack_schema.py index 04c63a850..c70ff2a70 100644 --- a/monkey/monkey_island/cc/services/attack/attack_schema.py +++ b/monkey/monkey_island/cc/services/attack/attack_schema.py @@ -90,6 +90,16 @@ SCHEMA = { "description": "Adversaries with a sufficient level of access " "may create a local system, domain, or cloud tenant account." }, + "T1158": { + "title": "Hidden files and directories", + "type": "bool", + "value": True, + "necessary": False, + "link": "https://attack.mitre.org/techniques/T1158", + "description": "Adversaries can hide files and folders on the system " + "and evade a typical user or system analysis that does not " + "incorporate investigation of hidden files." + }, "T1504": { "title": "PowerShell profile", "type": "bool", @@ -99,16 +109,6 @@ SCHEMA = { "description": "Adversaries may gain persistence and elevate privileges " "in certain situations by abusing PowerShell profiles which " "are scripts that run when PowerShell starts." - }, - "T1158": { - "title": "Hidden Files and Directories", - "type": "bool", - "value": True, - "necessary": False, - "link": "https://attack.mitre.org/techniques/T1158", - "description": "Adversaries can hide files and folders on the system " - "and evade a typical user or system analysis that does not " - "incorporate investigation of hidden files." } } }, From a11852ce3ca024ec70d5830496a7455689ab3b67 Mon Sep 17 00:00:00 2001 From: Shreya Date: Wed, 24 Jun 2020 16:11:14 +0530 Subject: [PATCH 37/37] Pass build Pass build --- .../post_breach/actions/modify_shell_startup_files.py | 2 +- .../linux/shell_startup_files_modification.py | 2 +- .../windows/shell_startup_files_modification.py | 2 +- monkey/infection_monkey/utils/hidden_files.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) 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 index 095c7cb11..383a7ae4c 100644 --- a/monkey/infection_monkey/post_breach/actions/modify_shell_startup_files.py +++ b/monkey/infection_monkey/post_breach/actions/modify_shell_startup_files.py @@ -21,7 +21,7 @@ class ModifyShellStartupFiles(PBA): class ShellStartupPBAGenerator(): def get_modify_shell_startup_pbas(): (cmds_for_linux, shell_startup_files_for_linux, usernames_for_linux),\ - (cmds_for_windows, shell_startup_files_per_user_for_windows) = get_commands_to_modify_shell_startup_files() + (cmds_for_windows, shell_startup_files_per_user_for_windows) = get_commands_to_modify_shell_startup_files() pbas = [] diff --git a/monkey/infection_monkey/post_breach/shell_startup_files/linux/shell_startup_files_modification.py b/monkey/infection_monkey/post_breach/shell_startup_files/linux/shell_startup_files_modification.py index 8a1ed7246..b18dff768 100644 --- a/monkey/infection_monkey/post_breach/shell_startup_files/linux/shell_startup_files_modification.py +++ b/monkey/infection_monkey/post_breach/shell_startup_files/linux/shell_startup_files_modification.py @@ -9,7 +9,7 @@ def get_linux_commands_to_modify_shell_startup_files(): HOME_DIR = "/home/" # get list of usernames - USERS = subprocess.check_output( + USERS = subprocess.check_output( # noqa: DUO116 "cut -d: -f1,3 /etc/passwd | egrep ':[0-9]{4}$' | cut -d: -f1", shell=True ).decode().split('\n')[:-1] diff --git a/monkey/infection_monkey/post_breach/shell_startup_files/windows/shell_startup_files_modification.py b/monkey/infection_monkey/post_breach/shell_startup_files/windows/shell_startup_files_modification.py index a9116c221..68889f28c 100644 --- a/monkey/infection_monkey/post_breach/shell_startup_files/windows/shell_startup_files_modification.py +++ b/monkey/infection_monkey/post_breach/shell_startup_files/windows/shell_startup_files_modification.py @@ -11,7 +11,7 @@ def get_windows_commands_to_modify_shell_startup_files(): SHELL_STARTUP_FILE_PATH_COMPONENTS = SHELL_STARTUP_FILE.split("\\") # get list of usernames - USERS = subprocess.check_output('dir C:\\Users /b', shell=True).decode().split("\r\n")[:-1] + USERS = subprocess.check_output('dir C:\\Users /b', shell=True).decode().split("\r\n")[:-1] # noqa: DUO116 STARTUP_FILES_PER_USER = ['\\'.join(SHELL_STARTUP_FILE_PATH_COMPONENTS[:2] + [user] + diff --git a/monkey/infection_monkey/utils/hidden_files.py b/monkey/infection_monkey/utils/hidden_files.py index 2c629af39..4fe520177 100644 --- a/monkey/infection_monkey/utils/hidden_files.py +++ b/monkey/infection_monkey/utils/hidden_files.py @@ -24,6 +24,6 @@ def get_commands_to_hide_folders(): def cleanup_hidden_files(is_windows=is_windows_os()): - subprocess.run(get_windows_commands_to_delete() if is_windows + subprocess.run(get_windows_commands_to_delete() if is_windows # noqa: DUO116 else ' '.join(get_linux_commands_to_delete()), shell=True)