diff --git a/monkey/common/data/post_breach_consts.py b/monkey/common/data/post_breach_consts.py index c3bba9950..514086b16 100644 --- a/monkey/common/data/post_breach_consts.py +++ b/monkey/common/data/post_breach_consts.py @@ -6,3 +6,4 @@ POST_BREACH_HIDDEN_FILES = "Hide files and directories" POST_BREACH_TRAP_COMMAND = "Execute command when a particular signal is received" POST_BREACH_SETUID_SETGID = "Setuid and Setgid" POST_BREACH_JOB_SCHEDULING = "Schedule jobs" +POST_BREACH_SIGNED_SCRIPT_PROXY_EXEC = "Signed script proxy execution" diff --git a/monkey/infection_monkey/post_breach/actions/use_signed_scripts.py b/monkey/infection_monkey/post_breach/actions/use_signed_scripts.py new file mode 100644 index 000000000..a4c299ba8 --- /dev/null +++ b/monkey/infection_monkey/post_breach/actions/use_signed_scripts.py @@ -0,0 +1,13 @@ +from common.data.post_breach_consts import POST_BREACH_SIGNED_SCRIPT_PROXY_EXEC +from infection_monkey.post_breach.pba import PBA +from infection_monkey.post_breach.signed_script_proxy.signed_script_proxy import ( + cleanup_changes, get_commands_to_proxy_execution_using_signed_script) + + +class SignedScriptProxyExecution(PBA): + def __init__(self): + windows_cmds = get_commands_to_proxy_execution_using_signed_script() + super().__init__(POST_BREACH_SIGNED_SCRIPT_PROXY_EXEC, + windows_cmd=' '.join(windows_cmds)) + + cleanup_changes() diff --git a/monkey/infection_monkey/post_breach/signed_script_proxy/signed_script_proxy.py b/monkey/infection_monkey/post_breach/signed_script_proxy/signed_script_proxy.py new file mode 100644 index 000000000..6b940a4ef --- /dev/null +++ b/monkey/infection_monkey/post_breach/signed_script_proxy/signed_script_proxy.py @@ -0,0 +1,16 @@ +import subprocess + +from infection_monkey.post_breach.signed_script_proxy.windows.signed_script_proxy import ( + get_windows_commands_to_proxy_execution_using_signed_script, + get_windows_commands_to_reset_comspec) +from infection_monkey.utils.environment import is_windows_os + + +def get_commands_to_proxy_execution_using_signed_script(): + windows_cmds = get_windows_commands_to_proxy_execution_using_signed_script() + return windows_cmds + + +def cleanup_changes(): + if is_windows_os(): + subprocess.run(get_windows_commands_to_reset_comspec(), shell=True) # noqa: DUO116 diff --git a/monkey/infection_monkey/post_breach/signed_script_proxy/windows/random_executable.exe b/monkey/infection_monkey/post_breach/signed_script_proxy/windows/random_executable.exe new file mode 100644 index 000000000..0b1c3f6be Binary files /dev/null and b/monkey/infection_monkey/post_breach/signed_script_proxy/windows/random_executable.exe differ diff --git a/monkey/infection_monkey/post_breach/signed_script_proxy/windows/signed_script_proxy.py b/monkey/infection_monkey/post_breach/signed_script_proxy/windows/signed_script_proxy.py new file mode 100644 index 000000000..ea19ce248 --- /dev/null +++ b/monkey/infection_monkey/post_breach/signed_script_proxy/windows/signed_script_proxy.py @@ -0,0 +1,16 @@ +import subprocess + +ORIGINAL_COMSPEC = r'C:\Windows\System32\cmd.exe' + + +def get_windows_commands_to_proxy_execution_using_signed_script(): + global ORIGINAL_COMSPEC + ORIGINAL_COMSPEC = subprocess.check_output('echo %COMSPEC%', shell=True).decode() # noqa: DUO116 + return [ + r'set comspec=infection_monkey\post_breach\signed_script_proxy\windows\random_executable.exe &&', + r'cscript C:\Windows\System32\manage-bde.wsf' + ] + + +def get_windows_commands_to_reset_comspec(): + return f'set comspec={ORIGINAL_COMSPEC}' diff --git a/monkey/monkey_island/cc/services/attack/attack_report.py b/monkey/monkey_island/cc/services/attack/attack_report.py index 6d4bac9ed..578ad8a79 100644 --- a/monkey/monkey_island/cc/services/attack/attack_report.py +++ b/monkey/monkey_island/cc/services/attack/attack_report.py @@ -18,7 +18,8 @@ from monkey_island.cc.services.attack.technique_reports import (T1003, T1005, T1158, T1166, T1168, T1188, T1197, T1210, - T1222, T1504) + T1216, T1222, + T1504) from monkey_island.cc.services.reporting.report_generation_synchronisation import \ safe_generate_attack_report @@ -57,7 +58,8 @@ TECHNIQUES = {'T1210': T1210.T1210, 'T1154': T1154.T1154, 'T1166': T1166.T1166, 'T1168': T1168.T1168, - 'T1053': T1053.T1053 + 'T1053': T1053.T1053, + 'T1216': T1216.T1216 } 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 30d33ca3e..ea4cb54df 100644 --- a/monkey/monkey_island/cc/services/attack/attack_schema.py +++ b/monkey/monkey_island/cc/services/attack/attack_schema.py @@ -185,6 +185,15 @@ SCHEMA = { "necessary": True, "link": "https://attack.mitre.org/techniques/T1222", "description": "Adversaries may modify file permissions/attributes to evade intended DACLs." + }, + "T1216": { + "title": "Signed script proxy execution", + "type": "bool", + "value": True, + "necessary": False, + "link": "https://attack.mitre.org/techniques/T1216", + "description": "Adversaries may use scripts signed with trusted certificates to " + "proxy execution of malicious files on Windows systems." } } }, diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1216.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1216.py new file mode 100644 index 000000000..6e4fa2b00 --- /dev/null +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1216.py @@ -0,0 +1,15 @@ +from common.data.post_breach_consts import POST_BREACH_SIGNED_SCRIPT_PROXY_EXEC +from monkey_island.cc.services.attack.technique_reports.pba_technique import \ + PostBreachTechnique + +__author__ = "shreyamalviya" + + +class T1216(PostBreachTechnique): + tech_id = "T1216" + unscanned_msg = "Monkey didn't attempt to execute an arbitrary file with the help of a " +\ + "pre-existing signed script since it didn't run on any Windows machines." + scanned_msg = "Monkey attempted to execute an arbitrary file with the help of a " +\ + "pre-existing signed script on Windows but failed." + used_msg = "Monkey executed an arbitrary file with the help of a pre-existing signed script on Windows." + pba_names = [POST_BREACH_SIGNED_SCRIPT_PROXY_EXEC] diff --git a/monkey/monkey_island/cc/services/config_schema/definitions/post_breach_actions.py b/monkey/monkey_island/cc/services/config_schema/definitions/post_breach_actions.py index f3e2a9bfa..dd113881b 100644 --- a/monkey/monkey_island/cc/services/config_schema/definitions/post_breach_actions.py +++ b/monkey/monkey_island/cc/services/config_schema/definitions/post_breach_actions.py @@ -70,6 +70,16 @@ POST_BREACH_ACTIONS = { "title": "Job scheduling", "info": "Attempts to create a scheduled job on the system and remove it.", "attack_techniques": ["T1168", "T1053"] + }, + { + "type": "string", + "enum": [ + "SignedScriptProxyExecution" + ], + "title": "Signed script proxy execution", + "info": "On Windows systems, attemps to execute an arbitrary file " + "with the help of a pre-existing signed script.", + "attack_techniques": ["T1216"] } ] } diff --git a/monkey/monkey_island/cc/services/config_schema/monkey.py b/monkey/monkey_island/cc/services/config_schema/monkey.py index dd10cb35b..28f7785b0 100644 --- a/monkey/monkey_island/cc/services/config_schema/monkey.py +++ b/monkey/monkey_island/cc/services/config_schema/monkey.py @@ -67,7 +67,8 @@ MONKEY = { "HiddenFiles", "TrapCommand", "ChangeSetuidSetgid", - "ScheduleJobs" + "ScheduleJobs", + "SignedScriptProxyExecution" ] }, } diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1216.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1216.js new file mode 100644 index 000000000..e608492a1 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1216.js @@ -0,0 +1,45 @@ +import React from 'react'; +import ReactTable from 'react-table'; +import {renderMachineFromSystemData, ScanStatus} from './Helpers'; +import MitigationsComponent from './MitigationsComponent'; + +class T1216 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 ( +