Merge branch 'brute_force_report' into attack_pass_the_hash

This commit is contained in:
VakarisZ 2019-06-05 13:37:00 +03:00
commit 7c67ee430d
14 changed files with 149 additions and 20 deletions

View File

@ -1,6 +1,7 @@
from abc import ABCMeta, abstractmethod, abstractproperty from abc import ABCMeta, abstractmethod, abstractproperty
import infection_monkey.config import infection_monkey.config
from common.utils.exploit_enum import ExploitType from common.utils.exploit_enum import ExploitType
from datetime import datetime
__author__ = 'itamar' __author__ = 'itamar'
@ -20,11 +21,20 @@ class HostExploiter(object):
def __init__(self, host): def __init__(self, host):
self._config = infection_monkey.config.WormConfiguration self._config = infection_monkey.config.WormConfiguration
self._exploit_info = {'display_name': self._EXPLOITED_SERVICE, self._exploit_info = {'display_name': self._EXPLOITED_SERVICE,
'exploit_type': self.EXPLOIT_TYPE.name,
'started': '',
'finished': '',
'vulnerable_urls': [], 'vulnerable_urls': [],
'vulnerable_ports': []} 'vulnerable_ports': []}
self._exploit_attempts = [] self._exploit_attempts = []
self.host = host self.host = host
def set_start_time(self):
self._exploit_info['started'] = datetime.now().isoformat()
def set_finish_time(self):
self._exploit_info['finished'] = datetime.now().isoformat()
def is_os_supported(self): def is_os_supported(self):
return self.host.os.get('type') in self._TARGET_OS_TYPE return self.host.os.get('type') in self._TARGET_OS_TYPE

View File

@ -124,10 +124,12 @@ class MSSQLExploiter(HostExploiter):
conn = pymssql.connect(host, user, password, port=port, login_timeout=self.LOGIN_TIMEOUT) conn = pymssql.connect(host, user, password, port=port, login_timeout=self.LOGIN_TIMEOUT)
LOG.info('Successfully connected to host: {0}, ' LOG.info('Successfully connected to host: {0}, '
'using user: {1}, password: {2}'.format(host, user, password)) 'using user: {1}, password: {2}'.format(host, user, password))
self.add_vuln_port(MSSQLExploiter.SQL_DEFAULT_TCP_PORT)
self.report_login_attempt(True, user, password) self.report_login_attempt(True, user, password)
cursor = conn.cursor() cursor = conn.cursor()
return cursor return cursor
except pymssql.OperationalError: except pymssql.OperationalError:
self.report_login_attempt(False, user, password)
# Combo didn't work, hopping to the next one # Combo didn't work, hopping to the next one
pass pass

View File

@ -283,7 +283,9 @@ class InfectionMonkey(object):
result = False result = False
try: try:
exploiter.set_start_time()
result = exploiter.exploit_host() result = exploiter.exploit_host()
exploiter.set_finish_time()
if result: if result:
self.successfully_exploited(machine, exploiter) self.successfully_exploited(machine, exploiter)
return True return True

View File

@ -16,4 +16,6 @@ WINDOWS_COMMANDS = ['net', 'user', WormConfiguration.user_to_add,
class BackdoorUser(PBA): class BackdoorUser(PBA):
def __init__(self): def __init__(self):
super(BackdoorUser, self).__init__("Backdoor user", linux_cmd=LINUX_COMMANDS, windows_cmd=WINDOWS_COMMANDS) super(BackdoorUser, self).__init__("Backdoor user",
linux_cmd=' '.join(LINUX_COMMANDS),
windows_cmd=WINDOWS_COMMANDS)

View File

@ -2,7 +2,6 @@ import os
import sys import sys
import shutil import shutil
import struct import struct
import datetime
from infection_monkey.config import WormConfiguration from infection_monkey.config import WormConfiguration

View File

@ -119,6 +119,8 @@ class Telemetry(flask_restful.Resource):
def process_exploit_telemetry(telemetry_json): def process_exploit_telemetry(telemetry_json):
edge = Telemetry.get_edge_by_scan_or_exploit_telemetry(telemetry_json) edge = Telemetry.get_edge_by_scan_or_exploit_telemetry(telemetry_json)
Telemetry.encrypt_exploit_creds(telemetry_json) Telemetry.encrypt_exploit_creds(telemetry_json)
telemetry_json['data']['info']['started'] = dateutil.parser.parse(telemetry_json['data']['info']['started'])
telemetry_json['data']['info']['finished'] = dateutil.parser.parse(telemetry_json['data']['info']['finished'])
new_exploit = copy.deepcopy(telemetry_json['data']) new_exploit = copy.deepcopy(telemetry_json['data'])

View File

@ -1,5 +1,5 @@
import logging import logging
from monkey_island.cc.services.attack.technique_reports import T1210, T1197 from monkey_island.cc.services.attack.technique_reports import T1210, T1197, T1110
from monkey_island.cc.services.attack.attack_telem import AttackTelemService from monkey_island.cc.services.attack.attack_telem import AttackTelemService
from monkey_island.cc.services.attack.attack_config import AttackConfig from monkey_island.cc.services.attack.attack_config import AttackConfig
from monkey_island.cc.database import mongo from monkey_island.cc.database import mongo
@ -10,7 +10,8 @@ __author__ = "VakarisZ"
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
TECHNIQUES = {'T1210': T1210.T1210, TECHNIQUES = {'T1210': T1210.T1210,
'T1197': T1197.T1197} 'T1197': T1197.T1197,
'T1110': T1110.T1110}
REPORT_NAME = 'new_report' REPORT_NAME = 'new_report'

View File

@ -0,0 +1,70 @@
from monkey_island.cc.database import mongo
from monkey_island.cc.services.attack.technique_reports import AttackTechnique
from common.utils.attack_utils import ScanStatus
from common.utils.exploit_enum import ExploitType
from monkey_island.cc.encryptor import encryptor
__author__ = "VakarisZ"
class T1110(AttackTechnique):
tech_id = "T1110"
unscanned_msg = "Monkey didn't try to brute force any services."
scanned_msg = "Monkey tried to brute force some services, but failed."
used_msg = "Monkey successfully used brute force in the network."
@staticmethod
def get_report_data():
data = {'title': T1110.technique_title(T1110.tech_id)}
results = mongo.db.telemetry.find({'telem_type': 'exploit',
'data.info.exploit_type': ExploitType.BRUTE_FORCE.name,
'data.attempts': {'$ne': '[]'}},
{'data.machine': 1, 'data.info': 1, 'data.attempts': 1})
parsed_results = []
succeeded = False
attempted = False
for result in results:
parsed_result, attempt_status = T1110.parse_exploiter_result(result)
parsed_results.append(parsed_result)
if parsed_result['successful_creds']:
succeeded = True
elif attempt_status:
attempted = True
if succeeded:
data.update({'message': T1110.used_msg, 'status': ScanStatus.USED.name})
elif attempted:
data.update({'message': T1110.scanned_msg, 'status': ScanStatus.SCANNED.name})
else:
data.update({'message': T1110.unscanned_msg, 'status': ScanStatus.UNSCANNED.name})
data.update({'services': parsed_results})
return data
@staticmethod
def parse_exploiter_result(result):
attempted = False
successful_creds = []
for attempt in result['data']['attempts']:
attempted = True
if attempt['result']:
successful_creds.append(T1110.parse_creds(attempt))
result['data']['successful_creds'] = successful_creds
return result['data'], attempted
@staticmethod
def parse_creds(attempt):
username = attempt['user']
if attempt['lm_hash']:
return '%s ; LM hash %s ...' % (username, encryptor.dec(attempt['lm_hash'])[0:5])
if attempt['lm_hash']:
return '%s ; NTLM hash %s ...' % (username, encryptor.dec(attempt['ntlm_hash'])[0:20])
if attempt['ssh_key']:
return '%s ; SSH key %s ...' % (username, encryptor.dec(attempt['ssh_key'])[0:15])
if attempt['password']:
return '%s : %s' % (username, T1110.obfuscate_password(encryptor.dec(attempt['password'])))
@staticmethod
def obfuscate_password(password, plain_chars=3):
return password[0:plain_chars] + '*' * (len(password) - plain_chars)

View File

@ -4,13 +4,6 @@ from monkey_island.cc.database import mongo
__author__ = "VakarisZ" __author__ = "VakarisZ"
TECHNIQUE = "T1210"
MESSAGES = {
'unscanned': "Monkey didn't scan any remote services. Maybe it didn't find any machines on the network?",
'scanned': "Monkey scanned for remote services on the network, but couldn't exploit any of them.",
'used': "Monkey scanned for remote services and exploited some on the network."
}
class T1210(AttackTechnique): class T1210(AttackTechnique):
@ -21,7 +14,7 @@ class T1210(AttackTechnique):
@staticmethod @staticmethod
def get_report_data(): def get_report_data():
data = {'title': T1210.technique_title(TECHNIQUE)} data = {'title': T1210.technique_title(T1210.tech_id)}
scanned_services = T1210.get_scanned_services() scanned_services = T1210.get_scanned_services()
exploited_services = T1210.get_exploited_services() exploited_services = T1210.get_exploited_services()
if exploited_services: if exploited_services:

View File

@ -57,8 +57,8 @@ class ReportService:
STRUTS2 = 8 STRUTS2 = 8
WEBLOGIC = 9 WEBLOGIC = 9
HADOOP = 10 HADOOP = 10
PTH_CRIT_SERVICES_ACCESS = 11, PTH_CRIT_SERVICES_ACCESS = 11
MSSQL = 12, MSSQL = 12
VSFTPD = 13 VSFTPD = 13
class WARNINGS_DICT(Enum): class WARNINGS_DICT(Enum):
@ -296,7 +296,7 @@ class ReportService:
def process_vsftpd_exploit(exploit): def process_vsftpd_exploit(exploit):
processed_exploit = ReportService.process_general_creds_exploit(exploit) processed_exploit = ReportService.process_general_creds_exploit(exploit)
processed_exploit['type'] = 'vsftp' processed_exploit['type'] = 'vsftp'
return processed_exploit return processed_exploit
@staticmethod @staticmethod
def process_sambacry_exploit(exploit): def process_sambacry_exploit(exploit):

View File

@ -0,0 +1,47 @@
import React from 'react';
import '../../../styles/Collapse.scss'
import ReactTable from "react-table";
class T1110 extends React.Component {
constructor(props) {
super(props);
}
static getServiceColumns() {
return ([{
columns: [
{Header: 'Machine', id: 'machine', accessor: x => this.renderMachine(x.machine),
style: { 'whiteSpace': 'unset' }, width: 160},
{Header: 'Service', id: 'service', accessor: x => x.info.display_name, style: { 'whiteSpace': 'unset' }, width: 100},
{Header: 'Started', id: 'started', accessor: x => x.info.started, style: { 'whiteSpace': 'unset' }},
{Header: 'Finished', id: 'finished', accessor: x => x.info.finished, style: { 'whiteSpace': 'unset' }},
{Header: 'Attempts', id: 'attempts', accessor: x => x.attempts.length, style: { 'whiteSpace': 'unset' }, width: 160},
{Header: 'Successful credentials', id: 'credentials', accessor: x => x.successful_creds, style: { 'whiteSpace': 'unset' }},
]
}])};
static renderMachine(val){
return (
<span>{val.ip_addr} {(val.domain_name ? " (".concat(val.domain_name, ")") : "")}</span>
)
};
render() {
return (
<div>
<div>{this.props.data.message}</div>
<br/>
<ReactTable
columns={T1110.getServiceColumns()}
data={this.props.data.services}
showPagination={false}
defaultPageSize={this.props.data.services.length}
/>
</div>
);
}
}
export default T1110;

View File

@ -299,9 +299,8 @@ class ConfigurePageComponent extends AuthComponent {
try { try {
this.setState({ this.setState({
configuration: JSON.parse(event.target.result), configuration: JSON.parse(event.target.result),
selectedSection: 'basic',
lastAction: 'import_success' lastAction: 'import_success'
}, () => {this.sendConfig()}); }, () => {this.sendConfig(); this.setInitialConfig(JSON.parse(event.target.result))});
this.currentSection = 'basic'; this.currentSection = 'basic';
this.currentFormData = {}; this.currentFormData = {};
} catch(SyntaxError) { } catch(SyntaxError) {

View File

@ -81,7 +81,7 @@ class ReportPageComponent extends AuthComponent {
} }
return ( return (
<Col xs={12} lg={8}> <Col xs={12} lg={10}>
<h1 className="page-title no-print">4. Security Report</h1> <h1 className="page-title no-print">4. Security Report</h1>
<div style={{'fontSize': '1.2em'}}> <div style={{'fontSize': '1.2em'}}>
{content} {content}
@ -308,7 +308,7 @@ class ReportPageComponent extends AuthComponent {
}).length} threats</span>: }).length} threats</span>:
<ul> <ul>
{this.state.report.overview.issues[this.Issue.STOLEN_SSH_KEYS] ? {this.state.report.overview.issues[this.Issue.STOLEN_SSH_KEYS] ?
<li>Stolen SSH keys are used to exploit other machines.</li> : null } <li>Stolen SSH keys are used to exploit other machines.</li> : null }
{this.state.report.overview.issues[this.Issue.STOLEN_CREDS] ? {this.state.report.overview.issues[this.Issue.STOLEN_CREDS] ?
<li>Stolen credentials are used to exploit other machines.</li> : null} <li>Stolen credentials are used to exploit other machines.</li> : null}
{this.state.report.overview.issues[this.Issue.ELASTIC] ? {this.state.report.overview.issues[this.Issue.ELASTIC] ?

View File

@ -6,11 +6,13 @@ import AuthComponent from '../AuthComponent';
import Collapse from '@kunukn/react-collapse'; import Collapse from '@kunukn/react-collapse';
import T1210 from '../attack/techniques/T1210'; import T1210 from '../attack/techniques/T1210';
import T1197 from '../attack/techniques/T1197'; import T1197 from '../attack/techniques/T1197';
import T1110 from '../attack/techniques/T1110';
import '../../styles/Collapse.scss' import '../../styles/Collapse.scss'
const tech_components = { const tech_components = {
'T1210': T1210, 'T1210': T1210,
'T1197': T1197 'T1197': T1197,
'T1110': T1110
}; };
const classNames = require('classnames'); const classNames = require('classnames');