Merge pull request #379 from VakarisZ/attack_exfiltration_c2_channel

T1041 Exfiltration Over Command and Control Channel
This commit is contained in:
Itay Mizeretz 2019-08-21 17:27:55 +03:00 committed by GitHub
commit 22a5f87ebb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 125 additions and 18 deletions

View File

@ -16,4 +16,5 @@ from config import Config
from creds import Creds
from monkey_ttl import MonkeyTtl
from pba_results import PbaResults
from command_control_channel import CommandControlChannel
from monkey import Monkey

View File

@ -0,0 +1,11 @@
from mongoengine import EmbeddedDocument, StringField
class CommandControlChannel(EmbeddedDocument):
"""
This value describes command and control channel monkey used in communication
src - Monkey Island's IP
dst - Monkey's IP (in case of a proxy chain this is the IP of the last monkey)
"""
src = StringField()
dst = StringField()

View File

@ -6,6 +6,7 @@ from mongoengine import Document, StringField, ListField, BooleanField, Embedded
from monkey_island.cc.models.monkey_ttl import MonkeyTtl, create_monkey_ttl_document
from monkey_island.cc.consts import DEFAULT_MONKEY_TTL_EXPIRY_DURATION_IN_SECONDS
from monkey_island.cc.models.command_control_channel import CommandControlChannel
class Monkey(Document):
@ -36,6 +37,7 @@ class Monkey(Document):
pba_results = ListField()
ttl_ref = ReferenceField(MonkeyTtl)
tunnel = ReferenceField("self")
command_control_channel = EmbeddedDocumentField(CommandControlChannel)
# LOGIC
@staticmethod

View File

@ -48,6 +48,7 @@ class Telemetry(flask_restful.Resource):
def post(self):
telemetry_json = json.loads(request.data)
telemetry_json['timestamp'] = datetime.now()
telemetry_json['command_control_channel'] = {'src': request.remote_addr, 'dst': request.host}
# Monkey communicated, so it's alive. Update the TTL.
Monkey.get_single_monkey_by_guid(telemetry_json['monkey_guid']).renew_ttl()
@ -113,6 +114,7 @@ class Telemetry(flask_restful.Resource):
@staticmethod
def process_state_telemetry(telemetry_json):
monkey = NodeService.get_monkey_by_guid(telemetry_json['monkey_guid'])
NodeService.add_communication_info(monkey, telemetry_json['command_control_channel'])
if telemetry_json['data']['done']:
NodeService.set_monkey_dead(monkey, True)
else:

View File

@ -2,7 +2,7 @@ import logging
from monkey_island.cc.models import Monkey
from monkey_island.cc.services.attack.technique_reports import T1210, T1197, T1110, T1075, T1003, T1059, T1086, T1082
from monkey_island.cc.services.attack.technique_reports import T1145, T1105, T1065, T1035, T1129, T1106, T1107, T1188
from monkey_island.cc.services.attack.technique_reports import T1090
from monkey_island.cc.services.attack.technique_reports import T1090, T1041
from monkey_island.cc.services.attack.attack_config import AttackConfig
from monkey_island.cc.database import mongo
@ -27,7 +27,8 @@ TECHNIQUES = {'T1210': T1210.T1210,
'T1106': T1106.T1106,
'T1107': T1107.T1107,
'T1188': T1188.T1188,
'T1090': T1090.T1090}
'T1090': T1090.T1090,
'T1041': T1041.T1041}
REPORT_NAME = 'new_report'

View File

@ -205,5 +205,18 @@ SCHEMA = {
}
}
},
"exfiltration": {
"title": "Exfiltration",
"type": "object",
"properties": {
"T1041": {
"title": "T1041 Exfiltration Over Command and Control Channel",
"type": "bool",
"value": True,
"necessary": True,
"description": "Data exfiltration is performed over the Command and Control channel."
}
}
}
}
}

View File

@ -0,0 +1,27 @@
from monkey_island.cc.services.attack.technique_reports import AttackTechnique
from monkey_island.cc.models.monkey import Monkey
from common.utils.attack_utils import ScanStatus
__author__ = "VakarisZ"
class T1041(AttackTechnique):
tech_id = "T1041"
unscanned_msg = "Monkey didn't exfiltrate any info trough command and control channel."
scanned_msg = ""
used_msg = "Monkey exfiltrated info trough command and control channel."
@staticmethod
def get_report_data():
monkeys = list(Monkey.objects())
info = [{'src': monkey['command_control_channel']['src'],
'dst': monkey['command_control_channel']['dst']}
for monkey in monkeys if monkey['command_control_channel']]
if info:
status = ScanStatus.USED.value
else:
status = ScanStatus.UNSCANNED.value
data = T1041.get_base_data_by_status(status)
data.update({'command_control_channel': info})
return data

View File

@ -247,6 +247,12 @@ class NodeService:
{'$set': props_to_set},
upsert=False)
@staticmethod
def add_communication_info(monkey, info):
mongo.db.monkey.update({"guid": monkey["guid"]},
{"$set": {'command_control_channel': info}},
upsert=False)
@staticmethod
def get_monkey_island_monkey():
ip_addresses = local_ip_addresses()

View File

@ -0,0 +1,37 @@
import React from 'react';
import '../../../styles/Collapse.scss'
import ReactTable from "react-table";
import {ScanStatus} from "./Helpers";
class T1041 extends React.Component {
constructor(props) {
super(props);
}
static getC2Columns() {
return ([{
Header: "Data exfiltration channels",
columns: [
{Header: 'Source', id: 'src', accessor: x => x.src, style: { 'whiteSpace': 'unset' }},
{Header: 'Destination', id: 'dst', accessor: x => x.dst, style: { 'whiteSpace': 'unset' }}
]}])};
render() {
return (
<div>
<div>{this.props.data.message}</div>
<br/>
{this.props.data.status === ScanStatus.USED ?
<ReactTable
columns={T1041.getC2Columns()}
data={this.props.data.command_control_channel}
showPagination={false}
defaultPageSize={this.props.data.command_control_channel.length}
/> : ""}
</div>
);
}
}
export default T1041;

View File

@ -1,7 +1,7 @@
import React from 'react';
import '../../../styles/Collapse.scss'
import ReactTable from "react-table";
import { renderMachineFromSystemData, scanStatus } from "./Helpers"
import { renderMachineFromSystemData, ScanStatus } from "./Helpers"
class T1090 extends React.Component {
@ -24,16 +24,13 @@ class T1090 extends React.Component {
<div>
<div>{this.props.data.message}</div>
<br/>
{this.props.data.status === scanStatus.USED ?
<div>
<p>Proxies were used to communicate with:</p>
<ReactTable
columns={T1090.getProxyColumns()}
data={this.props.data.proxies}
showPagination={false}
defaultPageSize={this.props.data.proxies.length}
/>
</div>: ""}
{this.props.data.status === ScanStatus.USED ?
<ReactTable
columns={T1090.getProxyColumns()}
data={this.props.data.proxies}
showPagination={false}
defaultPageSize={this.props.data.proxies.length}
/> : ""}
</div>
);
}

View File

@ -1,7 +1,7 @@
import React from 'react';
import '../../../styles/Collapse.scss'
import ReactTable from "react-table";
import { renderMachineFromSystemData, scanStatus } from "./Helpers"
import { renderMachineFromSystemData, ScanStatus } from "./Helpers"
class T1188 extends React.Component {
@ -34,7 +34,7 @@ class T1188 extends React.Component {
<div>
<div>{this.props.data.message}</div>
<br/>
{this.props.data.status === scanStatus.USED ?
{this.props.data.status === ScanStatus.USED ?
<ReactTable
columns={T1188.getHopColumns()}
data={this.props.data.hops}

View File

@ -496,7 +496,7 @@ class ConfigurePageComponent extends AuthComponent {
}
return (
<Col xs={12} lg={8}>
<Col xs={12} lg={10}>
{this.renderAttackAlertModal()}
<h1 className="page-title">Monkey Configuration</h1>
{this.renderNav()}

View File

@ -23,6 +23,7 @@ import T1129 from "../attack/techniques/T1129";
import T1106 from "../attack/techniques/T1106";
import T1188 from "../attack/techniques/T1188";
import T1090 from "../attack/techniques/T1090";
import T1041 from "../attack/techniques/T1041";
const tech_components = {
'T1210': T1210,
@ -41,7 +42,8 @@ const tech_components = {
'T1106': T1106,
'T1107': T1107,
'T1188': T1188,
'T1090': T1090
'T1090': T1090,
'T1041': T1041
};
const classNames = require('classnames');
@ -158,7 +160,7 @@ class AttackReportPageComponent extends AuthComponent {
return (
<div>
{this.renderLegend()}
<section className="app">{content}</section>
<section className="attack-report">{content}</section>
</div>
)
}

View File

@ -525,6 +525,14 @@ body {
margin-bottom: 30px;
}
.attack-matrix {
margin-bottom: 20px;
}
.attack-report .btn-collapse span:nth-of-type(2){
flex: 0;
}
.icon-info {
color: #ade3eb !important;
}