forked from p15670423/monkey
Merge pull request #80 from guardicore/feature/map-liveness
Feature/map liveness
This commit is contained in:
commit
cc1415b4d5
|
@ -17,6 +17,7 @@ from cc.resources.edge import Edge
|
||||||
from cc.resources.node import Node
|
from cc.resources.node import Node
|
||||||
|
|
||||||
from cc.resources.root import Root
|
from cc.resources.root import Root
|
||||||
|
from cc.resources.telemetry_feed import TelemetryFeed
|
||||||
from cc.services.config import ConfigService
|
from cc.services.config import ConfigService
|
||||||
|
|
||||||
__author__ = 'Barak'
|
__author__ = 'Barak'
|
||||||
|
@ -88,5 +89,6 @@ def init_app(mongo_url):
|
||||||
api.add_resource(NetMap, '/api/netmap', '/api/netmap/')
|
api.add_resource(NetMap, '/api/netmap', '/api/netmap/')
|
||||||
api.add_resource(Edge, '/api/netmap/edge', '/api/netmap/edge/')
|
api.add_resource(Edge, '/api/netmap/edge', '/api/netmap/edge/')
|
||||||
api.add_resource(Node, '/api/netmap/node', '/api/netmap/node/')
|
api.add_resource(Node, '/api/netmap/node', '/api/netmap/node/')
|
||||||
|
api.add_resource(TelemetryFeed, '/api/telemetry-feed', '/api/telemetry-feed/')
|
||||||
|
|
||||||
return app
|
return app
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
import dateutil
|
||||||
|
import flask_restful
|
||||||
|
from flask import request
|
||||||
|
|
||||||
|
from cc.database import mongo
|
||||||
|
from cc.services.node import NodeService
|
||||||
|
|
||||||
|
__author__ = 'itay.mizeretz'
|
||||||
|
|
||||||
|
|
||||||
|
class TelemetryFeed(flask_restful.Resource):
|
||||||
|
def get(self, **kw):
|
||||||
|
timestamp = request.args.get('timestamp')
|
||||||
|
if "null" == timestamp or timestamp is None: # special case to avoid ugly JS code...
|
||||||
|
telemetries = mongo.db.telemetry.find({})
|
||||||
|
else:
|
||||||
|
telemetries = mongo.db.telemetry.find({'timestamp': {'$gt': dateutil.parser.parse(timestamp)}})
|
||||||
|
|
||||||
|
return \
|
||||||
|
{
|
||||||
|
'telemetries': [TelemetryFeed.get_displayed_telemetry(telem) for telem in telemetries],
|
||||||
|
'timestamp': datetime.now().isoformat()
|
||||||
|
}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_displayed_telemetry(telem):
|
||||||
|
return \
|
||||||
|
{
|
||||||
|
'id': telem['_id'],
|
||||||
|
'timestamp': telem['timestamp'].strftime('%d/%m/%Y %H:%M:%S'),
|
||||||
|
'hostname': NodeService.get_monkey_by_guid(telem['monkey_guid'])['hostname'],
|
||||||
|
'brief': TELEM_PROCESS_DICT[telem['telem_type']](telem)
|
||||||
|
}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_tunnel_telem_brief(telem):
|
||||||
|
tunnel = telem['data']['proxy']
|
||||||
|
if tunnel is None:
|
||||||
|
return 'No tunnel is used.'
|
||||||
|
else:
|
||||||
|
tunnel_host_ip = tunnel.split(":")[-2].replace("//", "")
|
||||||
|
tunnel_host = NodeService.get_monkey_by_ip(tunnel_host_ip)['hostname']
|
||||||
|
return 'Tunnel set up to machine: %s.' % tunnel_host
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_state_telem_brief(telem):
|
||||||
|
if telem['data']['done']:
|
||||||
|
return 'Monkey died.'
|
||||||
|
else:
|
||||||
|
return 'Monkey started.'
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_exploit_telem_brief(telem):
|
||||||
|
target = telem['data']['machine']['ip_addr']
|
||||||
|
exploiter = telem['data']['exploiter']
|
||||||
|
result = telem['data']['result']
|
||||||
|
if result:
|
||||||
|
return 'Monkey successfully exploited %s using the %s exploiter.' % (target, exploiter)
|
||||||
|
else:
|
||||||
|
return 'Monkey failed exploiting %s using the %s exploiter.' % (target, exploiter)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_scan_telem_brief(telem):
|
||||||
|
return 'Monkey discovered machine %s.' % telem['data']['machine']['ip_addr']
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_systeminfo_telem_brief(telem):
|
||||||
|
return 'Monkey collected system information.'
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_trace_telem_brief(telem):
|
||||||
|
return 'Monkey reached max depth.'
|
||||||
|
|
||||||
|
|
||||||
|
TELEM_PROCESS_DICT = \
|
||||||
|
{
|
||||||
|
'tunnel': TelemetryFeed.get_tunnel_telem_brief,
|
||||||
|
'state': TelemetryFeed.get_state_telem_brief,
|
||||||
|
'exploit': TelemetryFeed.get_exploit_telem_brief,
|
||||||
|
'scan': TelemetryFeed.get_scan_telem_brief,
|
||||||
|
'system_info_collection': TelemetryFeed.get_systeminfo_telem_brief,
|
||||||
|
'trace': TelemetryFeed.get_trace_telem_brief
|
||||||
|
}
|
|
@ -53,7 +53,9 @@ class MapPageComponent extends React.Component {
|
||||||
selected: null,
|
selected: null,
|
||||||
selectedType: null,
|
selectedType: null,
|
||||||
killPressed: false,
|
killPressed: false,
|
||||||
showKillDialog: false
|
showKillDialog: false,
|
||||||
|
telemetry: [],
|
||||||
|
telemetryLastTimestamp: null
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,13 +79,18 @@ class MapPageComponent extends React.Component {
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.updateMapFromServer();
|
this.updateMapFromServer();
|
||||||
this.interval = setInterval(this.updateMapFromServer, 1000);
|
this.interval = setInterval(this.timedEvents, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
clearInterval(this.interval);
|
clearInterval(this.interval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
timedEvents = () => {
|
||||||
|
this.updateMapFromServer();
|
||||||
|
this.updateTelemetryFromServer();
|
||||||
|
};
|
||||||
|
|
||||||
updateMapFromServer = () => {
|
updateMapFromServer = () => {
|
||||||
fetch('/api/netmap')
|
fetch('/api/netmap')
|
||||||
.then(res => res.json())
|
.then(res => res.json())
|
||||||
|
@ -96,6 +103,21 @@ class MapPageComponent extends React.Component {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
updateTelemetryFromServer = () => {
|
||||||
|
fetch('/api/telemetry-feed?timestamp='+this.state.telemetryLastTimestamp)
|
||||||
|
.then(res => res.json())
|
||||||
|
.then(res => {
|
||||||
|
let newTelem = this.state.telemetry.concat(res['telemetries']);
|
||||||
|
|
||||||
|
this.setState(
|
||||||
|
{
|
||||||
|
telemetry: newTelem,
|
||||||
|
telemetryLastTimestamp: res['timestamp']
|
||||||
|
});
|
||||||
|
this.props.onStatusChange();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
selectionChanged(event) {
|
selectionChanged(event) {
|
||||||
if (event.nodes.length === 1) {
|
if (event.nodes.length === 1) {
|
||||||
fetch('/api/netmap/node?id=' + event.nodes[0])
|
fetch('/api/netmap/node?id=' + event.nodes[0])
|
||||||
|
@ -156,6 +178,26 @@ class MapPageComponent extends React.Component {
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
renderTelemetryEntry(telemetry) {
|
||||||
|
return (
|
||||||
|
<div key={telemetry.id}>
|
||||||
|
<span className="date">{telemetry.timestamp}</span>
|
||||||
|
<span className="source"> {telemetry.hostname}:</span>
|
||||||
|
<span className="event"> {telemetry.brief}</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderTelemetryConsole() {
|
||||||
|
return (
|
||||||
|
<div className="telemetry-console">
|
||||||
|
{
|
||||||
|
this.state.telemetry.map(this.renderTelemetryEntry)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
@ -174,17 +216,7 @@ class MapPageComponent extends React.Component {
|
||||||
<b style={{color: '#aeaeae'}}> | </b>
|
<b style={{color: '#aeaeae'}}> | </b>
|
||||||
<span>Island Communication <i className="fa fa-lg fa-minus" style={{color: '#a9aaa9'}} /></span>
|
<span>Island Communication <i className="fa fa-lg fa-minus" style={{color: '#a9aaa9'}} /></span>
|
||||||
</div>
|
</div>
|
||||||
{
|
{ this.renderTelemetryConsole() }
|
||||||
/*
|
|
||||||
<div className="telemetry-console">
|
|
||||||
<div>
|
|
||||||
<span className="date">2017-10-16 16:00:05</span>
|
|
||||||
<span className="source"> monkey-elastic</span>
|
|
||||||
<span className="event"> bla bla</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
<div style={{height: '80vh'}}>
|
<div style={{height: '80vh'}}>
|
||||||
<ReactiveGraph graph={this.state.graph} options={options} events={this.events}/>
|
<ReactiveGraph graph={this.state.graph} options={options} events={this.events}/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -276,13 +276,14 @@ body {
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
height: 70px;
|
height: 130px;
|
||||||
background: rgba(0,0,0,0.7);
|
background: rgba(0,0,0,0.7);
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
border: 3px solid #aaa;
|
border: 3px solid #aaa;
|
||||||
padding: 0.5em;
|
padding: 0.5em;
|
||||||
color: white;
|
color: white;
|
||||||
font-family: Consolas, "Courier New", monospace;
|
font-family: Consolas, "Courier New", monospace;
|
||||||
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.telemetry-console .date {
|
.telemetry-console .date {
|
||||||
|
|
Loading…
Reference in New Issue