diff --git a/monkey/infection_monkey/exploit/__init__.py b/monkey/infection_monkey/exploit/__init__.py index 804a5a2fc..f4cc4b290 100644 --- a/monkey/infection_monkey/exploit/__init__.py +++ b/monkey/infection_monkey/exploit/__init__.py @@ -76,8 +76,8 @@ class HostExploiter(object): Appends command to exploiter's info. :param cmd: String of executed command. e.g. 'echo Example' """ - command = {'cmd': cmd} - self._exploit_info['executed_cmds'].append(command) + powershell = True if "powershell" in cmd.lower() else False + self._exploit_info['executed_cmds'].append({'cmd': cmd, 'powershell': powershell}) from infection_monkey.exploit.win_ms08_067 import Ms08_067_Exploiter diff --git a/monkey/infection_monkey/exploit/mssqlexec.py b/monkey/infection_monkey/exploit/mssqlexec.py index e94be15eb..9d1dcb2d6 100644 --- a/monkey/infection_monkey/exploit/mssqlexec.py +++ b/monkey/infection_monkey/exploit/mssqlexec.py @@ -66,7 +66,7 @@ class MSSQLExploiter(HostExploiter): "xp_cmdshell \">%s\"" % (dst_path, tmp_file_path)] MSSQLExploiter.execute_command(cursor, commands) MSSQLExploiter.run_file(cursor, tmp_file_path) - + self.add_executed_cmd(' '.join(commands)) # Form monkey's command in a file monkey_args = tools.build_monkey_commandline(self.host, tools.get_monkey_depth() - 1, diff --git a/monkey/infection_monkey/exploit/web_rce.py b/monkey/infection_monkey/exploit/web_rce.py index 97358fe53..fe45c65ce 100644 --- a/monkey/infection_monkey/exploit/web_rce.py +++ b/monkey/infection_monkey/exploit/web_rce.py @@ -338,7 +338,7 @@ class WebRCE(HostExploiter): command = self.get_command(paths['dest_path'], http_path, commands) resp = self.exploit(url, command) - + self.add_executed_cmd(command) resp = self.run_backup_commands(resp, url, paths['dest_path'], http_path) http_thread.join(DOWNLOAD_TIMEOUT) diff --git a/monkey/monkey_island/cc/services/attack/attack_report.py b/monkey/monkey_island/cc/services/attack/attack_report.py index fac55a038..01990ff78 100644 --- a/monkey/monkey_island/cc/services/attack/attack_report.py +++ b/monkey/monkey_island/cc/services/attack/attack_report.py @@ -1,5 +1,5 @@ import logging -from monkey_island.cc.services.attack.technique_reports import T1210, T1197, T1110, T1075, T1003, T1059 +from monkey_island.cc.services.attack.technique_reports import T1210, T1197, T1110, T1075, T1003, T1059, T1086 from monkey_island.cc.services.attack.attack_config import AttackConfig from monkey_island.cc.database import mongo @@ -13,7 +13,8 @@ TECHNIQUES = {'T1210': T1210.T1210, 'T1110': T1110.T1110, 'T1075': T1075.T1075, 'T1003': T1003.T1003, - 'T1059': T1059.T1059} + 'T1059': T1059.T1059, + 'T1086': T1086.T1086} 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 a79b57a87..24c8cf1c6 100644 --- a/monkey/monkey_island/cc/services/attack/attack_schema.py +++ b/monkey/monkey_island/cc/services/attack/attack_schema.py @@ -95,6 +95,14 @@ SCHEMA = { "necessary": True, "description": "Adversaries may use command-line interfaces to interact with systems " "and execute other software during the course of an operation.", + }, + "T1086": { + "title": "T1086 Powershell", + "type": "bool", + "value": True, + "necessary": True, + "description": "Adversaries can use PowerShell to perform a number of actions," + " including discovery of information and execution of code.", } } }, diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1003.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1003.py index cd1a538cb..a92758cbc 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1003.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1003.py @@ -13,8 +13,8 @@ class T1003(AttackTechnique): used_msg = "Monkey successfully obtained some credentials from systems on the network." query = {'telem_category': 'system_info_collection', '$and': [{'data.credentials': {'$exists': True}}, - # $gt: {} checks if field is not an empty object - {'data.credentials': {'$gt': {}}}]} + # $gt: {} checks if field is not an empty object + {'data.credentials': {'$gt': {}}}]} @staticmethod def get_report_data(): diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py index 488a8f547..328c11112 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py @@ -14,10 +14,13 @@ class T1059(AttackTechnique): query = [{'$match': {'telem_category': 'exploit', 'data.info.executed_cmds': {'$exists': True, '$ne': []}}}, + {'$unwind': '$data.info.executed_cmds'}, + {'$sort': {'data.info.executed_cmds.powershell': 1}}, {'$project': {'_id': 0, 'machine': '$data.machine', 'info': '$data.info'}}, - {'$group': {'_id': '$machine', 'data': {'$push': '$$ROOT'}}}] + {'$group': {'_id': '$machine', 'data': {'$push': '$$ROOT'}}}, + {'$project': {'_id': 0, 'data': {'$arrayElemAt': ['$data', 0]}}}] @staticmethod def get_report_data(): diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1086.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1086.py new file mode 100644 index 000000000..4114047c5 --- /dev/null +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1086.py @@ -0,0 +1,36 @@ +from monkey_island.cc.services.attack.technique_reports import AttackTechnique +from common.utils.attack_utils import ScanStatus +from monkey_island.cc.database import mongo + +__author__ = "VakarisZ" + + +class T1086(AttackTechnique): + + tech_id = "T1086" + unscanned_msg = "Monkey didn't run powershell." + scanned_msg = "" + used_msg = "Monkey successfully ran powershell commands on exploited machines in the network." + + query = [{'$match': {'telem_category': 'exploit', + 'data.info.executed_cmds': {'$elemMatch': {'powershell': True}}}}, + {'$project': {'machine': '$data.machine', + 'info': '$data.info'}}, + {'$project': {'_id': 0, + 'machine': 1, + 'info.finished': 1, + 'info.executed_cmds': {'$filter': {'input': '$info.executed_cmds', + 'as': 'command', + 'cond': {'$eq': ['$$command.powershell', True]}}}}}, + {'$group': {'_id': '$machine', 'data': {'$push': '$$ROOT'}}}] + + @staticmethod + def get_report_data(): + cmd_data = list(mongo.db.telemetry.aggregate(T1086.query)) + data = {'title': T1086.technique_title(), 'cmds': cmd_data} + if cmd_data: + status = ScanStatus.USED + else: + status = ScanStatus.UNSCANNED + data.update(T1086.get_message_and_status(status)) + return data diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js index 5cc48a4c9..57d5bcb2c 100644 --- a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js +++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js @@ -14,9 +14,9 @@ class T1059 extends React.Component { return ([{ Header: 'Example commands used', columns: [ - {Header: 'Machine', id: 'machine', accessor: x => renderMachine(x.data[0].machine), style: { 'whiteSpace': 'unset'}, width: 160 }, - {Header: 'Approx. Time', id: 'time', accessor: x => x.data[0].info.finished, style: { 'whiteSpace': 'unset' }}, - {Header: 'Command', id: 'command', accessor: x => x.data[0].info.executed_cmds[0].cmd, style: { 'whiteSpace': 'unset' }}, + {Header: 'Machine', id: 'machine', accessor: x => renderMachine(x.data.machine), style: { 'whiteSpace': 'unset'}, width: 160 }, + {Header: 'Approx. Time', id: 'time', accessor: x => x.data.info.finished, style: { 'whiteSpace': 'unset' }}, + {Header: 'Command', id: 'command', accessor: x => x.data.info.executed_cmds.cmd, style: { 'whiteSpace': 'unset' }}, ] }])}; diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1086.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1086.js new file mode 100644 index 000000000..d6d22c093 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1086.js @@ -0,0 +1,40 @@ +import React from 'react'; +import '../../../styles/Collapse.scss' +import ReactTable from "react-table"; +import { renderMachine } from "./Helpers" + + +class T1086 extends React.Component { + + constructor(props) { + super(props); + } + + static getPowershellColumns() { + return ([{ + Header: 'Example Powershell commands used', + columns: [ + {Header: 'Machine', id: 'machine', accessor: x => renderMachine(x.data[0].machine), style: { 'whiteSpace': 'unset'}, width: 160 }, + {Header: 'Approx. Time', id: 'time', accessor: x => x.data[0].info.finished, style: { 'whiteSpace': 'unset' }}, + {Header: 'Command', id: 'command', accessor: x => x.data[0].info.executed_cmds[0].cmd, style: { 'whiteSpace': 'unset' }}, + ] + }])}; + + render() { + return ( +
+
{this.props.data.message}
+
+ {this.props.data.status === 'USED' ? + : ""} +
+ ); + } +} + +export default T1086; diff --git a/monkey/monkey_island/cc/ui/src/components/report-components/AttackReport.js b/monkey/monkey_island/cc/ui/src/components/report-components/AttackReport.js index 20250873a..87f6f0a38 100644 --- a/monkey/monkey_island/cc/ui/src/components/report-components/AttackReport.js +++ b/monkey/monkey_island/cc/ui/src/components/report-components/AttackReport.js @@ -2,7 +2,7 @@ import React from 'react'; import {Col} from 'react-bootstrap'; import {ReactiveGraph} from 'components/reactive-graph/ReactiveGraph'; import {edgeGroupToColor, options} from 'components/map/MapOptions'; -import '../../styles/Collapse.scss' +import '../../styles/Collapse.scss'; import AuthComponent from '../AuthComponent'; import Collapse from '@kunukn/react-collapse'; import T1210 from '../attack/techniques/T1210'; @@ -11,6 +11,7 @@ import T1110 from '../attack/techniques/T1110'; import T1075 from "../attack/techniques/T1075"; import T1003 from "../attack/techniques/T1003"; import T1059 from "../attack/techniques/T1059"; +import T1086 from "../attack/techniques/T1086"; const tech_components = { 'T1210': T1210, @@ -18,7 +19,8 @@ const tech_components = { 'T1110': T1110, 'T1075': T1075, 'T1003': T1003, - 'T1059': T1059 + 'T1059': T1059, + 'T1086': T1086 }; const classNames = require('classnames');