forked from p15670423/monkey
Refactored zerologon exploiters report part to conform to new report structure
This commit is contained in:
parent
c504b21d33
commit
e96b8eec38
|
@ -7,6 +7,8 @@ from monkey_island.cc.services.reporting.issue_processing.exploit_processing.pro
|
||||||
from monkey_island.cc.services.reporting.issue_processing.exploit_processing.processors.exploit import ExploitProcessor
|
from monkey_island.cc.services.reporting.issue_processing.exploit_processing.processors.exploit import ExploitProcessor
|
||||||
from monkey_island.cc.services.reporting.issue_processing.exploit_processing.processors.shellshock_exploit import \
|
from monkey_island.cc.services.reporting.issue_processing.exploit_processing.processors.shellshock_exploit import \
|
||||||
ShellShockExploitProcessor
|
ShellShockExploitProcessor
|
||||||
|
from monkey_island.cc.services.reporting.issue_processing.exploit_processing.processors.zerologon import \
|
||||||
|
ZerologonExploitProcessor
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
@ -31,3 +33,4 @@ class ExploiterDescriptorEnum(Enum):
|
||||||
MSSQL = ExploiterDescriptor('MSSQLExploiter', 'MSSQL Exploiter', ExploitProcessor)
|
MSSQL = ExploiterDescriptor('MSSQLExploiter', 'MSSQL Exploiter', ExploitProcessor)
|
||||||
VSFTPD = ExploiterDescriptor('VSFTPDExploiter', 'VSFTPD Backdoor Exploiter', CredExploitProcessor)
|
VSFTPD = ExploiterDescriptor('VSFTPDExploiter', 'VSFTPD Backdoor Exploiter', CredExploitProcessor)
|
||||||
DRUPAL = ExploiterDescriptor('DrupalExploiter', 'Drupal Server Exploiter', ExploitProcessor)
|
DRUPAL = ExploiterDescriptor('DrupalExploiter', 'Drupal Server Exploiter', ExploitProcessor)
|
||||||
|
ZEROLOGON = ExploiterDescriptor('ZerologonExploiter', 'ZeroLogon Exploiter', ZerologonExploitProcessor)
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
from monkey_island.cc.services.reporting.issue_processing.exploit_processing.processors.exploit import ExploitProcessor, \
|
||||||
|
ExploiterReportInfo
|
||||||
|
|
||||||
|
|
||||||
|
class ZerologonExploitProcessor:
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_exploit_info_by_dict(class_name: str, exploit_dict: dict) -> ExploiterReportInfo:
|
||||||
|
exploit_info = ExploitProcessor.get_exploit_info_by_dict(class_name, exploit_dict)
|
||||||
|
exploit_info.password_restored = exploit_dict['data']['info']['password_restored']
|
||||||
|
return exploit_info
|
|
@ -45,6 +45,7 @@ class ReportService:
|
||||||
class DerivedIssueEnum:
|
class DerivedIssueEnum:
|
||||||
WEAK_PASSWORD = "weak_password"
|
WEAK_PASSWORD = "weak_password"
|
||||||
STOLEN_CREDS = "stolen_creds"
|
STOLEN_CREDS = "stolen_creds"
|
||||||
|
ZEROLOGON_PASS_RESTORE_FAILED = "zerologon_pass_restore_failed"
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_first_monkey_time():
|
def get_first_monkey_time():
|
||||||
|
@ -264,7 +265,7 @@ class ReportService:
|
||||||
return exploiter_info
|
return exploiter_info
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_exploits() -> dict:
|
def get_exploits() -> List[dict]:
|
||||||
query = [{'$match': {'telem_category': 'exploit', 'data.result': True}},
|
query = [{'$match': {'telem_category': 'exploit', 'data.result': True}},
|
||||||
{'$group': {'_id': {'ip_address': '$data.machine.ip_addr'},
|
{'$group': {'_id': {'ip_address': '$data.machine.ip_addr'},
|
||||||
'data': {'$first': '$$ROOT'},
|
'data': {'$first': '$$ROOT'},
|
||||||
|
@ -439,7 +440,6 @@ class ReportService:
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_domain_issues():
|
def get_domain_issues():
|
||||||
|
|
||||||
ISSUE_GENERATORS = [
|
ISSUE_GENERATORS = [
|
||||||
PTHReportService.get_duplicated_passwords_issues,
|
PTHReportService.get_duplicated_passwords_issues,
|
||||||
PTHReportService.get_shared_admins_issues,
|
PTHReportService.get_shared_admins_issues,
|
||||||
|
@ -491,8 +491,7 @@ class ReportService:
|
||||||
if exploits == default_exploits:
|
if exploits == default_exploits:
|
||||||
return ['default']
|
return ['default']
|
||||||
|
|
||||||
# TODO investigate strange code
|
return exploits
|
||||||
return [exploit for exploit in exploits]
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_config_ips():
|
def get_config_ips():
|
||||||
|
@ -508,13 +507,12 @@ class ReportService:
|
||||||
|
|
||||||
for machine in issues:
|
for machine in issues:
|
||||||
for issue in issues[machine]:
|
for issue in issues[machine]:
|
||||||
# TODO check if this actually works, because stolen passwords get added to config
|
|
||||||
# so any password will be in config. We need to separate stolen passwords from initial
|
|
||||||
# passwords in config.
|
|
||||||
if ReportService._is_weak_credential_issue(issue, config_users, config_passwords):
|
if ReportService._is_weak_credential_issue(issue, config_users, config_passwords):
|
||||||
issue_set.add(ReportService.DerivedIssueEnum.WEAK_PASSWORD)
|
issue_set.add(ReportService.DerivedIssueEnum.WEAK_PASSWORD)
|
||||||
elif ReportService._is_stolen_credential_issue(issue):
|
elif ReportService._is_stolen_credential_issue(issue):
|
||||||
issue_set.add(ReportService.DerivedIssueEnum.STOLEN_CREDS)
|
issue_set.add(ReportService.DerivedIssueEnum.STOLEN_CREDS)
|
||||||
|
elif ReportService._is_zerologon_pass_restore_failed(issue):
|
||||||
|
issue_set.add(ReportService.DerivedIssueEnum.ZEROLOGON_PASS_RESTORE_FAILED)
|
||||||
|
|
||||||
issue_set.add(issue['type'])
|
issue_set.add(issue['type'])
|
||||||
|
|
||||||
|
@ -535,6 +533,11 @@ class ReportService:
|
||||||
(issue['credential_type'] == CredentialType.PASSWORD.value or
|
(issue['credential_type'] == CredentialType.PASSWORD.value or
|
||||||
issue['credential_type'] == CredentialType.HASH.value)
|
issue['credential_type'] == CredentialType.HASH.value)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _is_zerologon_pass_restore_failed(issue: dict):
|
||||||
|
return issue['type'] == ExploiterDescriptorEnum.ZEROLOGON.value.class_name \
|
||||||
|
and not issue['password_restored']
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def is_report_generated():
|
def is_report_generated():
|
||||||
generated_report = mongo.db.report.find_one({})
|
generated_report = mongo.db.report.find_one({})
|
||||||
|
@ -594,7 +597,6 @@ class ReportService:
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_issues():
|
def get_issues():
|
||||||
# Todo refactor these into separate files with a method signature -> dict
|
|
||||||
ISSUE_GENERATORS = [
|
ISSUE_GENERATORS = [
|
||||||
ReportService.get_exploits,
|
ReportService.get_exploits,
|
||||||
ReportService.get_tunnels,
|
ReportService.get_tunnels,
|
||||||
|
|
|
@ -46,6 +46,11 @@ import {StolenCredsIssueOverview} from './security/issues/StolenCredsIssue';
|
||||||
import {WeakPasswordIssueOverview} from './security/issues/WeakPasswordIssue';
|
import {WeakPasswordIssueOverview} from './security/issues/WeakPasswordIssue';
|
||||||
import {AzurePasswordIssueOverview, AzurePasswordIssueReport} from './security/issues/AzurePasswordIssue';
|
import {AzurePasswordIssueOverview, AzurePasswordIssueReport} from './security/issues/AzurePasswordIssue';
|
||||||
import {generateStrongUsersOnCritIssue} from './security/issues/StrongUsersOnCritIssue';
|
import {generateStrongUsersOnCritIssue} from './security/issues/StrongUsersOnCritIssue';
|
||||||
|
import {
|
||||||
|
ZerologonIssueOverview,
|
||||||
|
ZerologonIssueReport,
|
||||||
|
ZerologonOverviewWithFailedPassResetWarning
|
||||||
|
} from './security/issues/ZerologonIssue';
|
||||||
|
|
||||||
|
|
||||||
class ReportPageComponent extends AuthComponent {
|
class ReportPageComponent extends AuthComponent {
|
||||||
|
@ -139,7 +144,12 @@ class ReportPageComponent extends AuthComponent {
|
||||||
[this.issueContentTypes.TYPE]: this.issueTypes.DANGER
|
[this.issueContentTypes.TYPE]: this.issueTypes.DANGER
|
||||||
},
|
},
|
||||||
'ZerologonExploiter': {
|
'ZerologonExploiter': {
|
||||||
//TODO add
|
[this.issueContentTypes.OVERVIEW]: ZerologonIssueOverview,
|
||||||
|
[this.issueContentTypes.REPORT]: ZerologonIssueReport,
|
||||||
|
[this.issueContentTypes.TYPE]: this.issueTypes.DANGER
|
||||||
|
},
|
||||||
|
'zerologon_pass_restore_failed': {
|
||||||
|
[this.issueContentTypes.OVERVIEW]: ZerologonOverviewWithFailedPassResetWarning,
|
||||||
},
|
},
|
||||||
'island_cross_segment': {
|
'island_cross_segment': {
|
||||||
[this.issueContentTypes.OVERVIEW]: crossSegmentIssueOverview,
|
[this.issueContentTypes.OVERVIEW]: crossSegmentIssueOverview,
|
||||||
|
@ -162,11 +172,9 @@ class ReportPageComponent extends AuthComponent {
|
||||||
[this.issueContentTypes.TYPE]: this.issueTypes.WARNING
|
[this.issueContentTypes.TYPE]: this.issueTypes.WARNING
|
||||||
},
|
},
|
||||||
'shared_passwords_domain': {
|
'shared_passwords_domain': {
|
||||||
[this.issueContentTypes.REPORT]: generateSharedCredsDomainIssue(),
|
[this.issueContentTypes.REPORT]: generateSharedCredsDomainIssue,
|
||||||
[this.issueContentTypes.TYPE]: this.issueTypes.WARNING
|
[this.issueContentTypes.TYPE]: this.issueTypes.WARNING
|
||||||
},
|
},
|
||||||
|
|
||||||
// This issue was missing overview section
|
|
||||||
'strong_users_on_crit': {
|
'strong_users_on_crit': {
|
||||||
[this.issueContentTypes.REPORT]: generateStrongUsersOnCritIssue,
|
[this.issueContentTypes.REPORT]: generateStrongUsersOnCritIssue,
|
||||||
[this.issueContentTypes.TYPE]: this.issueTypes.DANGER
|
[this.issueContentTypes.TYPE]: this.issueTypes.DANGER
|
||||||
|
@ -224,8 +232,6 @@ class ReportPageComponent extends AuthComponent {
|
||||||
if (this.stillLoadingDataFromServer()) {
|
if (this.stillLoadingDataFromServer()) {
|
||||||
content = <ReportLoader loading={true}/>;
|
content = <ReportLoader loading={true}/>;
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
console.log(this.state.report);
|
|
||||||
content =
|
content =
|
||||||
<div>
|
<div>
|
||||||
{this.generateReportOverviewSection()}
|
{this.generateReportOverviewSection()}
|
||||||
|
@ -386,7 +392,7 @@ class ReportPageComponent extends AuthComponent {
|
||||||
<div>
|
<div>
|
||||||
The Monkey uncovered the following possible set of issues:
|
The Monkey uncovered the following possible set of issues:
|
||||||
<ul>
|
<ul>
|
||||||
{overviews}
|
{this.getPotentialSecurityIssuesOverviews()}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
:
|
:
|
||||||
|
@ -416,15 +422,18 @@ class ReportPageComponent extends AuthComponent {
|
||||||
|
|
||||||
getPotentialSecurityIssuesOverviews() {
|
getPotentialSecurityIssuesOverviews() {
|
||||||
let overviews = [];
|
let overviews = [];
|
||||||
|
let issues = this.state.report.overview.issues;
|
||||||
|
|
||||||
for (let issueKey of this.state.report.overview.issues) {
|
for(let i=0; i < issues.length; i++) {
|
||||||
overviews.push(this.IssueDescriptorEnum[issueKey][this.issueContentTypes.OVERVIEW]);
|
if (this.isIssuePotentialSecurityIssue(issues[i])) {
|
||||||
|
overviews.push(this.getIssueOverview(this.IssueDescriptorEnum[issues[i]]));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return overviews;
|
return overviews;
|
||||||
}
|
}
|
||||||
|
|
||||||
getImmediateThreats() {
|
getImmediateThreats() {
|
||||||
let threatCount = this.countImmediateThreats()
|
let threatCount = this.getImmediateThreatCount()
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h3>
|
<h3>
|
||||||
|
@ -436,18 +445,19 @@ class ReportPageComponent extends AuthComponent {
|
||||||
<span className="badge badge-warning">
|
<span className="badge badge-warning">
|
||||||
{threatCount} threats
|
{threatCount} threats
|
||||||
</span>:
|
</span>:
|
||||||
|
{this.getImmediateThreatsOverviews()}
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>)
|
</div>)
|
||||||
}
|
}
|
||||||
|
|
||||||
countImmediateThreats() {
|
getImmediateThreatCount() {
|
||||||
let threatCount = 0;
|
let threatCount = 0;
|
||||||
let issues = this.state.report.overview.issues;
|
let issues = this.state.report.overview.issues;
|
||||||
|
|
||||||
for(let i=0; i < issues.length; i++) {
|
for(let i=0; i < issues.length; i++) {
|
||||||
if (this.IssueDescriptorEnum[issues[i]][this.issueContentTypes.TYPE] === this.issueTypes.DANGER) {
|
if(this.isIssueImmediateThreat(issues[i])) {
|
||||||
threatCount++;
|
threatCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -551,8 +561,7 @@ class ReportPageComponent extends AuthComponent {
|
||||||
generateIssue = (issue) => {
|
generateIssue = (issue) => {
|
||||||
let issueDescriptor = this.IssueDescriptorEnum[issue.type];
|
let issueDescriptor = this.IssueDescriptorEnum[issue.type];
|
||||||
|
|
||||||
let reportFnc = (issue) => {
|
let reportFnc = (issue) => {};
|
||||||
};
|
|
||||||
if (issue.hasOwnProperty('credential_type')) {
|
if (issue.hasOwnProperty('credential_type')) {
|
||||||
reportFnc = issueDescriptor[this.issueContentTypes.REPORT][issue.credential_type];
|
reportFnc = issueDescriptor[this.issueContentTypes.REPORT][issue.credential_type];
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in New Issue