ui improvements post review
This commit is contained in:
parent
f0c43f8bb5
commit
0846258bbd
|
@ -1,8 +1,6 @@
|
||||||
from bson import ObjectId
|
|
||||||
from flask import request
|
from flask import request
|
||||||
import flask_restful
|
import flask_restful
|
||||||
|
|
||||||
from cc.database import mongo
|
|
||||||
from cc.services.edge import EdgeService
|
from cc.services.edge import EdgeService
|
||||||
|
|
||||||
__author__ = 'Barak'
|
__author__ = 'Barak'
|
||||||
|
@ -11,7 +9,6 @@ __author__ = 'Barak'
|
||||||
class Edge(flask_restful.Resource):
|
class Edge(flask_restful.Resource):
|
||||||
def get(self):
|
def get(self):
|
||||||
edge_id = request.args.get('id')
|
edge_id = request.args.get('id')
|
||||||
|
|
||||||
if edge_id:
|
if edge_id:
|
||||||
return {"edge": EdgeService.get_displayed_edge_by_id(edge_id)}
|
return {"edge": EdgeService.get_displayed_edge_by_id(edge_id)}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
from bson import ObjectId
|
|
||||||
from flask import request
|
from flask import request
|
||||||
import flask_restful
|
import flask_restful
|
||||||
|
|
||||||
from cc.database import mongo
|
|
||||||
from cc.services.edge import EdgeService
|
|
||||||
from cc.services.node import NodeService
|
from cc.services.node import NodeService
|
||||||
|
|
||||||
__author__ = 'Barak'
|
__author__ = 'Barak'
|
||||||
|
|
|
@ -169,11 +169,11 @@ class EdgeService:
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_edge_group(edge):
|
def get_edge_group(edge):
|
||||||
if edge["exploited"]:
|
if edge.get("exploited"):
|
||||||
return "exploited"
|
return "exploited"
|
||||||
if edge["tunnel"]:
|
if edge.get("tunnel"):
|
||||||
return "tunnel"
|
return "tunnel"
|
||||||
if (len(edge["scans"]) > 0) or (len(edge["exploits"]) > 0):
|
if (len(edge.get("scans", [])) > 0) or (len(edge.get("exploits", [])) > 0):
|
||||||
return "scan"
|
return "scan"
|
||||||
return "empty"
|
return "empty"
|
||||||
|
|
||||||
|
|
|
@ -101,10 +101,7 @@ class NodeService:
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_node_group(node):
|
def get_node_group(node):
|
||||||
if node["exploited"]:
|
return "exploited" if node.get("exploited") else "clean"
|
||||||
return "exploited"
|
|
||||||
else:
|
|
||||||
return "clean"
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def monkey_to_net_node(monkey):
|
def monkey_to_net_node(monkey):
|
||||||
|
|
|
@ -70,8 +70,6 @@
|
||||||
"react-bootstrap": "^0.31.2",
|
"react-bootstrap": "^0.31.2",
|
||||||
"react-copy-to-clipboard": "^5.0.0",
|
"react-copy-to-clipboard": "^5.0.0",
|
||||||
"react-data-components": "^1.1.1",
|
"react-data-components": "^1.1.1",
|
||||||
"react-data-grid": "^2.0.58",
|
|
||||||
"react-data-grid-addons": "^2.0.58",
|
|
||||||
"react-dom": "^15.6.1",
|
"react-dom": "^15.6.1",
|
||||||
"react-fa": "^4.2.0",
|
"react-fa": "^4.2.0",
|
||||||
"react-graph-vis": "^0.1.3",
|
"react-graph-vis": "^0.1.3",
|
||||||
|
|
|
@ -14,6 +14,7 @@ require('react-data-components/css/table-twbs.css');
|
||||||
require('styles/App.css');
|
require('styles/App.css');
|
||||||
|
|
||||||
let logoImage = require('../images/monkey-logo.png');
|
let logoImage = require('../images/monkey-logo.png');
|
||||||
|
let guardicoreLogoImage = require('../images/guardicore-logo.png');
|
||||||
|
|
||||||
class AppComponent extends React.Component {
|
class AppComponent extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
|
@ -24,52 +25,56 @@ class AppComponent extends React.Component {
|
||||||
<Col sm={3} md={2} className="sidebar">
|
<Col sm={3} md={2} className="sidebar">
|
||||||
<div className="header">
|
<div className="header">
|
||||||
<img src={logoImage} alt="Infection Monkey"/>
|
<img src={logoImage} alt="Infection Monkey"/>
|
||||||
by GuardiCore
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ul className="navigation">
|
<ul className="navigation">
|
||||||
<li>
|
<li>
|
||||||
<NavLink to="/" exact={true}>
|
<NavLink to="/" exact={true}>
|
||||||
<span className="number">1.</span>
|
<span className="number">1.</span>
|
||||||
Run Server
|
Run C&C Server
|
||||||
<Icon name="check" className="pull-right checkmark text-success"/>
|
<Icon name="check" className="pull-right checkmark text-success"/>
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
|
||||||
<NavLink to="/configure">
|
|
||||||
<span className="number">2.</span>
|
|
||||||
Configure
|
|
||||||
</NavLink>
|
|
||||||
</li>
|
|
||||||
<li>
|
<li>
|
||||||
<NavLink to="/run-monkey">
|
<NavLink to="/run-monkey">
|
||||||
<span className="number">3.</span>
|
<span className="number">2.</span>
|
||||||
Run Monkey
|
Run Monkey
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a className="disabled">
|
<NavLink to="/infection/map">
|
||||||
<span className="number">4.</span>
|
<span className="number">3.</span>
|
||||||
Infection
|
Infection Map
|
||||||
</a>
|
</NavLink>
|
||||||
<ul>
|
|
||||||
<li><NavLink to="/infection/map">Map</NavLink></li>
|
|
||||||
<li><NavLink to="/infection/logs">Full Logs</NavLink></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<NavLink to="/report">
|
<NavLink to="/report">
|
||||||
<span className="number">5.</span>
|
<span className="number">4.</span>
|
||||||
Pen. Test Report
|
Pen. Test Report
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<NavLink to="/start-over">
|
||||||
|
<span className="number">5.</span>
|
||||||
|
Start Over
|
||||||
|
</NavLink>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a>Clear DB</a></li>
|
<li><NavLink to="/configure">Configuration</NavLink></li>
|
||||||
<li><a>Kill All Monkeys</a></li>
|
<li><NavLink to="/infection/logs">Monkey Telemetry</NavLink></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
<hr/>
|
||||||
|
<div className="guardicore-link">
|
||||||
|
<span>Powered by</span>
|
||||||
|
<a href="http://www.guardicore.com" target="_blank">
|
||||||
|
<img src={guardicoreLogoImage} alt="GuardiCore"/>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
</Col>
|
</Col>
|
||||||
<Col sm={9} md={10} smOffset={3} mdOffset={2} className="main">
|
<Col sm={9} md={10} smOffset={3} mdOffset={2} className="main">
|
||||||
<Route exact path="/" component={RunServerPage}/>
|
<Route exact path="/" component={RunServerPage}/>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Form from 'react-jsonschema-form';
|
import Form from 'react-jsonschema-form';
|
||||||
import {Col} from 'react-bootstrap';
|
import {Col, Nav, NavItem} from 'react-bootstrap';
|
||||||
|
|
||||||
class ConfigurePageComponent extends React.Component {
|
class ConfigurePageComponent extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
@ -47,9 +47,9 @@ class ConfigurePageComponent extends React.Component {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
setSelectedSection = (event) => {
|
setSelectedSection = (key) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
selectedSection: event.target.value
|
selectedSection: key
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -57,17 +57,14 @@ class ConfigurePageComponent extends React.Component {
|
||||||
return (
|
return (
|
||||||
<Col xs={8}>
|
<Col xs={8}>
|
||||||
<h1 className="page-title">Monkey Configuration</h1>
|
<h1 className="page-title">Monkey Configuration</h1>
|
||||||
<div className="alert alert-info">
|
|
||||||
<i className="glyphicon glyphicon-info-sign" style={{'marginRight': '5px'}}/>
|
|
||||||
This configuration will only apply on new infections.
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<select value={this.state.selectedSection} onChange={this.setSelectedSection}
|
<Nav bsStyle="tabs" justified
|
||||||
className="form-control input-lg" style={{'margin-bottom': '1em'}}>
|
activeKey={this.state.selectedSection} onSelect={this.setSelectedSection}
|
||||||
|
style={{'marginBottom': '2em'}}>
|
||||||
{this.state.sections.map(section =>
|
{this.state.sections.map(section =>
|
||||||
<option value={section.key}>{section.title}</option>
|
<NavItem key={section.key} eventKey={section.key}>{section.title}</NavItem>
|
||||||
)}
|
)}
|
||||||
</select>
|
</Nav>
|
||||||
|
|
||||||
{ this.state.selectedSection ?
|
{ this.state.selectedSection ?
|
||||||
<Form schema={this.state.schema.properties[this.state.selectedSection]}
|
<Form schema={this.state.schema.properties[this.state.selectedSection]}
|
||||||
|
@ -75,6 +72,11 @@ class ConfigurePageComponent extends React.Component {
|
||||||
onSubmit={this.onSubmit}/>
|
onSubmit={this.onSubmit}/>
|
||||||
: ''}
|
: ''}
|
||||||
|
|
||||||
|
<div className="alert alert-info">
|
||||||
|
<i className="glyphicon glyphicon-info-sign" style={{'marginRight': '5px'}}/>
|
||||||
|
This configuration will only apply to new infections.
|
||||||
|
</div>
|
||||||
|
|
||||||
{ this.state.saved ?
|
{ this.state.saved ?
|
||||||
<p>Configuration saved successfully.</p>
|
<p>Configuration saved successfully.</p>
|
||||||
: ''}
|
: ''}
|
||||||
|
|
|
@ -3,13 +3,13 @@ import {Col} from 'react-bootstrap';
|
||||||
import JSONTree from 'react-json-tree'
|
import JSONTree from 'react-json-tree'
|
||||||
import {DataTable} from 'react-data-components';
|
import {DataTable} from 'react-data-components';
|
||||||
|
|
||||||
const renderJson = (val, row) => <JSONTree data={val} level={1} theme="eighties" invertTheme={true} />;
|
const renderJson = (val) => <JSONTree data={val} level={1} theme="eighties" invertTheme={true} />;
|
||||||
const renderTime = (val, row) => val.split('.')[0];
|
const renderTime = (val) => val.split('.')[0];
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{ title: 'Type', prop: 'telem_type' },
|
|
||||||
{ title: 'Monkey ID', prop: 'monkey_guid' },
|
|
||||||
{ title: 'Time', prop: 'timestamp', render: renderTime},
|
{ title: 'Time', prop: 'timestamp', render: renderTime},
|
||||||
|
{ title: 'Monkey ID', prop: 'monkey_guid' },
|
||||||
|
{ title: 'Type', prop: 'telem_type' },
|
||||||
{ title: 'More Info', prop: 'data', render: renderJson, width: '40%' }
|
{ title: 'More Info', prop: 'data', render: renderJson, width: '40%' }
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {Col} from 'react-bootstrap';
|
import {Col} from 'react-bootstrap';
|
||||||
import Graph from 'react-graph-vis';
|
import Graph from 'react-graph-vis';
|
||||||
import {Icon} from 'react-fa'
|
import PreviewPane from 'components/preview-pane/PreviewPane';
|
||||||
|
import {Link} from 'react-router-dom';
|
||||||
|
import {Icon} from 'react-fa';
|
||||||
|
|
||||||
let options = {
|
let options = {
|
||||||
layout: {
|
layout: {
|
||||||
|
@ -44,7 +45,9 @@ class MapPageComponent extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
graph: {nodes: [], edges: []}
|
graph: {nodes: [], edges: []},
|
||||||
|
selected: null,
|
||||||
|
selectedType: null
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,13 +63,19 @@ class MapPageComponent extends React.Component {
|
||||||
|
|
||||||
selectionChanged(event) {
|
selectionChanged(event) {
|
||||||
if (event.nodes.length === 1) {
|
if (event.nodes.length === 1) {
|
||||||
console.log('selected node:', event.nodes[0]);
|
console.log('selected node:', event.nodes[0]); // eslint-disable-line no-console
|
||||||
|
fetch('/api/netmap/node?id='+event.nodes[0])
|
||||||
|
.then(res => res.json())
|
||||||
|
.then(res => this.setState({selected: res, selectedType: 'node'}));
|
||||||
}
|
}
|
||||||
else if (event.edges.length === 1) {
|
else if (event.edges.length === 1) {
|
||||||
console.log('selected edge:', event.edges[0]);
|
fetch('/api/netmap/edge?id='+event.edges[0])
|
||||||
|
.then(res => res.json())
|
||||||
|
.then(res => this.setState({selected: res.edge, selectedType: 'edge'}));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
console.log('no preview.');
|
console.log('selection cleared.'); // eslint-disable-line no-console
|
||||||
|
this.setState({selected: null, selectedType: null});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,44 +86,21 @@ class MapPageComponent extends React.Component {
|
||||||
<h1 className="page-title">Infection Map</h1>
|
<h1 className="page-title">Infection Map</h1>
|
||||||
</Col>
|
</Col>
|
||||||
<Col xs={8}>
|
<Col xs={8}>
|
||||||
<div className="pull-left">
|
|
||||||
<input placeholder="Search" />
|
|
||||||
</div>
|
|
||||||
<Graph graph={this.state.graph} options={options} events={this.events}/>
|
<Graph graph={this.state.graph} options={options} events={this.events}/>
|
||||||
</Col>
|
</Col>
|
||||||
<Col xs={4}>
|
<Col xs={4}>
|
||||||
<div className="panel panel-default preview">
|
<input className="form-control input-block"
|
||||||
<div className="panel-heading">
|
placeholder="Find on map"
|
||||||
<h3>
|
style={{'marginBottom': '1em'}}/>
|
||||||
<Icon name="fire"/>
|
|
||||||
vm4
|
|
||||||
<small>Infected Asset</small>
|
|
||||||
</h3>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="panel-body">
|
<PreviewPane item={this.state.selected} type={this.state.selectedType} />
|
||||||
<h4>Machine Info</h4>
|
|
||||||
<p>...</p>
|
|
||||||
|
|
||||||
<h4 style={{'marginTop': '2em'}}>Exploit Method</h4>
|
<div>
|
||||||
<p>...</p>
|
<Link to="/infection/logs" className="btn btn-default btn-block" style={{'marginBottom': '0.5em'}}>Monkey Telemetry</Link>
|
||||||
|
<button onClick={this.killAllMonkeys} className="btn btn-danger btn-block">
|
||||||
<h4 style={{'marginTop': '2em'}}>Timeline</h4>
|
<Icon name="stop-circle" style={{'marginRight': '0.5em'}}></Icon>
|
||||||
<ul className="timeline">
|
Kill All Monkeys
|
||||||
<li>
|
</button>
|
||||||
<div className="bullet"></div>
|
|
||||||
failed attempt1
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<div className="bullet"></div>
|
|
||||||
failed attempt2
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<div className="bullet bad"></div>
|
|
||||||
Infection!
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</Col>
|
</Col>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,6 +2,7 @@ import React from 'react';
|
||||||
import {Button, Col, Well} from 'react-bootstrap';
|
import {Button, Col, Well} from 'react-bootstrap';
|
||||||
import CopyToClipboard from 'react-copy-to-clipboard';
|
import CopyToClipboard from 'react-copy-to-clipboard';
|
||||||
import {Icon} from 'react-fa';
|
import {Icon} from 'react-fa';
|
||||||
|
import {Link} from "react-router-dom";
|
||||||
|
|
||||||
class RunMonkeyPageComponent extends React.Component {
|
class RunMonkeyPageComponent extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
@ -9,7 +10,8 @@ class RunMonkeyPageComponent extends React.Component {
|
||||||
this.state = {
|
this.state = {
|
||||||
ips: [],
|
ips: [],
|
||||||
selectedIp: '0.0.0.0',
|
selectedIp: '0.0.0.0',
|
||||||
isRunning: true
|
isRunningOnIsland: false,
|
||||||
|
isRunningLocally: false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,14 +19,13 @@ class RunMonkeyPageComponent extends React.Component {
|
||||||
fetch('/api')
|
fetch('/api')
|
||||||
.then(res => res.json())
|
.then(res => res.json())
|
||||||
.then(res => this.setState({
|
.then(res => this.setState({
|
||||||
ips: res['ip_addresses'],
|
ips: res['ip_addresses']
|
||||||
selectedIp: res['ip_addresses'][0]
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
fetch('/api/local-monkey')
|
fetch('/api/local-monkey')
|
||||||
.then(res => res.json())
|
.then(res => res.json())
|
||||||
.then(res => this.setState({
|
.then(res => this.setState({
|
||||||
isRunning: res['is_running']
|
isRunningOnIsland: res['is_running']
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,50 +38,64 @@ class RunMonkeyPageComponent extends React.Component {
|
||||||
{
|
{
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
body: JSON.stringify({action: 'run', ip: this.state.selectedIp})
|
body: JSON.stringify({action: 'run'})
|
||||||
})
|
})
|
||||||
.then(res => res.json())
|
.then(res => res.json())
|
||||||
.then(res => {
|
.then(res => {
|
||||||
this.setState({
|
this.setState({
|
||||||
isRunning: res['is_running']
|
isRunningOnIsland: res['is_running']
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
setSelectedIp = (event) => {
|
|
||||||
this.setState({selectedIp: event.target.value});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<Col xs={8}>
|
<Col xs={8}>
|
||||||
<h1 className="page-title">Run the Monkey</h1>
|
<h1 className="page-title">Run the Monkey</h1>
|
||||||
<p>
|
<p style={{'fontSize': '1.2em', 'marginBottom': '2em'}}>
|
||||||
Select one of the server's IP addresses:
|
You can run the monkey on the C&C server, on your local machine and basically everywhere.
|
||||||
<select value={this.state.selectedIp} onChange={this.setSelectedIp}
|
The more the merrier 😄
|
||||||
className="form-control inline-select">
|
|
||||||
{this.state.ips.map(ip =>
|
|
||||||
<option value={ip}>{ip}</option>
|
|
||||||
)}
|
|
||||||
</select>
|
|
||||||
<br/>That address will be used as the monkey's C&C address.
|
|
||||||
</p>
|
</p>
|
||||||
<p>Run this snippet on a host for manually infecting it with a Monkey:</p>
|
<p style={{'marginBottom': '2em'}}>
|
||||||
<Well>
|
<button onClick={this.runLocalMonkey}
|
||||||
<CopyToClipboard text={this.generateCmd(this.state.selectedIp)} className="pull-right">
|
className="btn btn-default"
|
||||||
<Button style={{margin: '-0.5em'}} title="Copy to Clipboard">
|
disabled={this.state.isRunningOnIsland}>
|
||||||
<Icon name="clipboard"/>
|
Run on C&C Server
|
||||||
</Button>
|
{ !this.state.isRunningOnIsland ?
|
||||||
</CopyToClipboard>
|
<Icon name="check" className="text-success" style={{'marginLeft': '5px'}}/>
|
||||||
<code>{this.generateCmd(this.state.selectedIp)}</code>
|
: ''}
|
||||||
</Well>
|
</button>
|
||||||
<p>
|
<a href="/download-monkey"
|
||||||
Or simply click here to <a onClick={this.runLocalMonkey}
|
className="btn btn-default"
|
||||||
className="btn btn-default btn-sm"
|
disabled={this.state.isRunningLocally}
|
||||||
style={{'marginLeft': '0.2em'}}>Run on <b>{this.state.selectedIp}</b></a>
|
style={{'margin-left': '1em'}}>
|
||||||
{ this.state.isRunning ?
|
Download and run locally
|
||||||
<i className="text-success" style={{'marginLeft': '5px'}}>Running...</i>
|
{ !this.state.isRunningLocally ?
|
||||||
: ''}
|
<Icon name="check" className="text-success" style={{'marginLeft': '5px'}}/>
|
||||||
|
: ''}
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
<div className="run-monkey-snippets" style={{'marginBottom': '3em'}}>
|
||||||
|
<p>
|
||||||
|
Run one of those snippets on a host for infecting it with a Monkey:
|
||||||
|
<br/>
|
||||||
|
<span className="text-muted">(The IP address is used as the monkey's C&C address)</span>
|
||||||
|
</p>
|
||||||
|
<Well className="well-sm">
|
||||||
|
{this.state.ips.map(ip =>
|
||||||
|
<div style={{'overflow': 'auto', 'padding': '0.5em'}}>
|
||||||
|
<CopyToClipboard text={this.generateCmd(ip)} className="pull-right btn-sm">
|
||||||
|
<Button style={{margin: '-0.5em'}} title="Copy to Clipboard">
|
||||||
|
<Icon name="clipboard"/>
|
||||||
|
</Button>
|
||||||
|
</CopyToClipboard>
|
||||||
|
<code>{this.generateCmd(ip)}</code>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Well>
|
||||||
|
</div>
|
||||||
|
<p style={{'fontSize': '1.2em'}}>
|
||||||
|
Go ahead and monitor the ongoing infection in the <Link to="/infection/map">Infection Map</Link> view.
|
||||||
</p>
|
</p>
|
||||||
</Col>
|
</Col>
|
||||||
);
|
);
|
||||||
|
|
|
@ -21,7 +21,10 @@ class RunServerPageComponent extends React.Component {
|
||||||
<div style={{'fontSize': '1.5em'}}>
|
<div style={{'fontSize': '1.5em'}}>
|
||||||
<p>Your Monkey Island server is up and running on <b>{this.state.ip}</b> 👏 👏</p>
|
<p>Your Monkey Island server is up and running on <b>{this.state.ip}</b> 👏 👏</p>
|
||||||
<p>
|
<p>
|
||||||
Now <Link to="/configure">configure the monkey</Link> (or just stick with the default configuration) and <Link to="/run-monkey">run the monkey</Link>.
|
Go ahead and <Link to="/run-monkey">run the monkey</Link>.
|
||||||
|
</p>
|
||||||
|
<p style={{'marginTop': '30px'}}>
|
||||||
|
<i>(You can make further adjustments by <Link to="/configure">configuring the monkey</Link>)</i>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</Col>
|
</Col>
|
||||||
|
|
|
@ -0,0 +1,100 @@
|
||||||
|
import React from 'react';
|
||||||
|
import {Icon} from "react-fa";
|
||||||
|
|
||||||
|
class PreviewPaneComponent extends React.Component {
|
||||||
|
assetInfo(asset) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<table className="table table-condensed">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<th>Operating System</th>
|
||||||
|
<td>{asset.os}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>IP Addresses</th>
|
||||||
|
<td>{asset.ip_addresses.map(val => <div key={val}>{val}</div>)}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Services</th>
|
||||||
|
<td>{asset.services.map(val => <div key={val}>{val}</div>)}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Accessible From</th>
|
||||||
|
<td>{asset.accessible_from_nodes.map(val => <div key={val.id}>{val.id}</div>)}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
infectedAssetInfo(asset) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{this.assetInfo(asset)}
|
||||||
|
|
||||||
|
<h4 style={{'marginTop': '2em'}}>Timeline</h4>
|
||||||
|
<ul className="timeline">
|
||||||
|
{ asset.exploits.map(exploit =>
|
||||||
|
<li key={exploit.start_timestamp}>
|
||||||
|
<div className={'bullet ' + (exploit.result ? 'bad' : '')}></div>
|
||||||
|
<div>{exploit.start_timestamp}</div>
|
||||||
|
<div>{exploit.origin}</div>
|
||||||
|
<div>{exploit.exploiter}</div>
|
||||||
|
</li>
|
||||||
|
)}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
infectionInfo(edge) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
scanInfo(edge) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let info = null;
|
||||||
|
switch (this.props.type) {
|
||||||
|
case 'edge':
|
||||||
|
info = this.props.item.exploits.length ?
|
||||||
|
this.infectionInfo(this.props.item) : this.scanInfo(this.props.item);
|
||||||
|
case 'node':
|
||||||
|
info = this.props.item.exploits.some(exploit => exploit.result) ?
|
||||||
|
this.infectedAssetInfo(this.props.item) : this.assetInfo(this.props.item);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div className="preview-pane">
|
||||||
|
{ !this.props.item ?
|
||||||
|
<span>
|
||||||
|
<Icon name="hand-o-left" style={{'marginRight': '0.5em'}}></Icon>
|
||||||
|
Select an item on the map for a preview
|
||||||
|
</span>
|
||||||
|
:
|
||||||
|
<div>
|
||||||
|
<h3>
|
||||||
|
<b>{this.props.item.label}</b>
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<hr/>
|
||||||
|
{info}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PreviewPaneComponent;
|
Binary file not shown.
After Width: | Height: | Size: 9.6 KiB |
|
@ -91,6 +91,22 @@ body {
|
||||||
|
|
||||||
li .checkmark {
|
li .checkmark {
|
||||||
font-size: 1.3em;
|
font-size: 1.3em;
|
||||||
|
margin-right: -15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
border-top-color: #ccc !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.guardicore-link span {
|
||||||
|
color: #999;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.guardicore-link img {
|
||||||
|
height: 24px;
|
||||||
|
margin-left: 8px;
|
||||||
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,6 +178,10 @@ body {
|
||||||
margin-left: 1em;
|
margin-left: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.run-monkey-snippets .well {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Map Preview Pane
|
* Map Preview Pane
|
||||||
*/
|
*/
|
||||||
|
@ -172,10 +192,16 @@ body {
|
||||||
border-bottom: 3px solid #e8e8e8;
|
border-bottom: 3px solid #e8e8e8;
|
||||||
padding: 1.5em 1em;
|
padding: 1.5em 1em;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
|
margin-bottom: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-pane hr {
|
||||||
|
margin: 10px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.preview-pane h3 {
|
.preview-pane h3 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
font-size: 20px;
|
||||||
|
|
||||||
}
|
}
|
||||||
.preview-pane h3 small {
|
.preview-pane h3 small {
|
||||||
|
@ -191,6 +217,15 @@ body {
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.preview-pane .table tr:first-child th , .preview-pane .table tr:first-child td {
|
||||||
|
border-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-pane .table th {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
.preview-pane p, .preview-pane .timeline {
|
.preview-pane p, .preview-pane .timeline {
|
||||||
margin-left: 1em;
|
margin-left: 1em;
|
||||||
}
|
}
|
||||||
|
@ -220,6 +255,7 @@ body {
|
||||||
|
|
||||||
.timeline .bullet {
|
.timeline .bullet {
|
||||||
width: 16px;
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
background: #ccc;
|
background: #ccc;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 100%;
|
right: 100%;
|
||||||
|
@ -247,8 +283,16 @@ body {
|
||||||
padding: 15px 8px;
|
padding: 15px 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#search-field , #page-menu {
|
.data-table-container > .container > .row:first-child > div:first-child > div {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-table-container > .container > .row:first-child > div:first-child > div:last-child {
|
||||||
margin-left: 1em;
|
margin-left: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#search-field , #page-menu {
|
||||||
|
margin-left: 0.5em;
|
||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
height: 34px;
|
height: 34px;
|
||||||
padding: 6px 12px;
|
padding: 6px 12px;
|
||||||
|
@ -265,3 +309,11 @@ body {
|
||||||
-o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
|
-o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
|
||||||
transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
|
transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#search-field {
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-table-container .pagination {
|
||||||
|
margin: 0 !important;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue