private void GenerateRulesMatched() { AddBeginTable(); AddHeaderText("Domain"); AddHeaderText("Category"); AddHeaderText("Rule"); AddHeaderText("Score"); AddHeaderText("Description"); AddHeaderText("Rationale"); AddBeginTableData(); foreach (HealthcheckData data in Report) { foreach (HealthcheckRiskRule rule in data.RiskRules) { AddBeginRow(); AddPrintDomain(data.Domain); AddCellText(ReportHelper.GetEnumDescription(rule.Category)); AddCellText(rule.RiskId); AddCellNum(rule.Points); AddCellText(RuleSet <HealthcheckData> .GetRuleDescription(rule.RiskId)); AddCellText(rule.Rationale); AddEndRow(); } } AddEndTable(); }
private void GenerateControlPathsInformationAnomalies() { GenerateSubSection("Indirect links"); AddBeginTable(); AddHeaderText("Domain", null, 2); int numRisk = 0; foreach (var objectRisk in (CompromiseGraphDataObjectRisk[])Enum.GetValues(typeof(CompromiseGraphDataObjectRisk))) { AddHeaderText(ReportHelper.GetEnumDescription(objectRisk), colspan: 4); numRisk++; } AddEndRow(); AddBeginRow(); for (int i = 0; i < numRisk; i++) { AddHeaderText(@"Critical Object Found", "Indicates if critical objects such as everyone, authenticated users or domain users can take control, directly or not, of one of the objects."); AddHeaderText(@"Number of objects with Indirect", "Indicates the count of objects per category having at least one indirect user detected."); AddHeaderText(@"Max number of indirect numbers", "Indicates the maximum on all objects of the number of users having indirect access to the object."); AddHeaderText(@"Max ratio", "Indicates in percentage the value of (number of indirect users / number of direct users) if at least one direct users exists. Else the value is zero."); } AddBeginTableData(); foreach (var data in Report) { if (data.ControlPaths == null) { continue; } AddBeginRow(); AddPrintDomain(data.Domain); foreach (var objectRisk in (CompromiseGraphDataObjectRisk[])Enum.GetValues(typeof(CompromiseGraphDataObjectRisk))) { bool found = false; foreach (var analysis in data.ControlPaths.AnomalyAnalysis) { if (analysis.ObjectRisk != objectRisk) { continue; } found = true; AddCellText(analysis.CriticalObjectFound ? "YES" : "NO", true, !analysis.CriticalObjectFound); AddCellNum(analysis.NumberOfObjectsWithIndirect); AddCellNum(analysis.MaximumIndirectNumber); AddCellNum(analysis.MaximumDirectIndirectRatio); break; } if (!found) { AddCellText(""); AddCellNum(0, true); AddCellNum(0, true); AddCellNum(0, true); } } AddEndRow(); } AddEndTable(); }
private void GenerateControlPathsInformationTrusts() { GenerateSubSection("Link with other domains"); AddBeginTable(); AddHeaderText("Domain", null, 2); AddHeaderText("Remote Domain", null, 2); int numTypology = 0; foreach (var typology in (CompromiseGraphDataTypology[])Enum.GetValues(typeof(CompromiseGraphDataTypology))) { AddHeaderText(ReportHelper.GetEnumDescription(typology), colspan: 3); numTypology++; } AddEndRow(); AddBeginRow(); for (int i = 0; i < numTypology; i++) { AddHeaderText(@"Group", "Number of group impacted by this domain"); AddHeaderText("Resolved", "Number of unique SID (account, group, computer, ...) resolved"); AddHeaderText("Unresolved", "Number of unique SID (account, group, computer, ...) NOT resolved meaning that the underlying object may have been removed"); } AddBeginTableData(); foreach (var data in Report) { if (data.ControlPaths == null) { continue; } if (data.ControlPaths != null && data.ControlPaths.Dependancies != null) { foreach (var dependancy in data.ControlPaths.Dependancies) { AddBeginRow(); AddPrintDomain(data.Domain); AddPrintDomain(dependancy.Domain); foreach (var typology in (CompromiseGraphDataTypology[])Enum.GetValues(typeof(CompromiseGraphDataTypology))) { bool found = false; foreach (var item in dependancy.Details) { if (item.Typology != typology) { continue; } found = true; AddCellNum(item.NumberOfGroupImpacted); AddCellNum(item.NumberOfResolvedItems); AddCellNum(item.NumberOfUnresolvedItems); break; } if (!found) { AddCellNum(0, true); AddCellNum(0, true); AddCellNum(0, true); } } AddEndRow(); } } } AddEndTable(); }
protected void GenerateRiskModelPanel(List <HealthcheckRiskRule> rules, int numberOfDomain = 1) { Add(@" <div class=""row d-print-none""><div class=""col-lg-12""> <a data-toggle=""collapse"" data-target=""#riskModel""> <h2>Risk model</h2> </a> </div></div> <div class=""row collapse show d-print-none"" id=""riskModel""> <div class=""col-md-12 table-responsive""> <table class=""model_table""> <thead><tr><th>Stale Objects</th><th>Privileged accounts</th><th>Trusts</th><th>Anomalies</th></tr></thead> <tbody> "); var riskmodel = new Dictionary <RiskRuleCategory, List <RiskModelCategory> >(); foreach (RiskRuleCategory category in Enum.GetValues(typeof(RiskRuleCategory))) { riskmodel[category] = new List <RiskModelCategory>(); } for (int j = 0; j < 4; j++) { for (int i = 0; ; i++) { int id = (1000 * j + 1000 + i); if (Enum.IsDefined(typeof(RiskModelCategory), id)) { riskmodel[(RiskRuleCategory)j].Add((RiskModelCategory)id); } else { break; } } } foreach (RiskRuleCategory category in Enum.GetValues(typeof(RiskRuleCategory))) { riskmodel[category].Sort( (RiskModelCategory a, RiskModelCategory b) => { return(string.Compare(ReportHelper.GetEnumDescription(a), ReportHelper.GetEnumDescription(b))); }); } for (int i = 0; ; i++) { string line = "<tr>"; bool HasValue = false; foreach (RiskRuleCategory category in Enum.GetValues(typeof(RiskRuleCategory))) { if (i < riskmodel[category].Count) { HasValue = true; RiskModelCategory model = riskmodel[category][i]; int score = 0; int numrules = 0; List <HealthcheckRiskRule> rulematched = new List <HealthcheckRiskRule>(); foreach (HealthcheckRiskRule rule in rules) { if (rule.Model == model) { numrules++; score += rule.Points; rulematched.Add(rule); } } string tdclass = ""; if (numrules == 0) { tdclass = "model_good"; } else if (score == 0) { tdclass = "model_info"; } else if (score <= 10 * numberOfDomain) { tdclass = "model_toimprove"; } else if (score <= 30 * numberOfDomain) { tdclass = "model_warning"; } else { tdclass = "model_danger"; } string tooltip = "Rules: " + numrules + " Score: " + (numberOfDomain == 0 ? 100 : score / numberOfDomain); string tooltipdetail = null; string modelstring = ReportHelper.GetEnumDescription(model); rulematched.Sort((HealthcheckRiskRule a, HealthcheckRiskRule b) => { return(a.Points.CompareTo(b.Points)); }); foreach (var rule in rulematched) { tooltipdetail += ReportHelper.Encode(rule.Rationale) + "<br>"; var hcrule = RuleSet <T> .GetRuleFromID(rule.RiskId); if (hcrule != null && !string.IsNullOrEmpty(hcrule.ReportLocation)) { tooltipdetail += "<small class='text-muted'>" + ReportHelper.Encode(hcrule.ReportLocation) + "</small><br>"; } } line += "<td class=\"model_cell " + tdclass + "\"><div class=\"div_model\" placement=\"auto right\" data-toggle=\"popover\" title=\"" + tooltip + "\" data-html=\"true\" data-content=\"" + (String.IsNullOrEmpty(tooltipdetail) ? "No rule matched" : "<p>" + tooltipdetail + "</p>") + "\"><span class=\"small\">" + modelstring + "</span></div></td>"; } else { line += "<td class=\"model_empty_cell\"></td>"; } } line += "</tr>"; if (HasValue) { Add(line); } else { break; } } Add(@" </tbody> </table> </div> <div class=""col-md-12"" id=""maturityModel""> Legend: <br> <i class=""risk_model_none""> </i> score is 0 - no risk identified but some improvements detected<br> <i class=""risk_model_low""> </i> score between 1 and 10 - a few actions have been identified<br> <i class=""risk_model_medium""> </i> score between 10 and 30 - rules should be looked with attention<br> <i class=""risk_model_high""> </i> score higher than 30 - major risks identified </div> </div>" ); }
void GenerateMitreTechnique() { var reference = new Dictionary <RuleMitreAttackTechniqueAttribute, List <RuleBase <HealthcheckData> > >(); int notcovered = 0; foreach (var rule in RuleSet <HealthcheckData> .Rules) { object[] frameworks = rule.GetType().GetCustomAttributes(typeof(RuleMitreAttackTechniqueAttribute), true); if (frameworks == null || frameworks.Length == 0) { notcovered++; } foreach (RuleMitreAttackTechniqueAttribute f in frameworks) { if (!reference.ContainsKey(f)) { reference[f] = new List <RuleBase <HealthcheckData> >(); } reference[f].Add(rule); } } Add("<p>Number of Mitre rules matched: "); Add(reference.Count); Add("</p>"); Add("<p>Number of PingCastle rules not covered: "); Add(notcovered); Add("</p>"); Add("<div class='row'>"); Add("<div class='col-lg-12'>"); var keys = new List <RuleMitreAttackTechniqueAttribute>(reference.Keys); keys.Sort((RuleMitreAttackTechniqueAttribute a, RuleMitreAttackTechniqueAttribute b) => { return(string.Compare(a.Label, b.Label)); }); foreach (MitreAttackMainTechnique mainTechnique in Enum.GetValues(typeof(MitreAttackMainTechnique))) { var description = ReportHelper.GetEnumDescription(mainTechnique); AddParagraph("<strong>" + description + "</strong>"); foreach (var l in keys) { if (l.MainTechnique != mainTechnique) { continue; } Add("<p><a href="); Add(((RuleFrameworkReference)l).URL); Add(">"); Add(((RuleFrameworkReference)l).Label); Add("</a> ["); Add(reference[l].Count); Add("]</p>"); reference[l].Sort((RuleBase <HealthcheckData> a, RuleBase <HealthcheckData> b) => { return(string.CompareOrdinal(a.RiskId, b.RiskId)); }); foreach (var k in reference[l]) { Add(" <span class=\"text-monospace\">"); Add(k.RiskId); Add("</span>"); } } } Add("</div>"); Add("</div>"); }
protected void GenerateRiskModelPanel() { Add(@" <div class=""row""><div class=""col-lg-12""> <a data-toggle=""collapse"" data-target=""#riskModel""> <h2>Risk model</h2> </a> </div></div> <div class=""row""><div class=""col-lg-12""> <p>This model regroup all rules per category. It summarize what checks are performed. Click on a cell to show all rules associated to a category. </p> </div></div> <div class=""row collapse show"" id=""riskModel""> <div class=""col-md-12 table-responsive""> <table class=""model_table""> <thead><tr><th>Stale Objects</th><th>Privileged accounts</th><th>Trusts</th><th>Anomalies</th></tr></thead> <tbody> "); var riskmodel = new Dictionary <RiskRuleCategory, List <RiskModelCategory> >(); foreach (RiskRuleCategory category in Enum.GetValues(typeof(RiskRuleCategory))) { riskmodel[category] = new List <RiskModelCategory>(); } for (int j = 0; j < 4; j++) { for (int i = 0; ; i++) { int id = (1000 * j + 1000 + i); if (Enum.IsDefined(typeof(RiskModelCategory), id)) { riskmodel[(RiskRuleCategory)j].Add((RiskModelCategory)id); } else { break; } } } foreach (RiskRuleCategory category in Enum.GetValues(typeof(RiskRuleCategory))) { riskmodel[category].Sort( (RiskModelCategory a, RiskModelCategory b) => { return(string.Compare(ReportHelper.GetEnumDescription(a), ReportHelper.GetEnumDescription(b))); }); } for (int i = 0; ; i++) { string line = "<tr>"; bool HasValue = false; foreach (RiskRuleCategory category in Enum.GetValues(typeof(RiskRuleCategory))) { if (i < riskmodel[category].Count) { HasValue = true; RiskModelCategory model = riskmodel[category][i]; int score = 0; int numrules = 0; var rulematched = new List <RuleBase <HealthcheckData> >(); foreach (var rule in RuleSet <HealthcheckData> .Rules) { if (rule.Model == model) { numrules++; score += rule.Points; rulematched.Add(rule); } } string tdclass = ""; tdclass = "model_good"; string modelstring = ReportHelper.GetEnumDescription(model); string tooltip = modelstring + " [Rules: " + numrules + "]"; string tooltipdetail = null; rulematched.Sort((RuleBase <HealthcheckData> a, RuleBase <HealthcheckData> b) => { return(a.Points.CompareTo(b.Points)); }); foreach (var rule in rulematched) { tooltipdetail += "<li>" + ReportHelper.Encode(rule.Title) + "</li><br>"; } line += "<td class=\"model_cell " + tdclass + "\"><div class=\"div_model\" placement=\"auto\" data-toggle=\"popover\" title=\"" + tooltip + "\" data-html=\"true\" data-content=\"" + "<p>" + _resourceManager.GetString(model.ToString() + "_Detail") + "</p>" + (String.IsNullOrEmpty(tooltipdetail) ? "No rule matched" : "<p><ul>" + tooltipdetail + "</ul></p>") + "\"><span class=\"small\">" + modelstring + "</span></div></td>"; } else { line += "<td class=\"model_empty_cell\"></td>"; } } line += "</tr>"; if (HasValue) { Add(line); } else { break; } } Add(@" </tbody> </table> </div> </div>" ); }
private void GenerateRuleAccordeon(RiskRuleCategory category) { var rules = RuleSet <HealthcheckData> .Rules; rules.Sort((RuleBase <HealthcheckData> a, RuleBase <HealthcheckData> b) => { int c = ReportHelper.GetEnumDescription(a.Model).CompareTo(ReportHelper.GetEnumDescription(b.Model)); if (c == 0) { c = a.Title.CompareTo(b.Title); } return(c); } ); var m = RiskModelCategory.Unknown; var data = new List <KeyValuePair <RiskModelCategory, List <RuleBase <HealthcheckData> > > >(); foreach (var rule in rules) { if (rule.Category == category) { if (rule.Model != m) { m = rule.Model; data.Add(new KeyValuePair <RiskModelCategory, List <RuleBase <HealthcheckData> > >(rule.Model, new List <RuleBase <HealthcheckData> >())); } data[data.Count - 1].Value.Add(rule); } } Add(@" <div class=""row""><div class=""col-lg-12""> <p>Each line represents a rule. Click on a rule to expand it and show the details of it. </p> "); foreach (var d in data) { Add(@" <div class=""row""><div class=""col-lg-12 mt-3""> <h3>" ); Add(ReportHelper.GetEnumDescription(d.Key)); Add(@" </h3> "); string description = _resourceManager.GetString(d.Key.ToString() + "_Detail"); if (!string.IsNullOrEmpty(description)) { Add(@" <div class=""row""><div class=""col-lg-12""> <p>" ); Add(description); Add(@" </p> "); } GenerateAccordion("rules" + d.Key.ToString(), () => { foreach (var rule in d.Value) { GenerateIndicatorPanelDetail(d.Key, rule); } }); } }
private void GenerateTrusts() { List <string> knowndomains = new List <string>(); GenerateSubSection("Link with other domains"); Add(@" <div class=""row""> <div class=""col-md-12 table-responsive""> <table class=""table table-striped table-bordered""> <thead><tr> <th rowspan=""2"">Domain</th> <th rowspan=""2"">Remote Domain</th> "); int numTypology = 0; foreach (var typology in (CompromiseGraphDataTypology[])Enum.GetValues(typeof(CompromiseGraphDataTypology))) { Add(@"<th colspan=""3"">"); AddEncoded(ReportHelper.GetEnumDescription(typology)); Add(@"</th>"); numTypology++; } Add(@"</tr> "); Add(@"<tr>"); for (int i = 0; i < numTypology; i++) { Add(@"<th>Group <i class=""info-mark"" data-placement=""bottom"" data-toggle=""tooltip"" title="""" data-original-title=""Number of group impacted by this domain"">?</i></th><th>Resolved <i class=""info-mark"" data-placement=""bottom"" data-toggle=""tooltip"" title="""" data-original-title=""Number of unique SID (account, group, computer, ...) resolved"">?</i></th><th>Unresolved <i class=""info-mark"" data-placement=""bottom"" data-toggle=""tooltip"" title="""" data-original-title=""Number of unique SID (account, group, computer, ...) NOT resolved meaning that the underlying object may have been removed"">?</i></th>"); } Add(@"</tr>"); Add(@" </thead> <tbody> "); foreach (var data in Report) { if (!knowndomains.Contains(data.DomainFQDN)) { knowndomains.Add(data.DomainFQDN); } foreach (var dependancy in data.Dependancies) { if (!knowndomains.Contains(dependancy.FQDN)) { knowndomains.Add(dependancy.FQDN); } Add(@" <tr> <td class='text'>" + PrintDomain(data.Domain) + @"</td> <td class='text'>" + PrintDomain(dependancy.Domain) + @"</td> "); foreach (var typology in (CompromiseGraphDataTypology[])Enum.GetValues(typeof(CompromiseGraphDataTypology))) { bool found = false; foreach (var item in dependancy.Details) { if (item.Typology != typology) { continue; } found = true; Add(@"<td class=""num"">"); Add(item.NumberOfGroupImpacted); Add(@"</td><td class=""num"">"); Add(item.NumberOfResolvedItems); Add(@"</td><td class=""num"">"); Add(item.NumberOfUnresolvedItems); Add(@"</td>"); break; } if (!found) { Add(@"<td></td><td></td><td></td>"); } } Add(@"</tr> "); } } Add(@" </tbody> </table> </div> </div> "); }
private void GenerateAnomalies() { List <string> knowndomains = new List <string>(); GenerateSubSection("Link with other domains"); Add(@" <div class=""row""> <div class=""col-md-12 table-responsive""> <table class=""table table-striped table-bordered""> <thead><tr> <th rowspan=""2"">Domain</th> "); int numRisk = 0; foreach (var objectRisk in (CompromiseGraphDataObjectRisk[])Enum.GetValues(typeof(CompromiseGraphDataObjectRisk))) { Add(@"<th colspan=""4"">"); AddEncoded(ReportHelper.GetEnumDescription(objectRisk)); Add(@"</th>"); numRisk++; } Add(@"</tr> "); Add(@"<tr>"); for (int i = 0; i < numRisk; i++) { Add(@"<th>Critical Object Found <i class=""info-mark"" data-placement=""bottom"" data-toggle=""tooltip"" title="""" data-original-title=""Indicates if critical objects such as everyone, authenticated users or domain users can take control, directly or not, of one of the objects."">?</i></th> <th>Number of objects with Indirect <i class=""info-mark"" data-placement=""bottom"" data-toggle=""tooltip"" title="""" data-original-title=""Indicates the count of objects per category having at least one indirect user detected."">?</i></th> <th>Max number of indirect numbers <i class=""info-mark"" data-placement=""bottom"" data-toggle=""tooltip"" title="""" data-original-title=""Indicates the maximum on all objects of the number of users having indirect access to the object."">?</i></th> <th>Max ratio <i class=""info-mark"" data-placement=""bottom"" data-toggle=""tooltip"" title="""" data-original-title=""Indicates in percentage the value of (number of indirect users / number of direct users) if at least one direct users exists. Else the value is zero."">?</i></th>"); } Add(@"</tr>"); Add(@" </thead> <tbody> "); foreach (var data in Report) { Add(@" <tr> <td class='text'>" + PrintDomain(data.Domain) + @"</td> "); foreach (var objectRisk in (CompromiseGraphDataObjectRisk[])Enum.GetValues(typeof(CompromiseGraphDataObjectRisk))) { bool found = false; foreach (var analysis in data.AnomalyAnalysis) { if (analysis.ObjectRisk != objectRisk) { continue; } found = true; Add(@"<td class=""text"">"); Add((analysis.CriticalObjectFound ? "<span class='unticked'>YES</span>" : "<span class='ticked'>NO</span>")); Add(@"</td><td class=""num"">"); Add(analysis.NumberOfObjectsWithIndirect); Add(@"</td><td class=""num"">"); Add(analysis.MaximumIndirectNumber); Add(@"</td><td class=""num"">"); Add(analysis.MaximumDirectIndirectRatio); Add(@"</td>"); break; } if (!found) { Add(@"<td></td><td></td><td></td><td></td>"); } } Add(@"</tr> "); } Add(@" </tbody> </table> </div> </div> "); }