public bool RegenerateHtmlTask() { return(StartTask("Regenerate html report", () => { if (!File.Exists(FileOrDirectory)) { WriteInRed("The file " + FileOrDirectory + " doesn't exist"); return; } if (FileOrDirectory.StartsWith("ad_cg_")) { CompromiseGraphData data = DataHelper <CompromiseGraphData> .LoadXml(FileOrDirectory); HealthCheckReportCompromiseGraph report = new HealthCheckReportCompromiseGraph(data, License); report.GenerateReportFile("ad_cg_" + data.DomainFQDN + ".html"); } else { HealthcheckData healthcheckData = DataHelper <HealthcheckData> .LoadXml(FileOrDirectory); HealthCheckReportSingle report = new HealthCheckReportSingle(healthcheckData, License); report.GenerateReportFile("ad_hc_" + healthcheckData.DomainFQDN + ".html"); } } )); }
public bool RegenerateHtmlTask() { return(StartTask("Regenerate html report", () => { if (!File.Exists(FileOrDirectory)) { WriteInRed("The file " + FileOrDirectory + " doesn't exist"); return; } var fi = new FileInfo(FileOrDirectory); if (fi.Name.StartsWith("ad_cg_")) { CompromiseGraphData data = DataHelper <CompromiseGraphData> .LoadXml(FileOrDirectory); var report = new ReportCompromiseGraph(); report.GenerateReportFile(data, License, data.GetHumanReadableFileName()); } else { var healthcheckData = DataHelper <HealthcheckData> .LoadXml(FileOrDirectory); var endUserReportGenerator = PingCastleFactory.GetEndUserReportGenerator <HealthcheckData>(); endUserReportGenerator.GenerateReportFile(healthcheckData, License, healthcheckData.GetHumanReadableFileName()); } } )); }
protected override int?AnalyzeDataNew(CompromiseGraphData compromiseGraphData) { foreach (var single in compromiseGraphData.Data) { if (single.Typology != CompromiseGraphDataTypology.PrivilegedAccount) { continue; } if (single.Name != "S-1-5-32-548" && single.Name != "S-1-5-32-549") { continue; } foreach (var obj in single.Nodes) { if (obj.Type != "user") { continue; } if (obj.Suspicious) { continue; } return(1); } } return(-1); }
protected override int?AnalyzeDataNew(CompromiseGraphData compromiseGraphData) { foreach (var single in compromiseGraphData.Dependancies) { } return(-1); }
public HealthCheckReportCompromiseGraph(CompromiseGraphData compromiseGraphData, ADHealthCheckingLicense license) { this.CompromiseGraphData = compromiseGraphData; _license = license; CompromiseGraphData.Data.Sort( (SingleCompromiseGraphData a, SingleCompromiseGraphData b) => { return(String.Compare(a.Description, b.Description)); }); }
private void PrepareAnomalyAnalysisData(CompromiseGraphData data) { var reference = new Dictionary <CompromiseGraphDataObjectRisk, CompromiseGraphAnomalyAnalysisData>(); foreach (var sg in data.Data) { CompromiseGraphAnomalyAnalysisData analysis = null; if (!reference.ContainsKey(sg.ObjectRisk)) { analysis = new CompromiseGraphAnomalyAnalysisData() { ObjectRisk = sg.ObjectRisk, }; reference[sg.ObjectRisk] = analysis; } else { analysis = reference[sg.ObjectRisk]; } analysis.NumberOfObjectsScreened++; if (sg.CriticalObjectFound) { analysis.CriticalObjectFound = true; } if (sg.IndirectMembers != null && sg.IndirectMembers.Count > 0) { if (analysis.MaximumIndirectNumber < sg.IndirectMembers.Count) { analysis.MaximumIndirectNumber = sg.IndirectMembers.Count; } analysis.NumberOfObjectsWithIndirect++; if (sg.DirectUserMembers != null && sg.DirectUserMembers.Count > 0) { int ratio = 100 * sg.IndirectMembers.Count / sg.DirectUserMembers.Count; if (ratio > analysis.MaximumDirectIndirectRatio) { analysis.MaximumDirectIndirectRatio = ratio; } } } } data.AnomalyAnalysis = new List <CompromiseGraphAnomalyAnalysisData>(); data.AnomalyAnalysis.AddRange(reference.Values); data.AnomalyAnalysis.Sort( (CompromiseGraphAnomalyAnalysisData a, CompromiseGraphAnomalyAnalysisData b) => { return(((int)a.ObjectRisk).CompareTo((int)b.ObjectRisk)); }); }
protected override int?AnalyzeDataNew(CompromiseGraphData compromiseGraphData) { foreach (var single in compromiseGraphData.Dependancies) { foreach (var detail in single.Details) { if (detail.Typology == CompromiseGraphDataTypology.UserDefined) { return(1); } } } return(-1); }
protected override int?AnalyzeDataNew(CompromiseGraphData compromiseGraphData) { foreach (var single in compromiseGraphData.Data) { if (single.Typology != CompromiseGraphDataTypology.PrivilegedAccount && single.Typology != CompromiseGraphDataTypology.PrivilegedAccount) { continue; } if (single.DeletedObjects != null && single.DeletedObjects.Count > 0) { return(1); } } return(-1); }
public CompromiseGraphData GenerateReport(List <string> AdditionalNames) { CompromiseGraphData data = new CompromiseGraphData(); data.GenerationDate = DateTime.Now; Version version = Assembly.GetExecutingAssembly().GetName().Version; data.EngineVersion = version.ToString(4); #if DEBUG data.EngineVersion += " Beta"; #endif Dictionary <string, string> databaseProperties = storage.GetDatabaseInformation(); data.DomainSid = databaseProperties["DomainSid"]; data.DomainFQDN = databaseProperties["DomainName"]; data.Data = new List <SingleCompromiseGraphData>(); ProduceReportFile(data, "Account Operator", "S-1-5-32-548"); ProduceReportFile(data, "Administrators", "S-1-5-32-544"); ProduceReportFile(data, "Domain Administrators", data.DomainSid + "-512"); ProduceReportFile(data, "Enterprise Administrators", data.DomainSid + "-519"); ProduceReportFile(data, "Schema Administrators", data.DomainSid + "-518"); ProduceReportFile(data, "Administrator", data.DomainSid + "-500"); ProduceReportFile(data, "Backup Operators", "S-1-5-32-551"); ProduceReportFile(data, "Certificate Publishers", data.DomainSid + "-517"); ProduceReportFile(data, "Certificate Operators", "S-1-5-32-569"); ProduceReportFile(data, "Domain Controllers", data.DomainSid + "-516"); ProduceReportFile(data, "Enterprise Read Only Domain Controllers", data.DomainSid + "-498"); ProduceReportFile(data, "Group Policy Creator Owners", data.DomainSid + "-520"); ProduceReportFile(data, "Incoming Forest Trust Builders", "S-1-5-32-557"); ProduceReportFile(data, "Krbtgt account", data.DomainSid + "-502"); ProduceReportFile(data, "Network Operators", "S-1-5-32-556"); ProduceReportFile(data, "Pre-Windows 2000 Compatible Access", "S-1-5-32-554"); ProduceReportFile(data, "Print Operators", "S-1-5-32-550"); ProduceReportFile(data, "Domain Root", data.DomainSid); ProduceReportFile(data, "Read Only Domain Controllers", data.DomainSid + "-521"); ProduceReportFile(data, "Server Operators", "S-1-5-32-549"); foreach (string name in AdditionalNames) { ProduceReportFile(data, name, name, true); } return(data); }
private void BuildDeletedObjects(ADDomainInfo domainInfo, CompromiseGraphData data, SingleCompromiseGraphData singleCompromiseData, Dictionary <int, Node> chartNodes) { singleCompromiseData.DeletedObjects = new List <SingleCompromiseGraphDeletedData>(); foreach (var node in chartNodes.Values) { if (String.Equals(node.Type, "foreignsecurityprincipal", StringComparison.InvariantCultureIgnoreCase)) { // ignore everything but deleted accounts if (node.Sid.StartsWith(domainInfo.DomainSid.Value + "-")) { singleCompromiseData.DeletedObjects.Add(new SingleCompromiseGraphDeletedData() { Sid = node.Sid, } ); } } } singleCompromiseData.NumberOfDeletedObjects = singleCompromiseData.DeletedObjects.Count; }
protected int?AnalyzeDataNew(CompromiseGraphData compromiseGraphData, int trigger) { int domainCount = 0; foreach (var single in compromiseGraphData.Dependancies) { foreach (var detail in single.Details) { if (detail.Typology == CompromiseGraphDataTypology.PrivilegedAccount || detail.Typology == CompromiseGraphDataTypology.Infrastructure) { domainCount++; break; } } } if (domainCount > trigger) { return(1); } return(-1); }
protected int?AnalyzeDataNew(CompromiseGraphData compromiseGraphData, CompromiseGraphDataObjectRisk risk, int trigger) { foreach (var analysis in compromiseGraphData.AnomalyAnalysis) { if (analysis.ObjectRisk != risk) { continue; } if (trigger == -1) { if (analysis.CriticalObjectFound) { return(1); } } else if (analysis.MaximumIndirectNumber > trigger) { return(1); } } return(-1); }
private void ProduceReportFile(CompromiseGraphData data, string description, string name, bool onDemand = false) { try { Dictionary <string, string> databaseProperties = storage.GetDatabaseInformation(); DateTime exportDate = DateTime.Parse(databaseProperties["Date"]); Trace.WriteLine("Generating Description:" + description + " Name=" + name); int rootNodeId = storage.SearchItem(name); if (rootNodeId < 0) { Trace.WriteLine("Id not found for name=" + name); Console.WriteLine("The report " + description + " starting from " + name + " couldn't be built because the object wasn't found"); return; } List <int> nodesid = new List <int>(); Dictionary <int, List <Relation> > links = RetrieveLinks(rootNodeId, nodesid); Dictionary <int, Node> nodes = storage.RetrieveNodes(nodesid); SimplifyGraph(nodes, links); ComputeDistance(rootNodeId, links, nodes); var singleCompromiseData = BuildSingleCompromiseGraphData(rootNodeId, nodes, links); singleCompromiseData.Name = name; singleCompromiseData.Description = description; singleCompromiseData.OnDemandAnalysis = onDemand; data.Data.Add(singleCompromiseData); } catch (Exception ex) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Exception: " + ex.Message); Console.WriteLine(ex.StackTrace); Trace.WriteLine(ex.Message); Trace.WriteLine(ex.StackTrace); if (ex.InnerException != null) { Trace.WriteLine("innerexception: " + ex.InnerException.Message); } } }
protected override int?AnalyzeDataNew(CompromiseGraphData compromiseGraphData) { return(AnalyzeDataNew(compromiseGraphData, CompromiseGraphDataObjectRisk.High, 100)); }
public bool ReloadXmlReport() { return(StartTask("Reload report", () => { if (!File.Exists(FileOrDirectory)) { WriteInRed("The file " + FileOrDirectory + " doesn't exist"); return; } string newfile = FileOrDirectory.Replace(".xml", "_reloaded.xml"); string xml = null; string domainFQDN = null; if (FileOrDirectory.StartsWith("ad_hc_")) { HealthcheckData healthcheckData = DataHelper <HealthcheckData> .LoadXml(FileOrDirectory); domainFQDN = healthcheckData.DomainFQDN; DisplayAdvancement("Regenerating xml " + (EncryptReport ? " (encrypted)" : "")); healthcheckData.Level = ExportLevel; xml = DataHelper <HealthcheckData> .SaveAsXml(healthcheckData, newfile, EncryptReport); } else if (FileOrDirectory.StartsWith("ad_cg_")) { CompromiseGraphData data = DataHelper <CompromiseGraphData> .LoadXml(FileOrDirectory); domainFQDN = data.DomainFQDN; DisplayAdvancement("Regenerating xml " + (EncryptReport ? " (encrypted)" : "")); xml = DataHelper <CompromiseGraphData> .SaveAsXml(data, newfile, EncryptReport); } if (!String.IsNullOrEmpty(apiKey) && !String.IsNullOrEmpty(apiEndpoint)) { SendViaAPI(new Dictionary <string, string>() { { FileOrDirectory, xml } }); } if (!String.IsNullOrEmpty(sharepointdirectory)) { UploadToWebsite(newfile, xml); } if (!String.IsNullOrEmpty(sendXmlTo)) { SendEmail(sendXmlTo, new List <string> { domainFQDN }, new List <Attachment> { Attachment.CreateAttachmentFromString(xml, newfile) }); } if (!String.IsNullOrEmpty(sendHtmlTo)) { WriteInRed("Html report ignored when xml file used as input"); } if (!String.IsNullOrEmpty(sendAllTo)) { WriteInRed("Html report ignored when xml file used as input"); SendEmail(sendAllTo, new List <string> { domainFQDN }, new List <Attachment> { Attachment.CreateAttachmentFromString(xml, newfile) }); } } )); }
private void PrepareDependancyGlobalData(CompromiseGraphData data) { var reference = new Dictionary <string, CompromiseGraphDependancyData>(); foreach (var sg in data.Data) { foreach (SingleCompromiseGraphDependancyData d in sg.Dependancies) { // beware: we are using exising SingleCompromiseGraphDependancyData with data a key // do not modify the object !!!! if (!reference.ContainsKey(d.Sid)) { reference[d.Sid] = new CompromiseGraphDependancyData(); reference[d.Sid].Details = new List <CompromiseGraphDependancyDetailData>(); reference[d.Sid].FQDN = d.FQDN; reference[d.Sid].Netbios = d.Netbios; reference[d.Sid].Sid = d.Sid; } var gdData = reference[d.Sid]; CompromiseGraphDependancyDetailData detail = null; foreach (var a in gdData.Details) { if (a.Typology == sg.Typology) { detail = a; } } if (detail == null) { detail = new CompromiseGraphDependancyDetailData() { Typology = sg.Typology, Items = new List <string>(), }; reference[d.Sid].Details.Add(detail); } detail.NumberOfGroupImpacted++; foreach (var item in d.Items) { if (!detail.Items.Contains(item.Sid)) { detail.Items.Add(item.Sid); if (item.Name.Contains("\\")) { detail.NumberOfResolvedItems++; } else { detail.NumberOfUnresolvedItems++; } } } } } data.Dependancies = new List <CompromiseGraphDependancyData>(reference.Values); data.Dependancies.Sort((CompromiseGraphDependancyData a, CompromiseGraphDependancyData b) => { return(string.Compare(a.Netbios, b.Netbios)); }); }
private void BuildDependancies(ADDomainInfo domainInfo, CompromiseGraphData refData, SingleCompromiseGraphData singleCompromiseData, Dictionary <int, Node> chartNodes) { var reference = new Dictionary <SecurityIdentifier, SingleCompromiseGraphDependancyData>(); var domains = storage.GetKnownDomains(); foreach (var node in chartNodes.Values) { if (String.Equals(node.Type, "foreignsecurityprincipal", StringComparison.InvariantCultureIgnoreCase)) { // ignore deleted accounts if (node.Sid.StartsWith(domainInfo.DomainSid.Value + "-")) { continue; } SingleCompromiseGraphDependancyData data; var sid = new SecurityIdentifier(node.Sid); var domainSid = sid.AccountDomainSid; if (domainSid == null) { continue; } if (!reference.ContainsKey(domainSid)) { data = new SingleCompromiseGraphDependancyData(); reference[domainSid] = data; data.Sid = domainSid.Value; foreach (var domain in domains) { if (String.Equals(domain.DomainSid.Value, data.Sid, StringComparison.InvariantCultureIgnoreCase)) { data.FQDN = domain.DnsDomainName; data.Netbios = domain.NetbiosDomainName; break; } } data.Items = new List <SingleCompromiseGraphDependancyMemberData>(); } else { data = reference[domainSid]; } if (node.Shortname.Contains("\\")) { if (String.IsNullOrEmpty(data.Netbios)) { data.Netbios = node.Shortname.Split('\\')[0]; } data.NumberOfResolvedItems++; } else { data.NumberOfUnresolvedItems++; } data.Items.Add(new SingleCompromiseGraphDependancyMemberData() { Name = node.Shortname, Sid = node.Sid, } ); } } singleCompromiseData.Dependancies = new List <SingleCompromiseGraphDependancyData>(reference.Values); singleCompromiseData.Dependancies.Sort( (SingleCompromiseGraphDependancyData a, SingleCompromiseGraphDependancyData b) => { return(String.Compare(a.Netbios, b.Netbios)); } ); }
protected override int?AnalyzeDataNew(CompromiseGraphData compromiseGraphData) { return(AnalyzeDataNew(compromiseGraphData, 0)); }
protected override int?AnalyzeDataNew(CompromiseGraphData compromiseGraphData) { return(AnalyzeDataNew(compromiseGraphData, CompromiseGraphDataObjectRisk.Critical, -1)); }