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

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 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
from monkey_island.cc.services.attack.attack_config import AttackConfig
from monkey_island.cc.database import mongo

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

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

REPORT_NAME = 'new_report'

Expand Down
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
Original file line number Diff line number Diff line change
Expand Up @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class T1197(AttackTechnique):

@staticmethod
def get_report_data():
data = T1197.get_tech_base_data(T1197)
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'},
Expand Down
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
Original file line number Diff line number Diff line change
Expand Up @@ -46,52 +46,63 @@ def get_report_data():
"""
pass

@staticmethod
def technique_status(technique):
@classmethod
def technique_status(cls):
"""
Gets the status of a certain attack technique.
:param technique: technique's id.
:return: ScanStatus Enum object
"""
if mongo.db.telemetry.find_one({'telem_category': 'attack', 'data.status': ScanStatus.USED.value, 'data.technique': technique}):
if mongo.db.attack_results.find_one({'telem_category': 'attack',
'status': ScanStatus.USED.value,
'technique': cls.tech_id}):
return ScanStatus.USED
elif mongo.db.telemetry.find_one({'telem_category': 'attack', 'data.status': ScanStatus.SCANNED.value, 'data.technique': technique}):
elif mongo.db.attack_results.find_one({'telem_category': 'attack',
'status': ScanStatus.SCANNED.value,
'technique': cls.tech_id}):
return ScanStatus.SCANNED
else:
return ScanStatus.UNSCANNED

@staticmethod
def get_message_and_status(technique, status):
return {'message': technique.get_message_by_status(technique, status), 'status': status.name}
@classmethod
def get_message_and_status(cls, status):
"""
Returns a dict with attack technique's message and status.
:param status: Enum type value from common/attack_utils.py
:return: Dict with message and status
"""
return {'message': cls.get_message_by_status(status), 'status': status.name}

@staticmethod
def get_message_by_status(technique, status):
@classmethod
def get_message_by_status(cls, status):
"""
Picks a message to return based on status.
:param status: Enum type value from common/attack_utils.py
:return: message string
"""
if status == ScanStatus.UNSCANNED:
return technique.unscanned_msg
return cls.unscanned_msg
elif status == ScanStatus.SCANNED:
return technique.scanned_msg
return cls.scanned_msg
else:
return technique.used_msg
return cls.used_msg

@staticmethod
def technique_title(technique):
@classmethod
def technique_title(cls):
"""
:param technique: Technique's id. E.g. T1110
:return: techniques title. E.g. "T1110 Brute force"
"""
return AttackConfig.get_technique(technique)['title']
return AttackConfig.get_technique(cls.tech_id)['title']

@staticmethod
def get_tech_base_data(technique):
@classmethod
def get_tech_base_data(cls):
"""
Gathers basic attack technique data into a dict.
:param technique: Technique's id. E.g. T1110
:return: dict E.g. {'message': 'Brute force used', 'status': 'Used', 'title': 'T1110 Brute force'}
"""
data = {}
status = AttackTechnique.technique_status(technique.tech_id)
title = AttackTechnique.technique_title(technique.tech_id)
status = cls.technique_status()
title = cls.technique_title()
data.update({'status': status.name,
'title': title,
'message': technique.get_message_by_status(technique, status)})
'message': cls.get_message_by_status(status)})
return data
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import React from "react";

export function renderMachine(val){
return (
<span>{val.ip_addr} {(val.domain_name ? " (".concat(val.domain_name, ")") : "")}</span>
)
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import React from 'react';
import '../../../styles/Collapse.scss'
import ReactTable from "react-table";
import { renderMachine } from "./Helpers"


class T1075 extends React.Component {

constructor(props) {
super(props);
this.props.data.successful_logins.forEach((login) => this.setLoginHashType(login))
}

setLoginHashType(login){
if(login.attempts[0].ntlm_hash !== ""){
login.attempts[0].hashType = 'NTLM';
} else if(login.attempts[0].lm_hash !== ""){
login.attempts[0].hashType = 'LM';
}
}

static getHashColumns() {
return ([{
columns: [
{Header: 'Machine', id: 'machine', accessor: x => renderMachine(x.machine), style: { 'whiteSpace': 'unset' }},
{Header: 'Service', id: 'service', accessor: x => x.info.display_name, style: { 'whiteSpace': 'unset' }},
{Header: 'Username', id: 'attempts', accessor: x => x.attempts[0].user, style: { 'whiteSpace': 'unset' }},
{Header: 'Hash type', id: 'credentials', accessor: x => x.attempts[0].hashType, style: { 'whiteSpace': 'unset' }},
]
}])};

render() {
return (
<div>
<div>{this.props.data.message}</div>
<br/>
{this.props.data.status === 'USED' ?
<ReactTable
columns={T1075.getHashColumns()}
data={this.props.data.successful_logins}
showPagination={false}
defaultPageSize={this.props.data.successful_logins.length}
/> : ""}
</div>
);
}
}

export default T1075;
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import '../../../styles/Collapse.scss'
import ReactTable from "react-table";
import { renderMachine } from "./Helpers"


class T1110 extends React.Component {
Expand All @@ -12,7 +13,7 @@ class T1110 extends React.Component {
static getServiceColumns() {
return ([{
columns: [
{Header: 'Machine', id: 'machine', accessor: x => this.renderMachine(x.machine),
{Header: 'Machine', id: 'machine', accessor: x => 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' }},
Expand All @@ -23,13 +24,7 @@ class T1110 extends React.Component {
}])};

static renderCreds(creds) {
return <span>{creds.map(cred => <div>{cred}</div>)}</span>
};

static renderMachine(val){
return (
<span>{val.ip_addr} {(val.domain_name ? " (".concat(val.domain_name, ")") : "")}</span>
)
return <span>{creds.map(cred => <div key={cred}>{cred}</div>)}</span>
};

render() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import React from 'react';
import '../../../styles/Collapse.scss'
import ReactTable from "react-table";
import { renderMachine } from "./Helpers"


class T1210 extends React.Component {

constructor(props) {
super(props);
this.columns = [ {Header: 'Machine',
id: 'machine', accessor: x => T1210.renderMachine(x),
id: 'machine', accessor: x => renderMachine(x),
style: { 'whiteSpace': 'unset' },
width: 200},
{Header: 'Time',
Expand All @@ -21,12 +22,6 @@ class T1210 extends React.Component {
]
}

static renderMachine(val){
return (
<span>{val.ip_addr} {(val.domain_name ? " (".concat(val.domain_name, ")") : "")}</span>
)
};

renderExploitedMachines(){
if (this.props.data.bits_jobs.length === 0){
return (<div />)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import '../../../styles/Collapse.scss'
import ReactTable from "react-table";
import { renderMachine } from "./Helpers"


class T1210 extends React.Component {
Expand All @@ -12,7 +13,7 @@ class T1210 extends React.Component {
static getScanColumns() {
return ([{
columns: [
{Header: 'Machine', id: 'machine', accessor: x => this.renderMachine(x.machine),
{Header: 'Machine', id: 'machine', accessor: x => renderMachine(x.machine),
style: { 'whiteSpace': 'unset' }, width: 200},
{Header: 'Time', id: 'time', accessor: x => x.time, style: { 'whiteSpace': 'unset' }, width: 170},
{Header: 'Port', id: 'port', accessor: x =>x.service.port, style: { 'whiteSpace': 'unset' }},
Expand All @@ -23,20 +24,14 @@ class T1210 extends React.Component {
static getExploitColumns() {
return ([{
columns: [
{Header: 'Machine', id: 'machine', accessor: x => this.renderMachine(x.machine),
{Header: 'Machine', id: 'machine', accessor: x => renderMachine(x.machine),
style: { 'whiteSpace': 'unset' }, width: 200},
{Header: 'Time', id: 'time', accessor: x => x.time, style: { 'whiteSpace': 'unset' }, width: 170},
{Header: 'Port/url', id: 'port', accessor: x =>this.renderEndpoint(x.service), style: { 'whiteSpace': 'unset' }},
{Header: 'Service', id: 'service', accessor: x => x.service.display_name, style: { 'whiteSpace': 'unset' }}
]
}])};

static renderMachine(val){
return (
<span>{val.ip_addr} {(val.domain_name ? " (".concat(val.domain_name, ")") : "")}</span>
)
};

static renderEndpoint(val){
return (
<span>{(val.vulnerable_urls.length !== 0 ? val.vulnerable_urls[0] : val.vulnerable_ports[0])}</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,19 @@ 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 AuthComponent from '../AuthComponent';
import Collapse from '@kunukn/react-collapse';
import T1210 from '../attack/techniques/T1210';
import T1197 from '../attack/techniques/T1197';
import T1110 from '../attack/techniques/T1110';
import '../../styles/Collapse.scss'
import T1075 from "../attack/techniques/T1075";

const tech_components = {
'T1210': T1210,
'T1197': T1197,
'T1110': T1110
'T1110': T1110,
'T1075': T1075
};

const classNames = require('classnames');
Expand Down