forked from p34709852/monkey
Merge pull request #341 from VakarisZ/attack_pass_the_hash
T1075 pass the hash
This commit is contained in:
commit
2e020a6c73
|
@ -1,5 +1,5 @@
|
||||||
import logging
|
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.services.attack.attack_config import AttackConfig
|
||||||
from monkey_island.cc.database import mongo
|
from monkey_island.cc.database import mongo
|
||||||
|
|
||||||
|
@ -10,7 +10,8 @@ LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
TECHNIQUES = {'T1210': T1210.T1210,
|
TECHNIQUES = {'T1210': T1210.T1210,
|
||||||
'T1197': T1197.T1197,
|
'T1197': T1197.T1197,
|
||||||
'T1110': T1110.T1110}
|
'T1110': T1110.T1110,
|
||||||
|
'T1075': T1075.T1075}
|
||||||
|
|
||||||
REPORT_NAME = 'new_report'
|
REPORT_NAME = 'new_report'
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
@ -35,16 +35,16 @@ class T1110(AttackTechnique):
|
||||||
result['successful_creds'].append(T1110.parse_creds(attempt))
|
result['successful_creds'].append(T1110.parse_creds(attempt))
|
||||||
|
|
||||||
if succeeded:
|
if succeeded:
|
||||||
data = T1110.get_message_and_status(T1110, ScanStatus.USED)
|
status = ScanStatus.USED
|
||||||
elif attempts:
|
elif attempts:
|
||||||
data = T1110.get_message_and_status(T1110, ScanStatus.SCANNED)
|
status = ScanStatus.SCANNED
|
||||||
else:
|
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
|
# Remove data with no successful brute force attempts
|
||||||
attempts = [attempt for attempt in attempts if attempt['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
|
return data
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|
|
@ -12,7 +12,7 @@ class T1197(AttackTechnique):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_report_data():
|
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}},
|
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'},
|
{'$group': {'_id': {'ip_addr': '$data.machine.ip_addr', 'usage': '$data.usage'},
|
||||||
'ip_addr': {'$first': '$data.machine.ip_addr'},
|
'ip_addr': {'$first': '$data.machine.ip_addr'},
|
||||||
|
|
|
@ -14,15 +14,16 @@ class T1210(AttackTechnique):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_report_data():
|
def get_report_data():
|
||||||
data = {'title': T1210.technique_title(T1210.tech_id)}
|
data = {'title': T1210.technique_title()}
|
||||||
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:
|
||||||
data.update({'status': ScanStatus.USED.name, 'message': T1210.used_msg})
|
status = ScanStatus.USED
|
||||||
elif scanned_services:
|
elif scanned_services:
|
||||||
data.update({'status': ScanStatus.SCANNED.name, 'message': T1210.scanned_msg})
|
status = ScanStatus.SCANNED
|
||||||
else:
|
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})
|
data.update({'scanned_services': scanned_services, 'exploited_services': exploited_services})
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
|
@ -46,52 +46,63 @@ class AttackTechnique(object):
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@staticmethod
|
@classmethod
|
||||||
def technique_status(technique):
|
def technique_status(cls):
|
||||||
"""
|
"""
|
||||||
Gets the status of a certain attack technique.
|
Gets the status of a certain attack technique.
|
||||||
:param technique: technique's id.
|
|
||||||
:return: ScanStatus Enum object
|
: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
|
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
|
return ScanStatus.SCANNED
|
||||||
else:
|
else:
|
||||||
return ScanStatus.UNSCANNED
|
return ScanStatus.UNSCANNED
|
||||||
|
|
||||||
@staticmethod
|
@classmethod
|
||||||
def get_message_and_status(technique, status):
|
def get_message_and_status(cls, status):
|
||||||
return {'message': technique.get_message_by_status(technique, status), 'status': status.name}
|
"""
|
||||||
|
Returns a dict with attack technique's message and status.
|
||||||
@staticmethod
|
:param status: Enum type value from common/attack_utils.py
|
||||||
def get_message_by_status(technique, status):
|
:return: Dict with message and status
|
||||||
if status == ScanStatus.UNSCANNED:
|
"""
|
||||||
return technique.unscanned_msg
|
return {'message': cls.get_message_by_status(status), 'status': status.name}
|
||||||
elif status == ScanStatus.SCANNED:
|
|
||||||
return technique.scanned_msg
|
@classmethod
|
||||||
else:
|
def get_message_by_status(cls, status):
|
||||||
return technique.used_msg
|
"""
|
||||||
|
Picks a message to return based on status.
|
||||||
@staticmethod
|
:param status: Enum type value from common/attack_utils.py
|
||||||
def technique_title(technique):
|
:return: message string
|
||||||
|
"""
|
||||||
|
if status == ScanStatus.UNSCANNED:
|
||||||
|
return cls.unscanned_msg
|
||||||
|
elif status == ScanStatus.SCANNED:
|
||||||
|
return cls.scanned_msg
|
||||||
|
else:
|
||||||
|
return cls.used_msg
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def technique_title(cls):
|
||||||
"""
|
"""
|
||||||
:param technique: Technique's id. E.g. T1110
|
|
||||||
:return: techniques title. E.g. "T1110 Brute force"
|
:return: techniques title. E.g. "T1110 Brute force"
|
||||||
"""
|
"""
|
||||||
return AttackConfig.get_technique(technique)['title']
|
return AttackConfig.get_technique(cls.tech_id)['title']
|
||||||
|
|
||||||
@staticmethod
|
@classmethod
|
||||||
def get_tech_base_data(technique):
|
def get_tech_base_data(cls):
|
||||||
"""
|
"""
|
||||||
Gathers basic attack technique data into a dict.
|
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'}
|
:return: dict E.g. {'message': 'Brute force used', 'status': 'Used', 'title': 'T1110 Brute force'}
|
||||||
"""
|
"""
|
||||||
data = {}
|
data = {}
|
||||||
status = AttackTechnique.technique_status(technique.tech_id)
|
status = cls.technique_status()
|
||||||
title = AttackTechnique.technique_title(technique.tech_id)
|
title = cls.technique_title()
|
||||||
data.update({'status': status.name,
|
data.update({'status': status.name,
|
||||||
'title': title,
|
'title': title,
|
||||||
'message': technique.get_message_by_status(technique, status)})
|
'message': cls.get_message_by_status(status)})
|
||||||
return data
|
return data
|
||||||
|
|
|
@ -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>
|
||||||
|
)
|
||||||
|
};
|
|
@ -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;
|
|
@ -1,6 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import '../../../styles/Collapse.scss'
|
import '../../../styles/Collapse.scss'
|
||||||
import ReactTable from "react-table";
|
import ReactTable from "react-table";
|
||||||
|
import { renderMachine } from "./Helpers"
|
||||||
|
|
||||||
|
|
||||||
class T1110 extends React.Component {
|
class T1110 extends React.Component {
|
||||||
|
@ -12,7 +13,7 @@ class T1110 extends React.Component {
|
||||||
static getServiceColumns() {
|
static getServiceColumns() {
|
||||||
return ([{
|
return ([{
|
||||||
columns: [
|
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},
|
style: { 'whiteSpace': 'unset' }, width: 160},
|
||||||
{Header: 'Service', id: 'service', accessor: x => x.info.display_name, style: { 'whiteSpace': 'unset' }, width: 100},
|
{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: 'Started', id: 'started', accessor: x => x.info.started, style: { 'whiteSpace': 'unset' }},
|
||||||
|
@ -23,13 +24,7 @@ class T1110 extends React.Component {
|
||||||
}])};
|
}])};
|
||||||
|
|
||||||
static renderCreds(creds) {
|
static renderCreds(creds) {
|
||||||
return <span>{creds.map(cred => <div>{cred}</div>)}</span>
|
return <span>{creds.map(cred => <div key={cred}>{cred}</div>)}</span>
|
||||||
};
|
|
||||||
|
|
||||||
static renderMachine(val){
|
|
||||||
return (
|
|
||||||
<span>{val.ip_addr} {(val.domain_name ? " (".concat(val.domain_name, ")") : "")}</span>
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import '../../../styles/Collapse.scss'
|
import '../../../styles/Collapse.scss'
|
||||||
import ReactTable from "react-table";
|
import ReactTable from "react-table";
|
||||||
|
import { renderMachine } from "./Helpers"
|
||||||
|
|
||||||
|
|
||||||
class T1210 extends React.Component {
|
class T1210 extends React.Component {
|
||||||
|
@ -8,7 +9,7 @@ class T1210 extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.columns = [ {Header: 'Machine',
|
this.columns = [ {Header: 'Machine',
|
||||||
id: 'machine', accessor: x => T1210.renderMachine(x),
|
id: 'machine', accessor: x => renderMachine(x),
|
||||||
style: { 'whiteSpace': 'unset' },
|
style: { 'whiteSpace': 'unset' },
|
||||||
width: 200},
|
width: 200},
|
||||||
{Header: 'Time',
|
{Header: 'Time',
|
||||||
|
@ -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(){
|
renderExploitedMachines(){
|
||||||
if (this.props.data.bits_jobs.length === 0){
|
if (this.props.data.bits_jobs.length === 0){
|
||||||
return (<div />)
|
return (<div />)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import '../../../styles/Collapse.scss'
|
import '../../../styles/Collapse.scss'
|
||||||
import ReactTable from "react-table";
|
import ReactTable from "react-table";
|
||||||
|
import { renderMachine } from "./Helpers"
|
||||||
|
|
||||||
|
|
||||||
class T1210 extends React.Component {
|
class T1210 extends React.Component {
|
||||||
|
@ -12,7 +13,7 @@ class T1210 extends React.Component {
|
||||||
static getScanColumns() {
|
static getScanColumns() {
|
||||||
return ([{
|
return ([{
|
||||||
columns: [
|
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},
|
style: { 'whiteSpace': 'unset' }, width: 200},
|
||||||
{Header: 'Time', id: 'time', accessor: x => x.time, style: { 'whiteSpace': 'unset' }, width: 170},
|
{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' }},
|
{Header: 'Port', id: 'port', accessor: x =>x.service.port, style: { 'whiteSpace': 'unset' }},
|
||||||
|
@ -23,7 +24,7 @@ class T1210 extends React.Component {
|
||||||
static getExploitColumns() {
|
static getExploitColumns() {
|
||||||
return ([{
|
return ([{
|
||||||
columns: [
|
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},
|
style: { 'whiteSpace': 'unset' }, width: 200},
|
||||||
{Header: 'Time', id: 'time', accessor: x => x.time, style: { 'whiteSpace': 'unset' }, width: 170},
|
{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: 'Port/url', id: 'port', accessor: x =>this.renderEndpoint(x.service), style: { 'whiteSpace': 'unset' }},
|
||||||
|
@ -31,12 +32,6 @@ class T1210 extends React.Component {
|
||||||
]
|
]
|
||||||
}])};
|
}])};
|
||||||
|
|
||||||
static renderMachine(val){
|
|
||||||
return (
|
|
||||||
<span>{val.ip_addr} {(val.domain_name ? " (".concat(val.domain_name, ")") : "")}</span>
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
static renderEndpoint(val){
|
static renderEndpoint(val){
|
||||||
return (
|
return (
|
||||||
<span>{(val.vulnerable_urls.length !== 0 ? val.vulnerable_urls[0] : val.vulnerable_ports[0])}</span>
|
<span>{(val.vulnerable_urls.length !== 0 ? val.vulnerable_urls[0] : val.vulnerable_ports[0])}</span>
|
||||||
|
|
|
@ -2,17 +2,19 @@ import React from 'react';
|
||||||
import {Col} from 'react-bootstrap';
|
import {Col} from 'react-bootstrap';
|
||||||
import {ReactiveGraph} from 'components/reactive-graph/ReactiveGraph';
|
import {ReactiveGraph} from 'components/reactive-graph/ReactiveGraph';
|
||||||
import {edgeGroupToColor, options} from 'components/map/MapOptions';
|
import {edgeGroupToColor, options} from 'components/map/MapOptions';
|
||||||
|
import '../../styles/Collapse.scss'
|
||||||
import AuthComponent from '../AuthComponent';
|
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 T1110 from '../attack/techniques/T1110';
|
||||||
import '../../styles/Collapse.scss'
|
import T1075 from "../attack/techniques/T1075";
|
||||||
|
|
||||||
const tech_components = {
|
const tech_components = {
|
||||||
'T1210': T1210,
|
'T1210': T1210,
|
||||||
'T1197': T1197,
|
'T1197': T1197,
|
||||||
'T1110': T1110
|
'T1110': T1110,
|
||||||
|
'T1075': T1075
|
||||||
};
|
};
|
||||||
|
|
||||||
const classNames = require('classnames');
|
const classNames = require('classnames');
|
||||||
|
|
Loading…
Reference in New Issue