Aggregated 3 reports into one with tabs

This commit is contained in:
VakarisZ 2019-11-21 18:22:40 +02:00
parent 2811bb29d5
commit 0f44bc6075
9 changed files with 1139 additions and 1165 deletions

View File

@ -25,7 +25,7 @@ class AttackConfiguration(flask_restful.Resource):
config_json = json.loads(request.data)
if 'reset_attack_matrix' in config_json:
AttackConfig.reset_config()
return jsonify(configuration=AttackConfig.get_config()['properties'])
return jsonify(configuration=AttackConfig.get_config())
else:
AttackConfig.update_config({'properties': json.loads(request.data)})
AttackConfig.apply_to_monkey_config()

View File

@ -26,7 +26,7 @@ class AttackConfig(object):
:return: Technique object or None if technique is not found
"""
attack_config = AttackConfig.get_config()
for key, attack_type in list(attack_config['properties'].items()):
for key, attack_type in list(attack_config.items()):
for key, technique in list(attack_type['properties'].items()):
if key == technique_id:
return technique
@ -169,7 +169,7 @@ class AttackConfig(object):
"""
attack_config = AttackConfig.get_config()
techniques = {}
for type_name, attack_type in list(attack_config['properties'].items()):
for type_name, attack_type in list(attack_config.items()):
for key, technique in list(attack_type['properties'].items()):
techniques[key] = technique['value']
return techniques

View File

@ -10,7 +10,7 @@ import MapPage from 'components/pages/MapPage';
import TelemetryPage from 'components/pages/TelemetryPage';
import StartOverPage from 'components/pages/StartOverPage';
import ReportPage from 'components/pages/ReportPage';
import ZeroTrustReportPage from 'components/pages/ZeroTrustReportPage';
import ZeroTrustReportPage from 'components/report-components/ZeroTrustReport';
import LicensePage from 'components/pages/LicensePage';
import AuthComponent from 'components/AuthComponent';
import LoginPageComponent from 'components/pages/LoginPage';
@ -152,16 +152,7 @@ class AppComponent extends AuthComponent {
<li>
<NavLink to="/report/security">
<span className="number">4.</span>
Security Report
{this.state.completedSteps.report_done ?
<Icon name="check" className="pull-right checkmark text-success"/>
: ''}
</NavLink>
</li>
<li>
<NavLink to="/report/zero_trust">
<span className="number">5.</span>
Zero Trust Report
Security Reports
{this.state.completedSteps.report_done ?
<Icon name="check" className="pull-right checkmark text-success"/>
: ''}
@ -201,7 +192,7 @@ class AppComponent extends AuthComponent {
{this.renderRoute('/infection/map', <MapPage onStatusChange={this.updateStatus}/>)}
{this.renderRoute('/infection/telemetry', <TelemetryPage onStatusChange={this.updateStatus}/>)}
{this.renderRoute('/start-over', <StartOverPage onStatusChange={this.updateStatus}/>)}
{this.renderRoute('/report/security', <ReportPage onStatusChange={this.updateStatus}/>)}
{this.renderRoute('/report/security', <ReportPage/>)}
{this.renderRoute(reportZeroTrustRoute, <ZeroTrustReportPage onStatusChange={this.updateStatus}/>)}
{this.renderRoute('/license', <LicensePage onStatusChange={this.updateStatus}/>)}
</Col>

File diff suppressed because it is too large Load Diff

View File

@ -1,133 +0,0 @@
import React, {Fragment} from 'react';
import {Col} from 'react-bootstrap';
import AuthComponent from '../AuthComponent';
import ReportHeader, {ReportTypes} from '../report-components/common/ReportHeader';
import ReportLoader from '../report-components/common/ReportLoader';
import MustRunMonkeyWarning from '../report-components/common/MustRunMonkeyWarning';
import PrintReportButton from '../report-components/common/PrintReportButton';
import {extractExecutionStatusFromServerResponse} from '../report-components/common/ExecutionStatus';
import SummarySection from '../report-components/zerotrust/SummarySection';
import FindingsSection from '../report-components/zerotrust/FindingsSection';
import PrinciplesSection from '../report-components/zerotrust/PrinciplesSection';
class ZeroTrustReportPageComponent extends AuthComponent {
constructor(props) {
super(props);
this.state = {
allMonkeysAreDead: false,
runStarted: true
};
}
componentDidMount() {
this.updatePageState();
const refreshInterval = setInterval(this.updatePageState, 8000);
this.setState(
{refreshDataIntervalHandler: refreshInterval}
)
}
componentWillUnmount() {
clearInterval(this.state.refreshDataIntervalHandler);
}
updateMonkeysRunning = () => {
return this.authFetch('/api')
.then(res => res.json())
.then(res => {
this.setState(extractExecutionStatusFromServerResponse(res));
return res;
});
};
updatePageState = () => {
this.updateMonkeysRunning().then(res => this.getZeroTrustReportFromServer(res));
};
render() {
let content;
if (this.state.runStarted) {
content = this.generateReportContent();
} else {
content = <MustRunMonkeyWarning/>;
}
return (
<Col xs={12} lg={10}>
<h1 className="page-title no-print">5. Zero Trust Report</h1>
<div style={{'fontSize': '1.2em'}}>
{content}
</div>
</Col>
);
}
generateReportContent() {
let content;
if (this.stillLoadingDataFromServer()) {
content = <ReportLoader loading={true}/>;
} else {
content = <div id="MainContentSection">
<SummarySection allMonkeysAreDead={this.state.allMonkeysAreDead} pillars={this.state.pillars}/>
<PrinciplesSection principles={this.state.principles}
pillarsToStatuses={this.state.pillars.pillarsToStatuses}/>
<FindingsSection pillarsToStatuses={this.state.pillars.pillarsToStatuses} findings={this.state.findings}/>
</div>;
}
return (
<Fragment>
<div style={{marginBottom: '20px'}}>
<PrintReportButton onClick={() => {
print();
}}/>
</div>
<div className="report-page">
<ReportHeader report_type={ReportTypes.zeroTrust}/>
<hr/>
{content}
</div>
<div style={{marginTop: '20px'}}>
<PrintReportButton onClick={() => {
print();
}}/>
</div>
</Fragment>
)
}
stillLoadingDataFromServer() {
return typeof this.state.findings === 'undefined'
|| typeof this.state.pillars === 'undefined'
|| typeof this.state.principles === 'undefined';
}
getZeroTrustReportFromServer() {
this.authFetch('/api/report/zero_trust/findings')
.then(res => res.json())
.then(res => {
this.setState({
findings: res
});
});
this.authFetch('/api/report/zero_trust/principles')
.then(res => res.json())
.then(res => {
this.setState({
principles: res
});
});
this.authFetch('/api/report/zero_trust/pillars')
.then(res => res.json())
.then(res => {
this.setState({
pillars: res
});
});
}
}
export default ZeroTrustReportPageComponent;

View File

@ -2,36 +2,35 @@ 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 {ScanStatus} from '../../attack/techniques/Helpers';
import '../../styles/Collapse.scss';
import AuthComponent from '../AuthComponent';
import {ScanStatus} from '../attack/techniques/Helpers';
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 T1075 from '../../attack/techniques/T1075';
import T1003 from '../../attack/techniques/T1003';
import T1059 from '../../attack/techniques/T1059';
import T1086 from '../../attack/techniques/T1086';
import T1082 from '../../attack/techniques/T1082';
import T1145 from '../../attack/techniques/T1145';
import T1105 from '../../attack/techniques/T1105';
import T1107 from '../../attack/techniques/T1107';
import T1065 from '../../attack/techniques/T1065';
import T1035 from '../../attack/techniques/T1035';
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';
import T1222 from '../../attack/techniques/T1222';
import T1005 from '../../attack/techniques/T1005';
import T1018 from '../../attack/techniques/T1018';
import T1016 from '../../attack/techniques/T1016';
import T1021 from '../../attack/techniques/T1021';
import T1064 from '../../attack/techniques/T1064';
import {extractExecutionStatusFromServerResponse} from '../common/ExecutionStatus';
import T1210 from '../attack/techniques/T1210';
import T1197 from '../attack/techniques/T1197';
import T1110 from '../attack/techniques/T1110';
import T1075 from '../attack/techniques/T1075';
import T1003 from '../attack/techniques/T1003';
import T1059 from '../attack/techniques/T1059';
import T1086 from '../attack/techniques/T1086';
import T1082 from '../attack/techniques/T1082';
import T1145 from '../attack/techniques/T1145';
import T1105 from '../attack/techniques/T1105';
import T1107 from '../attack/techniques/T1107';
import T1065 from '../attack/techniques/T1065';
import T1035 from '../attack/techniques/T1035';
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';
import T1222 from '../attack/techniques/T1222';
import T1005 from '../attack/techniques/T1005';
import T1018 from '../attack/techniques/T1018';
import T1016 from '../attack/techniques/T1016';
import T1021 from '../attack/techniques/T1021';
import T1064 from '../attack/techniques/T1064';
const tech_components = {
'T1210': T1210,
@ -67,35 +66,14 @@ class AttackReportPageComponent extends AuthComponent {
constructor(props) {
super(props);
this.state = {
report: false,
allMonkeysAreDead: false,
runStarted: true,
report: this.props.report,
collapseOpen: ''
};
}
componentDidMount() {
this.updateMonkeysRunning().then(res => this.getReportFromServer(res));
}
updateMonkeysRunning = () => {
return this.authFetch('/api')
.then(res => res.json())
.then(res => {
this.setState(extractExecutionStatusFromServerResponse(res));
return res;
});
};
getReportFromServer(res) {
if (res['completed_steps']['run_monkey']) {
this.authFetch('/api/attack/report')
.then(res => res.json())
.then(res => {
this.setState({
report: res
});
});
componentDidUpdate(prevProps) {
if (this.props.report !== prevProps.report) {
this.setState({ report: this.props.report })
}
}
@ -168,31 +146,28 @@ class AttackReportPageComponent extends AuthComponent {
content.push(this.getTechniqueCollapse(tech_id))
});
return (
<div id="attack">
<h3>
ATT&CK report
</h3>
<p>
This report shows information about ATT&CK techniques used by Infection Monkey.
</p>
<div>
{this.renderLegend()}
<section className="attack-report">{content}</section>
</div>
<br/>
</div>
)
}
render() {
let content;
if (!this.state.runStarted) {
content =
<p className="alert alert-warning">
<i className="glyphicon glyphicon-warning-sign" style={{'marginRight': '5px'}}/>
You have to run a monkey before generating a report!
</p>;
} else if (this.state.report === false) {
content = (<h1>Generating Report...</h1>);
} else if (Object.keys(this.state.report).length === 0) {
if (this.state.runStarted) {
content = (<h1>No techniques were scanned</h1>);
}
if (Object.keys(this.state.report).length === 0 && this.state.runStarted) {
return (<h1>No techniques were scanned</h1>);
} else {
content = this.generateReportContent();
return (<div> {this.generateReportContent()}</div>);
}
return (<div> {content} </div>);
}
}

View File

@ -0,0 +1,932 @@
import React, {Fragment} from 'react';
import BreachedServers from 'components/report-components/security/BreachedServers';
import ScannedServers from 'components/report-components/security/ScannedServers';
import PostBreach from 'components/report-components/security/PostBreach';
import {ReactiveGraph} from 'components/reactive-graph/ReactiveGraph';
import {edgeGroupToColor, options} from 'components/map/MapOptions';
import StolenPasswords from 'components/report-components/security/StolenPasswords';
import CollapsibleWellComponent from 'components/report-components/security/CollapsibleWell';
import {Line} from 'rc-progress';
import AuthComponent from '../AuthComponent';
import PassTheHashMapPageComponent from '../pages/PassTheHashMapPage';
import StrongUsers from 'components/report-components/security/StrongUsers';
import ReportHeader, {ReportTypes} from './common/ReportHeader';
import ReportLoader from './common/ReportLoader';
import SecurityIssuesGlance from './common/SecurityIssuesGlance';
import PrintReportButton from './common/PrintReportButton';
let guardicoreLogoImage = require('../../images/guardicore-logo.png');
class ReportPageComponent extends AuthComponent {
Issue =
{
WEAK_PASSWORD: 0,
STOLEN_CREDS: 1,
ELASTIC: 2,
SAMBACRY: 3,
SHELLSHOCK: 4,
CONFICKER: 5,
AZURE: 6,
STOLEN_SSH_KEYS: 7,
STRUTS2: 8,
WEBLOGIC: 9,
HADOOP: 10,
PTH_CRIT_SERVICES_ACCESS: 11,
MSSQL: 12,
VSFTPD: 13
};
Warning =
{
CROSS_SEGMENT: 0,
TUNNEL: 1,
SHARED_LOCAL_ADMIN: 2,
SHARED_PASSWORDS: 3,
SHARED_PASSWORDS_DOMAIN: 4
};
constructor(props) {
super(props);
this.state = {
report: props.report,
graph: {nodes: [], edges: []}
};
}
componentDidMount() {
this.updateMapFromServer();
}
componentWillUnmount() {
clearInterval(this.interval);
}
componentDidUpdate(prevProps) {
if (this.props.report !== prevProps.report) {
this.setState({ report: this.props.report })
}
}
render() {
let content;
if (this.stillLoadingDataFromServer()) {
content = <ReportLoader loading={true}/>;
} else {
content =
<div>
{this.generateReportOverviewSection()}
{this.generateReportFindingsSection()}
{this.generateReportRecommendationsSection()}
{this.generateReportGlanceSection()}
{this.generateReportFooter()}
</div>;
}
return (
<Fragment>
<div style={{marginBottom: '20px'}}>
<PrintReportButton onClick={() => {
print();
}}/>
</div>
<div className="report-page">
<ReportHeader report_type={ReportTypes.security}/>
<hr/>
{content}
</div>
<div style={{marginTop: '20px'}}>
<PrintReportButton onClick={() => {
print();
}}/>
</div>
</Fragment>
);
}
stillLoadingDataFromServer() {
return Object.keys(this.state.report).length === 0;
}
updateMapFromServer = () => {
this.authFetch('/api/netmap')
.then(res => res.json())
.then(res => {
res.edges.forEach(edge => {
edge.color = {'color': edgeGroupToColor(edge.group)};
});
this.setState({graph: res});
});
};
generateReportOverviewSection() {
return (
<div id="overview">
<h2>
Overview
</h2>
<SecurityIssuesGlance issuesFound={this.state.report.glance.exploited.length > 0}/>
{
this.state.report.glance.exploited.length > 0 ?
''
:
<p className="alert alert-info">
<i className="glyphicon glyphicon-info-sign" style={{'marginRight': '5px'}}/>
To improve the monkey's detection rates, try adding users and passwords and enable the "Local
network
scan" config value under <b>Basic - Network</b>.
</p>
}
<p>
The first monkey run was started on <span
className="label label-info">{this.state.report.overview.monkey_start_time}</span>. After <span
className="label label-info">{this.state.report.overview.monkey_duration}</span>, all monkeys finished
propagation attempts.
</p>
<p>
The monkey started propagating from the following machines where it was manually installed:
<ul>
{this.state.report.overview.manual_monkeys.map(x => <li>{x}</li>)}
</ul>
</p>
<p>
The monkeys were run with the following configuration:
</p>
{
this.state.report.overview.config_users.length > 0 ?
<p>
Usernames used for brute-forcing:
<ul>
{this.state.report.overview.config_users.map(x => <li>{x}</li>)}
</ul>
Passwords used for brute-forcing:
<ul>
{this.state.report.overview.config_passwords.map(x => <li>{x.substr(0, 3) + '******'}</li>)}
</ul>
</p>
:
<p>
Brute forcing uses stolen credentials only. No credentials were supplied during Monkeys
configuration.
</p>
}
{
this.state.report.overview.config_exploits.length > 0 ?
(
this.state.report.overview.config_exploits[0] === 'default' ?
''
:
<p>
The Monkey uses the following exploit methods:
<ul>
{this.state.report.overview.config_exploits.map(x => <li>{x}</li>)}
</ul>
</p>
)
:
<p>
No exploits are used by the Monkey.
</p>
}
{
this.state.report.overview.config_ips.length > 0 ?
<p>
The Monkey scans the following IPs:
<ul>
{this.state.report.overview.config_ips.map(x => <li>{x}</li>)}
</ul>
</p>
:
''
}
{
this.state.report.overview.config_scan ?
''
:
<p>
Note: Monkeys were configured to avoid scanning of the local network.
</p>
}
</div>
);
}
generateReportFindingsSection() {
return (
<div id="findings">
<h3>
Security Findings
</h3>
<div>
<h3>
Immediate Threats
</h3>
{
this.state.report.overview.issues.filter(function (x) {
return x === true;
}).length > 0 ?
<div>
During this simulated attack the Monkey uncovered <span
className="label label-warning">
{this.state.report.overview.issues.filter(function (x) {
return x === true;
}).length} threats</span>:
<ul>
{this.state.report.overview.issues[this.Issue.STOLEN_SSH_KEYS] ?
<li>Stolen SSH keys are used to exploit other machines.</li> : null}
{this.state.report.overview.issues[this.Issue.STOLEN_CREDS] ?
<li>Stolen credentials are used to exploit other machines.</li> : null}
{this.state.report.overview.issues[this.Issue.ELASTIC] ?
<li>Elasticsearch servers are vulnerable to <a
href="https://www.cvedetails.com/cve/cve-2015-1427">CVE-2015-1427</a>.
</li> : null}
{this.state.report.overview.issues[this.Issue.VSFTPD] ?
<li>VSFTPD is vulnerable to <a
href="https://www.rapid7.com/db/modules/exploit/unix/ftp/vsftpd_234_backdoor">CVE-2011-2523</a>.
</li> : null}
{this.state.report.overview.issues[this.Issue.SAMBACRY] ?
<li>Samba servers are vulnerable to SambaCry (<a
href="https://www.samba.org/samba/security/CVE-2017-7494.html"
>CVE-2017-7494</a>).</li> : null}
{this.state.report.overview.issues[this.Issue.SHELLSHOCK] ?
<li>Machines are vulnerable to Shellshock (<a
href="https://www.cvedetails.com/cve/CVE-2014-6271">CVE-2014-6271</a>).
</li> : null}
{this.state.report.overview.issues[this.Issue.CONFICKER] ?
<li>Machines are vulnerable to Conficker (<a
href="https://docs.microsoft.com/en-us/security-updates/SecurityBulletins/2008/ms08-067"
>MS08-067</a>).</li> : null}
{this.state.report.overview.issues[this.Issue.WEAK_PASSWORD] ?
<li>Machines are accessible using passwords supplied by the user during the Monkeys
configuration.</li> : null}
{this.state.report.overview.issues[this.Issue.AZURE] ?
<li>Azure machines expose plaintext passwords. (<a
href="https://www.guardicore.com/2018/03/recovering-plaintext-passwords-azure/"
>More info</a>)</li> : null}
{this.state.report.overview.issues[this.Issue.STRUTS2] ?
<li>Struts2 servers are vulnerable to remote code execution. (<a
href="https://cwiki.apache.org/confluence/display/WW/S2-045">
CVE-2017-5638</a>)</li> : null}
{this.state.report.overview.issues[this.Issue.WEBLOGIC] ?
<li>Oracle WebLogic servers are susceptible to a remote code execution vulnerability.</li> : null}
{this.state.report.overview.issues[this.Issue.HADOOP] ?
<li>Hadoop/Yarn servers are vulnerable to remote code execution.</li> : null}
{this.state.report.overview.issues[this.Issue.PTH_CRIT_SERVICES_ACCESS] ?
<li>Mimikatz found login credentials of a user who has admin access to a server defined as
critical.</li> : null}
{this.state.report.overview.issues[this.Issue.MSSQL] ?
<li>MS-SQL servers are vulnerable to remote code execution via xp_cmdshell command.</li> : null}
</ul>
</div>
:
<div>
During this simulated attack the Monkey uncovered <span
className="label label-success">0 threats</span>.
</div>
}
</div>
<div>
<h3>
Potential Security Issues
</h3>
{
this.state.report.overview.warnings.filter(function (x) {
return x === true;
}).length > 0 ?
<div>
The Monkey uncovered the following possible set of issues:
<ul>
{this.state.report.overview.warnings[this.Warning.CROSS_SEGMENT] ?
<li>Weak segmentation - Machines from different segments are able to
communicate.</li> : null}
{this.state.report.overview.warnings[this.Warning.TUNNEL] ?
<li>Weak segmentation - Machines were able to communicate over unused ports.</li> : null}
{this.state.report.overview.warnings[this.Warning.SHARED_LOCAL_ADMIN] ?
<li>Shared local administrator account - Different machines have the same account as a local
administrator.</li> : null}
{this.state.report.overview.warnings[this.Warning.SHARED_PASSWORDS] ?
<li>Multiple users have the same password</li> : null}
</ul>
</div>
:
<div>
The Monkey did not find any issues.
</div>
}
</div>
{this.state.report.overview.cross_segment_issues.length > 0 ?
<div>
<h3>
Segmentation Issues
</h3>
<div>
The Monkey uncovered the following set of segmentation issues:
<ul>
{this.state.report.overview.cross_segment_issues.map(x => this.generateCrossSegmentIssue(x))}
</ul>
</div>
</div>
:
''
}
</div>
);
}
generateReportRecommendationsSection() {
return (
<div id="recommendations">
{/* Checks if there are any domain issues. If there are more then one: render the title. Otherwise,
* don't render it (since the issues themselves will be empty. */}
{Object.keys(this.state.report.recommendations.domain_issues).length !== 0 ?
<h3>Domain related recommendations</h3> : null}
<div>
{this.generateIssues(this.state.report.recommendations.domain_issues)}
</div>
{/* Checks if there are any issues. If there are more then one: render the title. Otherwise,
* don't render it (since the issues themselves will be empty. */}
{Object.keys(this.state.report.recommendations.issues).length !== 0 ?
<h3>Machine related recommendations</h3> : null}
<div>
{this.generateIssues(this.state.report.recommendations.issues)}
</div>
</div>
);
}
generateReportGlanceSection() {
let exploitPercentage =
(100 * this.state.report.glance.exploited.length) / this.state.report.glance.scanned.length;
return (
<div id="glance">
<h3>
The Network from the Monkey's Eyes
</h3>
<div>
<p>
The Monkey discovered <span
className="label label-warning">{this.state.report.glance.scanned.length}</span> machines and
successfully breached <span
className="label label-danger">{this.state.report.glance.exploited.length}</span> of them.
</p>
<div className="text-center" style={{margin: '10px'}}>
<Line style={{width: '300px', marginRight: '5px'}} percent={exploitPercentage} strokeWidth="4"
trailWidth="4"
strokeColor="#d9534f" trailColor="#f0ad4e"/>
<b>{Math.round(exploitPercentage)}% of scanned machines exploited</b>
</div>
</div>
<p>
From the attacker's point of view, the network looks like this:
</p>
<div className="map-legend">
<b>Legend: </b>
<span>Exploit <i className="fa fa-lg fa-minus" style={{color: '#cc0200'}}/></span>
<b style={{color: '#aeaeae'}}> | </b>
<span>Scan <i className="fa fa-lg fa-minus" style={{color: '#ff9900'}}/></span>
<b style={{color: '#aeaeae'}}> | </b>
<span>Tunnel <i className="fa fa-lg fa-minus" style={{color: '#0158aa'}}/></span>
<b style={{color: '#aeaeae'}}> | </b>
<span>Island Communication <i className="fa fa-lg fa-minus" style={{color: '#a9aaa9'}}/></span>
</div>
<div style={{position: 'relative', height: '80vh'}}>
<ReactiveGraph graph={this.state.graph} options={options}/>
</div>
<div style={{marginBottom: '20px'}}>
<BreachedServers data={this.state.report.glance.exploited}/>
</div>
<div style={{marginBottom: '20px'}}>
<PostBreach data={this.state.report.glance.scanned}/>
</div>
<div style={{marginBottom: '20px'}}>
<ScannedServers data={this.state.report.glance.scanned}/>
</div>
<div style={{position: 'relative', height: '80vh'}}>
{this.generateReportPthMap()}
</div>
<div style={{marginBottom: '20px'}}>
<StolenPasswords data={this.state.report.glance.stolen_creds.concat(this.state.report.glance.ssh_keys)}/>
</div>
<div>
<StrongUsers data={this.state.report.glance.strong_users}/>
</div>
</div>
);
}
generateReportPthMap() {
return (
<div id="pth">
<h3>
Credentials Map
</h3>
<p>
This map visualizes possible attack paths through the network using credential compromise. Paths represent lateral
movement opportunities by attackers.
</p>
<div className="map-legend">
<b>Legend: </b>
<span>Access credentials <i className="fa fa-lg fa-minus" style={{color: '#0158aa'}}/></span> <b
style={{color: '#aeaeae'}}> | </b>
</div>
<div>
<PassTheHashMapPageComponent graph={this.state.report.glance.pth_map}/>
</div>
<br/>
</div>
);
}
generateReportFooter() {
return (
<div id="footer" className="text-center" style={{marginTop: '20px'}}>
For questions, suggestions or any other feedback
contact: <a href="mailto://labs@guardicore.com" className="no-print">labs@guardicore.com</a>
<div className="force-print" style={{display: 'none'}}>labs@guardicore.com</div>
<img src={guardicoreLogoImage} alt="GuardiCore" className="center-block" style={{height: '50px'}}/>
</div>
);
}
generateInfoBadges(data_array) {
return data_array.map(badge_data => <span className="label label-info" style={{margin: '2px'}}>{badge_data}</span>);
}
generateCrossSegmentIssue(crossSegmentIssue) {
return <li>
{'Communication possible from ' + crossSegmentIssue['source_subnet'] + ' to ' + crossSegmentIssue['target_subnet']}
<CollapsibleWellComponent>
<ul>
{crossSegmentIssue['issues'].map(x =>
x['is_self'] ?
<li>
{'Machine ' + x['hostname'] + ' has both ips: ' + x['source'] + ' and ' + x['target']}
</li>
:
<li>
{'IP ' + x['source'] + ' (' + x['hostname'] + ') connected to IP ' + x['target']
+ ' using the services: ' + Object.keys(x['services']).join(', ')}
</li>
)}
</ul>
</CollapsibleWellComponent>
</li>;
}
generateShellshockPathListBadges(paths) {
return paths.map(path => <span className="label label-warning" style={{margin: '2px'}}>{path}</span>);
}
generateSmbPasswordIssue(issue) {
return (
<li>
Change <span className="label label-success">{issue.username}</span>'s password to a complex one-use password
that is not shared with other computers on the network.
<CollapsibleWellComponent>
The machine <span className="label label-primary">{issue.machine}</span> (<span
className="label label-info" style={{margin: '2px'}}>{issue.ip_address}</span>) is vulnerable to a <span
className="label label-danger">SMB</span> attack.
<br/>
The Monkey authenticated over the SMB protocol with user <span
className="label label-success">{issue.username}</span> and its password.
</CollapsibleWellComponent>
</li>
);
}
generateSmbPthIssue(issue) {
return (
<li>
Change <span className="label label-success">{issue.username}</span>'s password to a complex one-use password
that is not shared with other computers on the network.
<CollapsibleWellComponent>
The machine <span className="label label-primary">{issue.machine}</span> (<span
className="label label-info" style={{margin: '2px'}}>{issue.ip_address}</span>) is vulnerable to a <span
className="label label-danger">SMB</span> attack.
<br/>
The Monkey used a pass-the-hash attack over SMB protocol with user <span
className="label label-success">{issue.username}</span>.
</CollapsibleWellComponent>
</li>
);
}
generateWmiPasswordIssue(issue) {
return (
<li>
Change <span className="label label-success">{issue.username}</span>'s password to a complex one-use password
that is not shared with other computers on the network.
<CollapsibleWellComponent>
The machine <span className="label label-primary">{issue.machine}</span> (<span
className="label label-info" style={{margin: '2px'}}>{issue.ip_address}</span>) is vulnerable to a <span
className="label label-danger">WMI</span> attack.
<br/>
The Monkey authenticated over the WMI protocol with user <span
className="label label-success">{issue.username}</span> and its password.
</CollapsibleWellComponent>
</li>
);
}
generateWmiPthIssue(issue) {
return (
<li>
Change <span className="label label-success">{issue.username}</span>'s password to a complex one-use password
that is not shared with other computers on the network.
<CollapsibleWellComponent>
The machine <span className="label label-primary">{issue.machine}</span> (<span
className="label label-info" style={{margin: '2px'}}>{issue.ip_address}</span>) is vulnerable to a <span
className="label label-danger">WMI</span> attack.
<br/>
The Monkey used a pass-the-hash attack over WMI protocol with user <span
className="label label-success">{issue.username}</span>.
</CollapsibleWellComponent>
</li>
);
}
generateSshIssue(issue) {
return (
<li>
Change <span className="label label-success">{issue.username}</span>'s password to a complex one-use password
that is not shared with other computers on the network.
<CollapsibleWellComponent>
The machine <span className="label label-primary">{issue.machine}</span> (<span
className="label label-info" style={{margin: '2px'}}>{issue.ip_address}</span>) is vulnerable to a <span
className="label label-danger">SSH</span> attack.
<br/>
The Monkey authenticated over the SSH protocol with user <span
className="label label-success">{issue.username}</span> and its password.
</CollapsibleWellComponent>
</li>
);
}
generateSshKeysIssue(issue) {
return (
<li>
Protect <span className="label label-success">{issue.ssh_key}</span> private key with a pass phrase.
<CollapsibleWellComponent>
The machine <span className="label label-primary">{issue.machine}</span> (<span
className="label label-info" style={{margin: '2px'}}>{issue.ip_address}</span>) is vulnerable to a <span
className="label label-danger">SSH</span> attack.
<br/>
The Monkey authenticated over the SSH protocol with private key <span
className="label label-success">{issue.ssh_key}</span>.
</CollapsibleWellComponent>
</li>
);
}
generateSambaCryIssue(issue) {
return (
<li>
Change <span className="label label-success">{issue.username}</span>'s password to a complex one-use password
that is not shared with other computers on the network.
<br/>
Update your Samba server to 4.4.14 and up, 4.5.10 and up, or 4.6.4 and up.
<CollapsibleWellComponent>
The machine <span className="label label-primary">{issue.machine}</span> (<span
className="label label-info" style={{margin: '2px'}}>{issue.ip_address}</span>) is vulnerable to a <span
className="label label-danger">SambaCry</span> attack.
<br/>
The Monkey authenticated over the SMB protocol with user <span
className="label label-success">{issue.username}</span> and its password, and used the SambaCry
vulnerability.
</CollapsibleWellComponent>
</li>
);
}
generateVsftpdBackdoorIssue(issue) {
return (
<li>
Update your VSFTPD server to the latest version vsftpd-3.0.3.
<CollapsibleWellComponent>
The machine <span className="label label-primary">{issue.machine}</span> (<span
className="label label-info" style={{margin: '2px'}}>{issue.ip_address}</span>) has a backdoor running at port <span
className="label label-danger">6200</span>.
<br/>
The attack was made possible because the VSFTPD server was not patched against CVE-2011-2523.
<br/><br/>In July 2011, it was discovered that vsftpd version 2.3.4 downloadable from the master site had been
compromised.
Users logging into a compromised vsftpd-2.3.4 server may issue a ":)" smileyface as the username and gain a command
shell on port 6200.
<br/><br/>
The Monkey executed commands by first logging in with ":)" in the username and then sending commands to the backdoor
at port 6200.
<br/><br/>Read more about the security issue and remediation <a
href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2011-2523"
>here</a>.
</CollapsibleWellComponent>
</li>
);
}
generateElasticIssue(issue) {
return (
<li>
Update your Elastic Search server to version 1.4.3 and up.
<CollapsibleWellComponent>
The machine <span className="label label-primary">{issue.machine}</span> (<span
className="label label-info" style={{margin: '2px'}}>{issue.ip_address}</span>) is vulnerable to an <span
className="label label-danger">Elastic Groovy</span> attack.
<br/>
The attack was made possible because the Elastic Search server was not patched against CVE-2015-1427.
</CollapsibleWellComponent>
</li>
);
}
generateShellshockIssue(issue) {
return (
<li>
Update your Bash to a ShellShock-patched version.
<CollapsibleWellComponent>
The machine <span className="label label-primary">{issue.machine}</span> (<span
className="label label-info" style={{margin: '2px'}}>{issue.ip_address}</span>) is vulnerable to a <span
className="label label-danger">ShellShock</span> attack.
<br/>
The attack was made possible because the HTTP server running on TCP port <span
className="label label-info">{issue.port}</span> was vulnerable to a shell injection attack on the
paths: {this.generateShellshockPathListBadges(issue.paths)}.
</CollapsibleWellComponent>
</li>
);
}
generateAzureIssue(issue) {
return (
<li>
Delete VM Access plugin configuration files.
<CollapsibleWellComponent>
Credentials could be stolen from <span
className="label label-primary">{issue.machine}</span> for the following users <span
className="label label-primary">{issue.users}</span>. Read more about the security issue and remediation <a
href="https://www.guardicore.com/2018/03/recovering-plaintext-passwords-azure/"
>here</a>.
</CollapsibleWellComponent>
</li>
);
}
generateConfickerIssue(issue) {
return (
<li>
Install the latest Windows updates or upgrade to a newer operating system.
<CollapsibleWellComponent>
The machine <span className="label label-primary">{issue.machine}</span> (<span
className="label label-info" style={{margin: '2px'}}>{issue.ip_address}</span>) is vulnerable to a <span
className="label label-danger">Conficker</span> attack.
<br/>
The attack was made possible because the target machine used an outdated and unpatched operating system
vulnerable to Conficker.
</CollapsibleWellComponent>
</li>
);
}
generateIslandCrossSegmentIssue(issue) {
return (
<li>
Segment your network and make sure there is no communication between machines from different segments.
<CollapsibleWellComponent>
The network can probably be segmented. A monkey instance on <span
className="label label-primary">{issue.machine}</span> in the
networks {this.generateInfoBadges(issue.networks)}
could directly access the Monkey Island server in the
networks {this.generateInfoBadges(issue.server_networks)}.
</CollapsibleWellComponent>
</li>
);
}
generateSharedCredsDomainIssue(issue) {
return (
<li>
Some domain users are sharing passwords, this should be fixed by changing passwords.
<CollapsibleWellComponent>
These users are sharing access password:
{this.generateInfoBadges(issue.shared_with)}.
</CollapsibleWellComponent>
</li>
);
}
generateSharedCredsIssue(issue) {
return (
<li>
Some users are sharing passwords, this should be fixed by changing passwords.
<CollapsibleWellComponent>
These users are sharing access password:
{this.generateInfoBadges(issue.shared_with)}.
</CollapsibleWellComponent>
</li>
);
}
generateSharedLocalAdminsIssue(issue) {
return (
<li>
Make sure the right administrator accounts are managing the right machines, and that there isnt an unintentional local
admin sharing.
<CollapsibleWellComponent>
Here is a list of machines which the account <span
className="label label-primary">{issue.username}</span> is defined as an administrator:
{this.generateInfoBadges(issue.shared_machines)}
</CollapsibleWellComponent>
</li>
);
}
generateStrongUsersOnCritIssue(issue) {
return (
<li>
This critical machine is open to attacks via strong users with access to it.
<CollapsibleWellComponent>
The services: {this.generateInfoBadges(issue.services)} have been found on the machine
thus classifying it as a critical machine.
These users has access to it:
{this.generateInfoBadges(issue.threatening_users)}.
</CollapsibleWellComponent>
</li>
);
}
generateTunnelIssue(issue) {
return (
<li>
Use micro-segmentation policies to disable communication other than the required.
<CollapsibleWellComponent>
Machines are not locked down at port level. Network tunnel was set up from <span
className="label label-primary">{issue.machine}</span> to <span
className="label label-primary">{issue.dest}</span>.
</CollapsibleWellComponent>
</li>
);
}
generateStruts2Issue(issue) {
return (
<li>
Upgrade Struts2 to version 2.3.32 or 2.5.10.1 or any later versions.
<CollapsibleWellComponent>
Struts2 server at <span className="label label-primary">{issue.machine}</span> (<span
className="label label-info" style={{margin: '2px'}}>{issue.ip_address}</span>) is vulnerable to <span
className="label label-danger">remote code execution</span> attack.
<br/>
The attack was made possible because the server is using an old version of Jakarta based file upload
Multipart parser. For possible work-arounds and more info read <a
href="https://cwiki.apache.org/confluence/display/WW/S2-045"
>here</a>.
</CollapsibleWellComponent>
</li>
);
}
generateWebLogicIssue(issue) {
return (
<li>
Update Oracle WebLogic server to the latest supported version.
<CollapsibleWellComponent>
Oracle WebLogic server at <span className="label label-primary">{issue.machine}</span> (<span
className="label label-info" style={{margin: '2px'}}>{issue.ip_address}</span>) is vulnerable to one of <span
className="label label-danger">remote code execution</span> attacks.
<br/>
The attack was made possible due to one of the following vulnerabilities:
<a href={'https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-10271'}> CVE-2017-10271</a> or
<a href={'https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-2725'}> CVE-2019-2725</a>
</CollapsibleWellComponent>
</li>
);
}
generateHadoopIssue(issue) {
return (
<li>
Run Hadoop in secure mode (<a
href="http://hadoop.apache.org/docs/current/hadoop-project-dist/hadoop-common/SecureMode.html">
add Kerberos authentication</a>).
<CollapsibleWellComponent>
The Hadoop server at <span className="label label-primary">{issue.machine}</span> (<span
className="label label-info" style={{margin: '2px'}}>{issue.ip_address}</span>) is vulnerable to <span
className="label label-danger">remote code execution</span> attack.
<br/>
The attack was made possible due to default Hadoop/Yarn configuration being insecure.
</CollapsibleWellComponent>
</li>
);
}
generateMSSQLIssue(issue) {
return (
<li>
Disable the xp_cmdshell option.
<CollapsibleWellComponent>
The machine <span className="label label-primary">{issue.machine}</span> (<span
className="label label-info" style={{margin: '2px'}}>{issue.ip_address}</span>) is vulnerable to a <span
className="label label-danger">MSSQL exploit attack</span>.
<br/>
The attack was made possible because the target machine used an outdated MSSQL server configuration allowing
the usage of the xp_cmdshell command. To learn more about how to disable this feature, read <a
href="https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/xp-cmdshell-server-configuration-option?view=sql-server-2017">
Microsoft's documentation. </a>
</CollapsibleWellComponent>
</li>
);
}
generateIssue = (issue) => {
let data;
switch (issue.type) {
case 'vsftp':
data = this.generateVsftpdBackdoorIssue(issue);
break;
case 'smb_password':
data = this.generateSmbPasswordIssue(issue);
break;
case 'smb_pth':
data = this.generateSmbPthIssue(issue);
break;
case 'wmi_password':
data = this.generateWmiPasswordIssue(issue);
break;
case 'wmi_pth':
data = this.generateWmiPthIssue(issue);
break;
case 'ssh':
data = this.generateSshIssue(issue);
break;
case 'ssh_key':
data = this.generateSshKeysIssue(issue);
break;
case 'sambacry':
data = this.generateSambaCryIssue(issue);
break;
case 'elastic':
data = this.generateElasticIssue(issue);
break;
case 'shellshock':
data = this.generateShellshockIssue(issue);
break;
case 'conficker':
data = this.generateConfickerIssue(issue);
break;
case 'island_cross_segment':
data = this.generateIslandCrossSegmentIssue(issue);
break;
case 'shared_passwords':
data = this.generateSharedCredsIssue(issue);
break;
case 'shared_passwords_domain':
data = this.generateSharedCredsDomainIssue(issue);
break;
case 'shared_admins_domain':
data = this.generateSharedLocalAdminsIssue(issue);
break;
case 'strong_users_on_crit':
data = this.generateStrongUsersOnCritIssue(issue);
break;
case 'tunnel':
data = this.generateTunnelIssue(issue);
break;
case 'azure_password':
data = this.generateAzureIssue(issue);
break;
case 'struts2':
data = this.generateStruts2Issue(issue);
break;
case 'weblogic':
data = this.generateWebLogicIssue(issue);
break;
case 'hadoop':
data = this.generateHadoopIssue(issue);
break;
case 'mssql':
data = this.generateMSSQLIssue(issue);
break;
}
return data;
};
generateIssues = (issues) => {
let issuesDivArray = [];
for (let machine of Object.keys(issues)) {
issuesDivArray.push(
<li>
<h4><b>{machine}</b></h4>
<ol>
{issues[machine].map(this.generateIssue)}
</ol>
</li>
);
}
return <ul>{issuesDivArray}</ul>;
};
}
export default ReportPageComponent;

View File

@ -0,0 +1,66 @@
import React, {Fragment} from 'react';
import AuthComponent from '../AuthComponent';
import ReportHeader, {ReportTypes} from './common/ReportHeader';
import ReportLoader from './common/ReportLoader';
import PrintReportButton from './common/PrintReportButton';
import SummarySection from './zerotrust/SummarySection';
import FindingsSection from './zerotrust/FindingsSection';
import PrinciplesSection from './zerotrust/PrinciplesSection';
class ZeroTrustReportPageComponent extends AuthComponent {
constructor(props) {
super(props);
this.state = this.props.report
}
componentDidUpdate(prevProps) {
if (this.props.report !== prevProps.report) {
this.setState(this.props.report)
}
}
render() {
let content;
if (this.stillLoadingDataFromServer()) {
content = <ReportLoader loading={true}/>;
} else {
content = <div id="MainContentSection">
<SummarySection allMonkeysAreDead={this.state.allMonkeysAreDead} pillars={this.state.pillars}/>
<PrinciplesSection principles={this.state.principles}
pillarsToStatuses={this.state.pillars.pillarsToStatuses}/>
<FindingsSection pillarsToStatuses={this.state.pillars.pillarsToStatuses} findings={this.state.findings}/>
</div>;
}
return (
<Fragment>
<div style={{marginBottom: '20px'}}>
<PrintReportButton onClick={() => {
print();
}}/>
</div>
<div className="report-page">
<ReportHeader report_type={ReportTypes.zeroTrust}/>
<hr/>
{content}
</div>
<div style={{marginTop: '20px'}}>
<PrintReportButton onClick={() => {
print();
}}/>
</div>
</Fragment>
)
}
stillLoadingDataFromServer() {
return typeof this.state.findings === 'undefined'
|| typeof this.state.pillars === 'undefined'
|| typeof this.state.principles === 'undefined';
}
}
export default ZeroTrustReportPageComponent;

View File

@ -1,6 +1,5 @@
import React, {Component} from 'react';
import {Col, Grid, Row} from 'react-bootstrap';
import MonkeysStillAliveWarning from '../common/MonkeysStillAliveWarning';
import PillarsOverview from './PillarOverview';
import ZeroTrustReportLegend from './ReportLegend';
import * as PropTypes from 'prop-types';
@ -12,7 +11,6 @@ export default class SummarySection extends Component {
<Grid fluid={true}>
<Row>
<Col xs={12} sm={12} md={12} lg={12}>
<MonkeysStillAliveWarning allMonkeysAreDead={this.props.allMonkeysAreDead}/>
<p>
Get a quick glance at how your network aligns with the <a
href="https://www.forrester.com/report/The+Zero+Trust+eXtended+ZTX+Ecosystem/-/E-RES137210">
@ -36,6 +34,5 @@ export default class SummarySection extends Component {
}
SummarySection.propTypes = {
allMonkeysAreDead: PropTypes.bool,
pillars: PropTypes.object
};