Refactored zerologon exploiters report part to conform to new report structure

This commit is contained in:
VakarisZ 2021-03-31 11:53:50 +03:00
parent c504b21d33
commit e96b8eec38
4 changed files with 47 additions and 22 deletions

View File

@ -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.shellshock_exploit import \
ShellShockExploitProcessor
from monkey_island.cc.services.reporting.issue_processing.exploit_processing.processors.zerologon import \
ZerologonExploitProcessor
@dataclass
@ -31,3 +33,4 @@ class ExploiterDescriptorEnum(Enum):
MSSQL = ExploiterDescriptor('MSSQLExploiter', 'MSSQL Exploiter', ExploitProcessor)
VSFTPD = ExploiterDescriptor('VSFTPDExploiter', 'VSFTPD Backdoor Exploiter', CredExploitProcessor)
DRUPAL = ExploiterDescriptor('DrupalExploiter', 'Drupal Server Exploiter', ExploitProcessor)
ZEROLOGON = ExploiterDescriptor('ZerologonExploiter', 'ZeroLogon Exploiter', ZerologonExploitProcessor)

View File

@ -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

View File

@ -45,6 +45,7 @@ class ReportService:
class DerivedIssueEnum:
WEAK_PASSWORD = "weak_password"
STOLEN_CREDS = "stolen_creds"
ZEROLOGON_PASS_RESTORE_FAILED = "zerologon_pass_restore_failed"
@staticmethod
def get_first_monkey_time():
@ -264,7 +265,7 @@ class ReportService:
return exploiter_info
@staticmethod
def get_exploits() -> dict:
def get_exploits() -> List[dict]:
query = [{'$match': {'telem_category': 'exploit', 'data.result': True}},
{'$group': {'_id': {'ip_address': '$data.machine.ip_addr'},
'data': {'$first': '$$ROOT'},
@ -439,7 +440,6 @@ class ReportService:
@staticmethod
def get_domain_issues():
ISSUE_GENERATORS = [
PTHReportService.get_duplicated_passwords_issues,
PTHReportService.get_shared_admins_issues,
@ -491,8 +491,7 @@ class ReportService:
if exploits == default_exploits:
return ['default']
# TODO investigate strange code
return [exploit for exploit in exploits]
return exploits
@staticmethod
def get_config_ips():
@ -508,13 +507,12 @@ class ReportService:
for machine in issues:
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):
issue_set.add(ReportService.DerivedIssueEnum.WEAK_PASSWORD)
elif ReportService._is_stolen_credential_issue(issue):
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'])
@ -535,6 +533,11 @@ class ReportService:
(issue['credential_type'] == CredentialType.PASSWORD.value or
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
def is_report_generated():
generated_report = mongo.db.report.find_one({})
@ -594,7 +597,6 @@ class ReportService:
@staticmethod
def get_issues():
# Todo refactor these into separate files with a method signature -> dict
ISSUE_GENERATORS = [
ReportService.get_exploits,
ReportService.get_tunnels,

View File

@ -46,6 +46,11 @@ import {StolenCredsIssueOverview} from './security/issues/StolenCredsIssue';
import {WeakPasswordIssueOverview} from './security/issues/WeakPasswordIssue';
import {AzurePasswordIssueOverview, AzurePasswordIssueReport} from './security/issues/AzurePasswordIssue';
import {generateStrongUsersOnCritIssue} from './security/issues/StrongUsersOnCritIssue';
import {
ZerologonIssueOverview,
ZerologonIssueReport,
ZerologonOverviewWithFailedPassResetWarning
} from './security/issues/ZerologonIssue';
class ReportPageComponent extends AuthComponent {
@ -139,7 +144,12 @@ class ReportPageComponent extends AuthComponent {
[this.issueContentTypes.TYPE]: this.issueTypes.DANGER
},
'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': {
[this.issueContentTypes.OVERVIEW]: crossSegmentIssueOverview,
@ -162,11 +172,9 @@ class ReportPageComponent extends AuthComponent {
[this.issueContentTypes.TYPE]: this.issueTypes.WARNING
},
'shared_passwords_domain': {
[this.issueContentTypes.REPORT]: generateSharedCredsDomainIssue(),
[this.issueContentTypes.REPORT]: generateSharedCredsDomainIssue,
[this.issueContentTypes.TYPE]: this.issueTypes.WARNING
},
// This issue was missing overview section
'strong_users_on_crit': {
[this.issueContentTypes.REPORT]: generateStrongUsersOnCritIssue,
[this.issueContentTypes.TYPE]: this.issueTypes.DANGER
@ -224,8 +232,6 @@ class ReportPageComponent extends AuthComponent {
if (this.stillLoadingDataFromServer()) {
content = <ReportLoader loading={true}/>;
} else {
console.log(this.state.report);
content =
<div>
{this.generateReportOverviewSection()}
@ -386,7 +392,7 @@ class ReportPageComponent extends AuthComponent {
<div>
The Monkey uncovered the following possible set of issues:
<ul>
{overviews}
{this.getPotentialSecurityIssuesOverviews()}
</ul>
</div>
:
@ -416,15 +422,18 @@ class ReportPageComponent extends AuthComponent {
getPotentialSecurityIssuesOverviews() {
let overviews = [];
let issues = this.state.report.overview.issues;
for (let issueKey of this.state.report.overview.issues) {
overviews.push(this.IssueDescriptorEnum[issueKey][this.issueContentTypes.OVERVIEW]);
for(let i=0; i < issues.length; i++) {
if (this.isIssuePotentialSecurityIssue(issues[i])) {
overviews.push(this.getIssueOverview(this.IssueDescriptorEnum[issues[i]]));
}
}
return overviews;
}
getImmediateThreats() {
let threatCount = this.countImmediateThreats()
let threatCount = this.getImmediateThreatCount()
return (
<div>
<h3>
@ -436,18 +445,19 @@ class ReportPageComponent extends AuthComponent {
<span className="badge badge-warning">
{threatCount} threats
</span>:
{this.getImmediateThreatsOverviews()}
</>
}
</div>
</div>)
}
countImmediateThreats() {
getImmediateThreatCount() {
let threatCount = 0;
let issues = this.state.report.overview.issues;
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++;
}
}
@ -551,8 +561,7 @@ class ReportPageComponent extends AuthComponent {
generateIssue = (issue) => {
let issueDescriptor = this.IssueDescriptorEnum[issue.type];
let reportFnc = (issue) => {
};
let reportFnc = (issue) => {};
if (issue.hasOwnProperty('credential_type')) {
reportFnc = issueDescriptor[this.issueContentTypes.REPORT][issue.credential_type];
} else {