Exemple #1
0
 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();
        }
Exemple #3
0
        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();
        }
Exemple #4
0
        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"">&nbsp;</i> score is 0 - no risk identified but some improvements detected<br>
			<i class=""risk_model_low"">&nbsp;</i> score between 1 and 10  - a few actions have been identified<br>
			<i class=""risk_model_medium"">&nbsp;</i> score between 10 and 30 - rules should be looked with attention<br>
			<i class=""risk_model_high"">&nbsp;</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);
                    }
                });
            }
        }
Exemple #8
0
        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&nbsp;<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&nbsp;<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&nbsp;<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>
");
        }
Exemple #9
0
        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&nbsp;<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&nbsp;<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&nbsp;<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&nbsp;<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>
");
        }