Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions monkey/common/data/post_breach_consts.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,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"
19 changes: 19 additions & 0 deletions monkey/infection_monkey/post_breach/actions/schedule_jobs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from common.data.post_breach_consts import POST_BREACH_JOB_SCHEDULING
from infection_monkey.post_breach.pba import PBA
from infection_monkey.post_breach.job_scheduling.job_scheduling import\
get_commands_to_schedule_jobs, remove_scheduled_jobs


class ScheduleJobs(PBA):
"""
This PBA attempts to schedule jobs on the system.
"""

def __init__(self):
linux_cmds, windows_cmds = get_commands_to_schedule_jobs()

super(ScheduleJobs, self).__init__(name=POST_BREACH_JOB_SCHEDULING,
linux_cmd=' '.join(linux_cmds),
windows_cmd=windows_cmds)

remove_scheduled_jobs()
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import subprocess
from infection_monkey.post_breach.job_scheduling.linux_job_scheduling import\
get_linux_commands_to_schedule_jobs
from infection_monkey.post_breach.job_scheduling.windows_job_scheduling import\
get_windows_commands_to_schedule_jobs,\
get_windows_commands_to_remove_scheduled_jobs
from infection_monkey.utils.environment import is_windows_os


def get_commands_to_schedule_jobs():
linux_cmds = get_linux_commands_to_schedule_jobs()
windows_cmds = get_windows_commands_to_schedule_jobs()
return linux_cmds, windows_cmds


def remove_scheduled_jobs():
if is_windows_os():
subprocess.run(get_windows_commands_to_remove_scheduled_jobs(), shell=True) # noqa: DUO116
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
TEMP_CRON = "$HOME/monkey-schedule-jobs"


def get_linux_commands_to_schedule_jobs():
return [
f'touch {TEMP_CRON} &&',
f'crontab -l > {TEMP_CRON} &&',
'echo \"# Successfully scheduled a job using crontab\" |',
f'tee -a {TEMP_CRON} &&',
f'crontab {TEMP_CRON} ;',
f'rm {TEMP_CRON}'
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
SCHEDULED_TASK_NAME = 'monkey-spawn-cmd'
SCHEDULED_TASK_COMMAND = 'C:\windows\system32\cmd.exe'

# Commands from: https://github.com/redcanaryco/atomic-red-team/blob/master/atomics/T1053.005/T1053.005.md


def get_windows_commands_to_schedule_jobs():
return f'schtasks /Create /SC monthly /TN {SCHEDULED_TASK_NAME} /TR {SCHEDULED_TASK_COMMAND}'


def get_windows_commands_to_remove_scheduled_jobs():
return f'schtasks /Delete /TN {SCHEDULED_TASK_NAME} /F > nul 2>&1'
6 changes: 4 additions & 2 deletions monkey/monkey_island/cc/services/attack/attack_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
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, T1158, T1154, T1166
from monkey_island.cc.services.attack.technique_reports import T1136, T1156, T1504, T1158, T1154, T1166, T1168, T1053
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
Expand Down Expand Up @@ -42,7 +42,9 @@
'T1504': T1504.T1504,
'T1158': T1158.T1158,
'T1154': T1154.T1154,
'T1166': T1166.T1166
'T1166': T1166.T1166,
'T1168': T1168.T1168,
'T1053': T1053.T1053
}

REPORT_NAME = 'new_report'
Expand Down
20 changes: 20 additions & 0 deletions monkey/monkey_island/cc/services/attack/attack_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,16 @@
"and evade a typical user or system analysis that does not "
"incorporate investigation of hidden files."
},
"T1168": {
"title": "Local job scheduling",
"type": "bool",
"value": True,
"necessary": False,
"link": "https://attack.mitre.org/techniques/T1168/",
"description": "Linux supports multiple methods for creating pre-scheduled and "
"periodic background jobs. Job scheduling can be used by adversaries to "
"schedule running malicious code at some specified date and time."
},
"T1504": {
"title": "PowerShell profile",
"type": "bool",
Expand All @@ -119,6 +129,16 @@
"in certain situations by abusing PowerShell profiles which "
"are scripts that run when PowerShell starts."
},
"T1053": {
"title": "Scheduled task",
"type": "bool",
"value": True,
"necessary": False,
"link": "https://attack.mitre.org/techniques/T1053",
"description": "Windows utilities can be used to schedule programs or scripts to "
"be executed at a date and time. An adversary may use task scheduling to "
"execute programs at system startup or on a scheduled basis for persistence."
},
"T1166": {
"title": "Setuid and Setgid",
"type": "bool",
Expand Down
35 changes: 35 additions & 0 deletions monkey/monkey_island/cc/services/attack/technique_reports/T1053.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from monkey_island.cc.services.attack.technique_reports import AttackTechnique
from monkey_island.cc.database import mongo
from common.utils.attack_utils import ScanStatus
from common.data.post_breach_consts import POST_BREACH_JOB_SCHEDULING
Comment on lines +1 to +4
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally, all imports should follow the same structure:

future imports

python imports

third party imports

project imports

If not sure about why, look up PEP8.
You can automatically achieve this on pycharm with ctrl + alt + o.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.



__author__ = "shreyamalviya"


class T1053(AttackTechnique):
tech_id = "T1053"
unscanned_msg = "Monkey did not try scheduling a job on Windows."
scanned_msg = "Monkey tried scheduling a job on the Windows system but failed."
used_msg = "Monkey scheduled a job on the Windows system."

query = [{'$match': {'telem_category': 'post_breach',
'data.name': POST_BREACH_JOB_SCHEDULING,
'data.command': {'$regex': 'schtasks'}}},
{'$project': {'_id': 0,
'machine': {'hostname': '$data.hostname',
'ips': ['$data.ip']},
'result': '$data.result'}}]

@staticmethod
def get_report_data():
data = {'title': T1053.technique_title()}

job_scheduling_info = list(mongo.db.telemetry.aggregate(T1053.query))

status = (ScanStatus.USED.value if job_scheduling_info[0]['result'][1]
else ScanStatus.SCANNED.value) if job_scheduling_info else ScanStatus.UNSCANNED.value

data.update(T1053.get_base_data_by_status(status))
data.update({'info': job_scheduling_info})
return data
35 changes: 35 additions & 0 deletions monkey/monkey_island/cc/services/attack/technique_reports/T1168.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from monkey_island.cc.services.attack.technique_reports import AttackTechnique
from monkey_island.cc.database import mongo
from common.utils.attack_utils import ScanStatus
from common.data.post_breach_consts import POST_BREACH_JOB_SCHEDULING


__author__ = "shreyamalviya"


class T1168(AttackTechnique):
tech_id = "T1168"
unscanned_msg = "Monkey did not try scheduling a job on Linux."
scanned_msg = "Monkey tried scheduling a job on the Linux system but failed."
used_msg = "Monkey scheduled a job on the Linux system."

query = [{'$match': {'telem_category': 'post_breach',
'data.name': POST_BREACH_JOB_SCHEDULING,
'data.command': {'$regex': 'crontab'}}},
{'$project': {'_id': 0,
'machine': {'hostname': '$data.hostname',
'ips': ['$data.ip']},
'result': '$data.result'}}]

@staticmethod
def get_report_data():
data = {'title': T1168.technique_title()}

job_scheduling_info = list(mongo.db.telemetry.aggregate(T1168.query))

status = (ScanStatus.USED.value if job_scheduling_info[0]['result'][1]
else ScanStatus.SCANNED.value) if job_scheduling_info else ScanStatus.UNSCANNED.value

data.update(T1168.get_base_data_by_status(status))
data.update({'info': job_scheduling_info})
return data
11 changes: 10 additions & 1 deletion monkey/monkey_island/cc/services/config_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,14 @@
],
"title": "Setuid and Setgid",
"attack_techniques": ["T1166"]
},
{
"type": "string",
"enum": [
"ScheduleJobs"
],
"title": "Job scheduling",
"attack_techniques": ["T1168", "T1053"]
}
],
},
Expand Down Expand Up @@ -415,7 +423,8 @@
"ModifyShellStartupFiles",
"HiddenFiles",
"TrapCommand",
"ChangeSetuidSetgid"
"ChangeSetuidSetgid",
"ScheduleJobs"
],
"description": "List of actions the Monkey will run post breach"
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import React from 'react';
import ReactTable from 'react-table';
import {renderMachineFromSystemData, ScanStatus} from './Helpers';
import MitigationsComponent from './MitigationsComponent';

class T1053 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={T1053.getColumns()}
data={this.props.data.info}
showPagination={false}
defaultPageSize={this.props.data.info.length}
/> : ''}
<MitigationsComponent mitigations={this.props.data.mitigations}/>
</div>
);
}
}

export default T1053;
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import React from 'react';
import ReactTable from 'react-table';
import {renderMachineFromSystemData, ScanStatus} from './Helpers';
import MitigationsComponent from './MitigationsComponent';

class T1168 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={T1168.getColumns()}
data={this.props.data.info}
showPagination={false}
defaultPageSize={this.props.data.info.length}
/> : ''}
<MitigationsComponent mitigations={this.props.data.mitigations}/>
</div>
);
}
}

export default T1168;