Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

T1086 powershell #344

Merged
merged 44 commits into from
Jul 7, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
7c67ee4
Merge branch 'brute_force_report' into attack_pass_the_hash
VakarisZ Jun 5, 2019
ed23fd3
Merge branch 'brute_force_report' into attack_pass_the_hash
VakarisZ Jun 6, 2019
c4d5aed
PTH implementation finished, helper methods added
VakarisZ Jun 6, 2019
75d52a7
Merge branch 'brute_force_report' into attack_pass_the_hash
VakarisZ Jun 7, 2019
350c7d9
T1003 credential dumping implemented
VakarisZ Jun 7, 2019
af63e93
Table not shown if no hashes were used.
VakarisZ Jun 7, 2019
7e059cb
Merge branch 'attack_pass_the_hash' into attack_credential_dumping
VakarisZ Jun 7, 2019
c99ceff
Table not shown if no passwords were stolen
VakarisZ Jun 7, 2019
9b08e60
CLI implementation started
VakarisZ Jun 10, 2019
908c531
command line implementation finished
VakarisZ Jun 10, 2019
6636cd2
Changed cmds from array to dict
VakarisZ Jun 10, 2019
6ca33ff
Added header to used commands table.
VakarisZ Jun 10, 2019
dbf469f
Powershell started
VakarisZ Jun 10, 2019
9cc526c
web_rce bugfix
VakarisZ Jun 10, 2019
5fe468f
Merge branch 'attack_comand_line_interface' into attack_powershell
VakarisZ Jun 10, 2019
71edd48
Powershell implementation started
VakarisZ Jun 10, 2019
911c2e8
technique added to report UI
VakarisZ Jun 11, 2019
881911e
Merge remote-tracking branch 'upstream/develop' into attack_pass_the_…
VakarisZ Jun 12, 2019
676eca6
Merge remote-tracking branch 'upstream/develop' into attack_pass_the_…
VakarisZ Jun 18, 2019
8505ad0
Refactored AttackTechnique methods to use @classmethod and minor impr…
VakarisZ Jun 18, 2019
9367e64
Merge remote-tracking branch 'upstream/develop' into attack_pass_the_…
VakarisZ Jun 18, 2019
a70b77b
Merge remote-tracking branch 'upstream/develop' into attack_comand_li…
VakarisZ Jun 19, 2019
ab4bbd4
Readability improvements
VakarisZ Jun 19, 2019
b1f1315
Merge branch 'attack_pass_the_hash' into attack_comand_line_interface
VakarisZ Jun 19, 2019
b3c6baf
Readability improvements
VakarisZ Jun 19, 2019
9935f15
Merge branch 'attack_pass_the_hash' into attack_comand_line_interface
VakarisZ Jun 19, 2019
7c01aab
CR improvements
VakarisZ Jun 19, 2019
7c41d1e
Merge branch 'attack_comand_line_interface' into attack_powershell
VakarisZ Jun 19, 2019
e38410a
CR improvements
VakarisZ Jun 19, 2019
17d08c7
Merge branch 'attack_comand_line_interface' into attack_powershell
VakarisZ Jun 19, 2019
c4c53f7
powershell command storage refactor
VakarisZ Jun 25, 2019
8ec5a6a
Readability improvements
VakarisZ Jun 19, 2019
f9bf3ef
Executed cmds info variable refactored
VakarisZ Jun 25, 2019
b7d1737
Merge branch 'attack_pass_the_hash' into attack_comand_line_interface
VakarisZ Jun 25, 2019
b667cb7
Merge remote-tracking branch 'upstream/develop' into attack_comand_li…
VakarisZ Jun 25, 2019
3cab7ba
Merge remote-tracking branch 'upstream/develop' into attack_pass_the_…
VakarisZ Jun 25, 2019
f8d5247
Merge branch 'attack_pass_the_hash' into attack_comand_line_interface
VakarisZ Jun 25, 2019
36f917b
Updated branch according to changes in dev.
VakarisZ Jun 25, 2019
fea8567
Merge branch 'attack_comand_line_interface' into attack_powershell
VakarisZ Jun 25, 2019
3e9dcd3
Powershell query changed to parse array of executed command dicts
VakarisZ Jun 26, 2019
737c735
Updated attack report in pass the hash
VakarisZ Jun 26, 2019
6ae23cd
Merge branch 'attack_pass_the_hash' into attack_comand_line_interface
VakarisZ Jun 26, 2019
bc73c64
Merge branch 'attack_comand_line_interface' into attack_powershell
VakarisZ Jun 26, 2019
e4bb468
Updated attack report in powershell
VakarisZ Jun 26, 2019
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
11 changes: 10 additions & 1 deletion monkey/infection_monkey/exploit/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ def __init__(self, host):
'started': '',
'finished': '',
'vulnerable_urls': [],
'vulnerable_ports': []}
'vulnerable_ports': [],
'executed_cmds': []}
self._exploit_attempts = []
self.host = host

Expand Down Expand Up @@ -70,6 +71,14 @@ def add_vuln_url(self, url):
def add_vuln_port(self, port):
self._exploit_info['vulnerable_ports'].append(port)

def add_executed_cmd(self, cmd):
"""
Appends command to exploiter's info.
:param cmd: String of executed command. e.g. 'echo Example'
"""
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
from infection_monkey.exploit.wmiexec import WmiExploiter
Expand Down
1 change: 1 addition & 0 deletions monkey/infection_monkey/exploit/hadoop.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ def _exploit_host(self):
return False
http_thread.join(self.DOWNLOAD_TIMEOUT)
http_thread.stop()
self.add_executed_cmd(command)
return True

def exploit(self, url, command):
Expand Down
4 changes: 2 additions & 2 deletions monkey/infection_monkey/exploit/mssqlexec.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def _exploit_host(self):
"xp_cmdshell \"<nul set /p=, ^\'%s^\') >>%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,
Expand All @@ -77,7 +77,7 @@ def _exploit_host(self):
commands.extend(monkey_args)
MSSQLExploiter.execute_command(cursor, commands)
MSSQLExploiter.run_file(cursor, tmp_file_path)

self.add_executed_cmd(commands[-1])
return True

@staticmethod
Expand Down
2 changes: 1 addition & 1 deletion monkey/infection_monkey/exploit/rdpgrinder.py
Original file line number Diff line number Diff line change
Expand Up @@ -343,5 +343,5 @@ def _exploit_host(self):

LOG.info("Executed monkey '%s' on remote victim %r",
os.path.basename(src_path), self.host)

self.add_executed_cmd(command)
return True
1 change: 1 addition & 0 deletions monkey/infection_monkey/exploit/shellshock.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ def _exploit_host(self):
if not (self.check_remote_file_exists(url, header, exploit, self._config.monkey_log_path_linux)):
LOG.info("Log file does not exist, monkey might not have run")
continue
self.add_executed_cmd(cmdline)
return True

return False
Expand Down
1 change: 1 addition & 0 deletions monkey/infection_monkey/exploit/sshexec.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ def _exploit_host(self):
self._config.dropper_target_path_linux, self.host, cmdline)

ssh.close()
self.add_executed_cmd(cmdline)
return True

except Exception as exc:
Expand Down
1 change: 1 addition & 0 deletions monkey/infection_monkey/exploit/vsftpd.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ def _exploit_host(self):
if backdoor_socket.send(run_monkey):
LOG.info("Executed monkey '%s' on remote victim %r (cmdline=%r)", self._config.dropper_target_path_linux,
self.host, run_monkey)
self.add_executed_cmd(run_monkey)
return True
else:
return False
5 changes: 4 additions & 1 deletion monkey/infection_monkey/exploit/web_rce.py
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ def upload_monkey(self, url, commands=None):
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)
Expand Down Expand Up @@ -408,6 +408,7 @@ def execute_remote_monkey(self, url, path, dropper=False):
# If exploiter returns True / False
if type(resp) is bool:
LOG.info("Execution attempt successfully finished")
self.add_executed_cmd(command)
return resp
# If exploiter returns command output, we can check for execution errors
if 'is not recognized' in resp or 'command not found' in resp:
Expand All @@ -420,6 +421,8 @@ def execute_remote_monkey(self, url, path, dropper=False):
LOG.error("Something went wrong when trying to execute remote monkey: %s" % e)
return False
LOG.info("Execution attempt finished")

self.add_executed_cmd(command)
return resp

def get_monkey_upload_path(self, url_to_monkey):
Expand Down
2 changes: 1 addition & 1 deletion monkey/infection_monkey/exploit/wmiexec.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ def _exploit_host(self):

result.RemRelease()
wmi_connection.close()

self.add_executed_cmd(cmdline)
return success

return False
8 changes: 6 additions & 2 deletions monkey/monkey_island/cc/services/attack/attack_report.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import logging
from monkey_island.cc.services.attack.technique_reports import T1210, T1197, T1110
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

Expand All @@ -10,7 +10,11 @@

TECHNIQUES = {'T1210': T1210.T1210,
'T1197': T1197.T1197,
'T1110': T1110.T1110}
'T1110': T1110.T1110,
'T1075': T1075.T1075,
'T1003': T1003.T1003,
'T1059': T1059.T1059,
'T1086': T1086.T1086}

REPORT_NAME = 'new_report'

Expand Down
22 changes: 22 additions & 0 deletions monkey/monkey_island/cc/services/attack/attack_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,5 +84,27 @@
}
}
},
"execution": {
"title": "Execution",
"type": "object",
"properties": {
"T1059": {
"title": "T1059 Command line interface",
"type": "bool",
"value": True,
"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.",
}
}
},
}
}
27 changes: 27 additions & 0 deletions monkey/monkey_island/cc/services/attack/technique_reports/T1003.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
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 T1003(AttackTechnique):

tech_id = "T1003"
unscanned_msg = "Monkey tried to obtain credentials from systems in the network but didn't find any or failed."
scanned_msg = ""
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': {}}}]}

@staticmethod
def get_report_data():
data = {'title': T1003.technique_title()}
if mongo.db.telemetry.count_documents(T1003.query):
status = ScanStatus.USED
else:
status = ScanStatus.UNSCANNED
data.update(T1003.get_message_and_status(status))
return data
34 changes: 34 additions & 0 deletions monkey/monkey_island/cc/services/attack/technique_reports/T1059.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
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 T1059(AttackTechnique):

tech_id = "T1059"
unscanned_msg = "Monkey didn't exploit any machines to run commands at."
scanned_msg = ""
used_msg = "Monkey successfully ran commands on exploited machines in the network."

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'}}},
{'$project': {'_id': 0, 'data': {'$arrayElemAt': ['$data', 0]}}}]

@staticmethod
def get_report_data():
cmd_data = list(mongo.db.telemetry.aggregate(T1059.query))
data = {'title': T1059.technique_title(), 'cmds': cmd_data}
if cmd_data:
status = ScanStatus.USED
else:
status = ScanStatus.UNSCANNED
data.update(T1059.get_message_and_status(status))
return data
44 changes: 44 additions & 0 deletions monkey/monkey_island/cc/services/attack/technique_reports/T1075.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
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 T1075(AttackTechnique):

tech_id = "T1075"
unscanned_msg = "Monkey didn't try to use pass the hash attack."
scanned_msg = "Monkey tried to use hashes while logging in but didn't succeed."
used_msg = "Monkey successfully used hashed credentials."

login_attempt_query = {'data.attempts': {'$elemMatch': {'$or': [{'ntlm_hash': {'$ne': ''}},
{'lm_hash': {'$ne': ''}}]}}}

# Gets data about successful PTH logins
query = [{'$match': {'telem_category': 'exploit',
'data.attempts': {'$not': {'$size': 0},
'$elemMatch': {'$and': [{'$or': [{'ntlm_hash': {'$ne': ''}},
{'lm_hash': {'$ne': ''}}]},
{'result': True}]}}}},
{'$project': {'_id': 0,
'machine': '$data.machine',
'info': '$data.info',
'attempt_cnt': {'$size': '$data.attempts'},
'attempts': {'$filter': {'input': '$data.attempts',
'as': 'attempt',
'cond': {'$eq': ['$$attempt.result', True]}}}}}]

@staticmethod
def get_report_data():
data = {'title': T1075.technique_title()}
successful_logins = list(mongo.db.telemetry.aggregate(T1075.query))
data.update({'successful_logins': successful_logins})
if successful_logins:
status = ScanStatus.USED
elif mongo.db.telemetry.count_documents(T1075.login_attempt_query):
status = ScanStatus.SCANNED
else:
status = ScanStatus.UNSCANNED
data.update(T1075.get_message_and_status(status))
return data
36 changes: 36 additions & 0 deletions monkey/monkey_island/cc/services/attack/technique_reports/T1086.py
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class T1110(AttackTechnique):
used_msg = "Monkey successfully used brute force in the network."

# Gets data about brute force attempts
query = [{'$match': {'telem_type': 'exploit',
query = [{'$match': {'telem_category': 'exploit',
'data.attempts': {'$not': {'$size': 0}}}},
{'$project': {'_id': 0,
'machine': '$data.machine',
Expand All @@ -35,16 +35,16 @@ def get_report_data():
result['successful_creds'].append(T1110.parse_creds(attempt))

if succeeded:
data = T1110.get_message_and_status(T1110, ScanStatus.USED)
status = ScanStatus.USED
elif attempts:
data = T1110.get_message_and_status(T1110, ScanStatus.SCANNED)
status = ScanStatus.SCANNED
else:
data = T1110.get_message_and_status(T1110, ScanStatus.UNSCANNED)

status = ScanStatus.UNSCANNED
data = T1110.get_message_and_status(status)
# Remove data with no successful brute force attempts
attempts = [attempt for attempt in attempts if attempt['attempts']]

data.update({'services': attempts, 'title': T1110.technique_title(T1110.tech_id)})
data.update({'services': attempts, 'title': T1110.technique_title()})
return data

@staticmethod
Expand Down
18 changes: 10 additions & 8 deletions monkey/monkey_island/cc/services/attack/technique_reports/T1197.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,16 @@ class T1197(AttackTechnique):

@staticmethod
def get_report_data():
data = T1197.get_tech_base_data(T1197)
bits_results = mongo.db.telemetry.aggregate([{'$match': {'telem_category': 'attack', 'data.technique': T1197.tech_id}},
{'$group': {'_id': {'ip_addr': '$data.machine.ip_addr', 'usage': '$data.usage'},
'ip_addr': {'$first': '$data.machine.ip_addr'},
'domain_name': {'$first': '$data.machine.domain_name'},
'usage': {'$first': '$data.usage'},
'time': {'$first': '$timestamp'}}
}])
data = T1197.get_tech_base_data()
bits_results = mongo.db.telemetry.aggregate([{'$match': {'telem_category': 'attack',
'data.technique': T1197.tech_id}},
{'$group': {'_id': {'ip_addr': '$data.machine.ip_addr',
'usage': '$data.usage'},
'ip_addr': {'$first': '$data.machine.ip_addr'},
'domain_name': {'$first': '$data.machine.domain_name'},
'usage': {'$first': '$data.usage'},
'time': {'$first': '$timestamp'}}
}])
bits_results = list(bits_results)
data.update({'bits_jobs': bits_results})
return data
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,16 @@ class T1210(AttackTechnique):

@staticmethod
def get_report_data():
data = {'title': T1210.technique_title(T1210.tech_id)}
data = {'title': T1210.technique_title()}
scanned_services = T1210.get_scanned_services()
exploited_services = T1210.get_exploited_services()
if exploited_services:
data.update({'status': ScanStatus.USED.name, 'message': T1210.used_msg})
status = ScanStatus.USED
elif scanned_services:
data.update({'status': ScanStatus.SCANNED.name, 'message': T1210.scanned_msg})
status = ScanStatus.SCANNED
else:
data.update({'status': ScanStatus.UNSCANNED.name, 'message': T1210.unscanned_msg})
status = ScanStatus.UNSCANNED
data.update(T1210.get_message_and_status(status))
data.update({'scanned_services': scanned_services, 'exploited_services': exploited_services})
return data

Expand Down
Loading