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.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)

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: 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,

View File

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