From 25a3cc525160ff93d183dfa1de96ebcfa1e601ae Mon Sep 17 00:00:00 2001 From: 1mm0rt41PC <5358076+1mm0rt41PC@users.noreply.github.com> Date: Tue, 4 Jul 2023 22:12:53 +0200 Subject: [PATCH 01/15] Update AppContainer.jsx --- src/AppContainer.jsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/AppContainer.jsx b/src/AppContainer.jsx index 4b64651d3..f53e0f72a 100644 --- a/src/AppContainer.jsx +++ b/src/AppContainer.jsx @@ -83,7 +83,12 @@ const fullEdgeList = [ 'AddKeyCredentialLink', 'DumpSMSAPassword', 'DCSync', - 'SyncLAPSPassword' + 'SyncLAPSPassword', + 'Enroll', + 'AutoEnroll', + 'ManageCa', + 'ManageCertificates', + 'EnabledBy' ]; export default class AppContainer extends Component { From 11e734323c2763a5963f77cdbf21d17cb86325e0 Mon Sep 17 00:00:00 2001 From: 1mm0rt41PC <5358076+1mm0rt41PC@users.noreply.github.com> Date: Tue, 4 Jul 2023 22:17:18 +0200 Subject: [PATCH 02/15] Adjust query field --- src/components/RawQuery.jsx | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/components/RawQuery.jsx b/src/components/RawQuery.jsx index 8f9240e49..77a20b80b 100644 --- a/src/components/RawQuery.jsx +++ b/src/components/RawQuery.jsx @@ -24,12 +24,14 @@ const RawQuery = () => { const onKeyDown = (e) => { let key = e.keyCode ? e.keyCode : e.which; - if (key === 13) { + if ((key == 10 || key == 13) && e.ctrlKey) { emitter.emit('query', query); } }; const onChange = (e) => { + e.target.style.height = 'inherit'; + e.target.style.height = `${e.target.scrollHeight}px`; setQueryFromEvent(e.target.value); }; @@ -59,7 +61,7 @@ const RawQuery = () => { transition={{ duration: 0.25 }} animate={open ? 'open' : 'closed'} > - { className={clsx(styles.input, 'form-control')} autoComplete='off' placeholder='Enter a cypher query. Your query must return nodes or paths.' - /> + /> */} + ); From 79bad46143ea19890a41a52842efef6d4eb7f22f Mon Sep 17 00:00:00 2001 From: 1mm0rt41PC <5358076+1mm0rt41PC@users.noreply.github.com> Date: Tue, 4 Jul 2023 22:19:12 +0200 Subject: [PATCH 03/15] Add edge for PKI --- .../SearchContainer/EdgeFilter/EdgeFilter.jsx | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/components/SearchContainer/EdgeFilter/EdgeFilter.jsx b/src/components/SearchContainer/EdgeFilter/EdgeFilter.jsx index 68f702626..d1edb653b 100644 --- a/src/components/SearchContainer/EdgeFilter/EdgeFilter.jsx +++ b/src/components/SearchContainer/EdgeFilter/EdgeFilter.jsx @@ -112,6 +112,21 @@ const EdgeFilter = ({ open }) => { + + + + +
Date: Tue, 4 Jul 2023 22:21:57 +0200 Subject: [PATCH 04/15] Support for icon PKI --- src/components/SearchContainer/SearchRow.jsx | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/components/SearchContainer/SearchRow.jsx b/src/components/SearchContainer/SearchRow.jsx index 74c9fe3aa..e2bda714c 100644 --- a/src/components/SearchContainer/SearchRow.jsx +++ b/src/components/SearchContainer/SearchRow.jsx @@ -43,6 +43,12 @@ const SearchRow = ({ item, search }) => { case 'OU': icon.className = 'fa fa-sitemap'; break; + case 'CA': + icon.className = 'fa fa-university'; + break; + case 'CertificateTemplate': + icon.className = 'fa fa-id-card'; + break; case 'Container': icon.className = 'fa fa-box' break @@ -104,8 +110,12 @@ const SearchRow = ({ item, search }) => { icon.className = 'fa fa-window-restore' break default: - icon.className = 'fa fa-question'; - type = 'Base'; + if (item.hasOwnProperty("bl-icon")){ + icon.className = 'fa '+ item["bl-icon"]; + }else{ + icon.className = 'fa fa-question'; + type = 'Base'; + } break; } From 1210224fb696bce3e79f73b408bd5b92ce4b9b7d Mon Sep 17 00:00:00 2001 From: 1mm0rt41PC <5358076+1mm0rt41PC@users.noreply.github.com> Date: Tue, 4 Jul 2023 22:26:00 +0200 Subject: [PATCH 05/15] Add support for PKI in tab view --- .../SearchContainer/TabContainer.jsx | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/components/SearchContainer/TabContainer.jsx b/src/components/SearchContainer/TabContainer.jsx index 3fa5b51d3..5d97b5be2 100644 --- a/src/components/SearchContainer/TabContainer.jsx +++ b/src/components/SearchContainer/TabContainer.jsx @@ -8,6 +8,8 @@ import ComputerNodeData from './Tabs/ComputerNodeData'; import DomainNodeData from './Tabs/DomainNodeData'; import GpoNodeData from './Tabs/GPONodeData'; import OuNodeData from './Tabs/OUNodeData'; +import CaNodeData from './Tabs/CANodeData'; +import TemplateNodeData from './Tabs/TemplateNodeData'; import AZGroupNodeData from './Tabs/AZGroupNodeData'; import AZUserNodeData from './Tabs/AZUserNodeData'; import AZContainerRegistryNodeData from './Tabs/AZContainerRegistryNodeData'; @@ -48,6 +50,8 @@ class TabContainer extends Component { domainVisible: false, gpoVisible: false, ouVisible: false, + caVisible: false, + templateVisible: false, containerVisible: false, azGroupVisible: false, azUserVisible: false, @@ -92,6 +96,10 @@ class TabContainer extends Component { this._domainNodeClicked(); } else if (type === 'OU') { this._ouNodeClicked(); + } else if (type === 'CA') { + this._caNodeClicked(); + } else if (type === 'CertificateTemplate') { + this._templateNodeClicked(); } else if (type === 'GPO') { this._gpoNodeClicked(); } else if (type === 'AZGroup') { @@ -225,6 +233,22 @@ class TabContainer extends Component { }); } + _caNodeClicked() { + this.clearVisible() + this.setState({ + caVisible: true, + selected: 2 + }); + } + + _templateNodeClicked() { + this.clearVisible() + this.setState({ + templateVisible: true, + selected: 2 + }); + } + _azGroupNodeClicked() { this.clearVisible() this.setState({ @@ -405,6 +429,8 @@ class TabContainer extends Component { !this.state.domainVisible && !this.state.gpoVisible && !this.state.ouVisible && + !this.state.caVisible && + !this.state.templateVisible && !this.state.azGroupVisible && !this.state.azUserVisible && !this.state.azContainerRegistryVisible && @@ -436,6 +462,8 @@ class TabContainer extends Component { + + From f805aeda2bff85069aee75d20d4dcfa1c71682cb Mon Sep 17 00:00:00 2001 From: 1mm0rt41PC <5358076+1mm0rt41PC@users.noreply.github.com> Date: Tue, 4 Jul 2023 22:27:21 +0200 Subject: [PATCH 06/15] Add support for custom group icon --- src/components/SearchContainer/SearchRow.jsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/components/SearchContainer/SearchRow.jsx b/src/components/SearchContainer/SearchRow.jsx index e2bda714c..83756d5e7 100644 --- a/src/components/SearchContainer/SearchRow.jsx +++ b/src/components/SearchContainer/SearchRow.jsx @@ -26,7 +26,11 @@ const SearchRow = ({ item, search }) => { switch (type) { case 'Group': - icon.className = 'fa fa-users'; + if (item.hasOwnProperty("bl-icon")){ + icon.className = 'fa '+ item["bl-icon"]; + }else{ + icon.className = 'fa fa-users'; + } break; case 'User': icon.className = 'fa fa-user'; From 23ecdeaf0c87755c141bc5ef079c6609c91cb755 Mon Sep 17 00:00:00 2001 From: 1mm0rt41PC <5358076+1mm0rt41PC@users.noreply.github.com> Date: Tue, 4 Jul 2023 22:29:36 +0200 Subject: [PATCH 07/15] Create CANodeData.jsx --- .../SearchContainer/Tabs/CANodeData.jsx | 171 ++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 src/components/SearchContainer/Tabs/CANodeData.jsx diff --git a/src/components/SearchContainer/Tabs/CANodeData.jsx b/src/components/SearchContainer/Tabs/CANodeData.jsx new file mode 100644 index 000000000..8e4c6ef7b --- /dev/null +++ b/src/components/SearchContainer/Tabs/CANodeData.jsx @@ -0,0 +1,171 @@ +/****************************************************************************************** +* The credit goes to https://github.com/ly4k/BloodHound. Thank you for the excellent work! +*/ +import clsx from 'clsx'; +import React, { useContext, useEffect, useState } from 'react'; +import { Table } from 'react-bootstrap'; +import { AppContext } from '../../../AppContext'; +import CollapsibleSection from './Components/CollapsibleSection'; +import ExtraNodeProps from './Components/ExtraNodeProps'; +import MappedNodeProps from './Components/MappedNodeProps'; +import NodeCypherLink from './Components/NodeCypherLink'; +import NodePlayCypherLink from './Components/NodePlayCypherLink'; +import NodeCypherNoNumberLink from './Components/NodeCypherNoNumberLink'; +import styles from './NodeData.module.css'; + +const CANodeData = () => { + const [visible, setVisible] = useState(false); + const [objectid, setObjectid] = useState(null); + const [label, setLabel] = useState(null); + const [domain, setDomain] = useState(null); + const [nodeProps, setNodeProps] = useState({}); + const [blocksInheritance, setBlocksInheritance] = useState(false); + const context = useContext(AppContext); + + useEffect(() => { + emitter.on('nodeClicked', nodeClickEvent); + + return () => { + emitter.removeListener('nodeClicked', nodeClickEvent); + }; + }, []); + + const nodeClickEvent = (type, id, blocksinheritance, domain) => { + if (type === 'CA') { + setVisible(true); + setObjectid(id); + setDomain(domain); + setBlocksInheritance(blocksinheritance); + let session = driver.session(); + session + .run(`MATCH (n:CA {objectid: $objectid}) RETURN n AS node`, { + objectid: id, + }) + .then((r) => { + let props = r.records[0].get('node').properties; + setNodeProps(props); + setLabel(props.name); + session.close(); + }); + } else { + setObjectid(null); + setVisible(false); + } + }; + + const displayMap = { + objectid: 'Object ID', + 'CA Name': 'CA Name', + }; + + return objectid === null ? ( +
+ ) : ( +
+
+
{label || objectid}
+ + +
+ + + + + +
+
+
+ +
+ + + +
+ + + +
+ + +
+ + + + (u1:CA {objectid: $objectid}) WHERE r.isacl=true' + } + end={label} + distinct + /> + (g:Group)-[r1:ManageCa|ManageCertificates|Auditor|Operator|Owns]->(u:CA {objectid: $objectid}) WITH LENGTH(p) as pathLength, p, n WHERE NONE (x in NODES(p)[1..(pathLength-1)] WHERE x.objectid = u.objectid) AND NOT n.objectid = u.objectid' + } + end={label} + distinct + /> + +
+
+
+ +
+ + +
+ + + + (u1:CA {objectid: $objectid}) WHERE r.isacl=true' + } + end={label} + distinct + /> + (g:Group)-[r1:Read|Enroll]->(u:CA {objectid: $objectid}) WITH LENGTH(p) as pathLength, p, n WHERE NONE (x in NODES(p)[1..(pathLength-1)] WHERE x.objectid = u.objectid) AND NOT n.objectid = u.objectid' + } + end={label} + distinct + /> + +
+
+
+ +
+
+
+ ); +}; + +CANodeData.propTypes = {}; +export default CANodeData; From 7f876d1c911b040eee3e6712259ec91544d10da8 Mon Sep 17 00:00:00 2001 From: 1mm0rt41PC <5358076+1mm0rt41PC@users.noreply.github.com> Date: Tue, 4 Jul 2023 22:31:48 +0200 Subject: [PATCH 08/15] Edit tab of item selection to add count of "Certificate Templates" & "Certificate Authorities" --- .../SearchContainer/Tabs/DatabaseDataDisplay.jsx | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/components/SearchContainer/Tabs/DatabaseDataDisplay.jsx b/src/components/SearchContainer/Tabs/DatabaseDataDisplay.jsx index a411c2829..17e3176bb 100644 --- a/src/components/SearchContainer/Tabs/DatabaseDataDisplay.jsx +++ b/src/components/SearchContainer/Tabs/DatabaseDataDisplay.jsx @@ -113,6 +113,20 @@ const DatabaseDataDisplay = () => { index={index} label={'Computers'} /> + + Date: Tue, 4 Jul 2023 22:33:18 +0200 Subject: [PATCH 09/15] Add prebuild queries for PKI --- .../SearchContainer/Tabs/PrebuiltQueries.json | 170 ++++++++++++++++++ 1 file changed, 170 insertions(+) diff --git a/src/components/SearchContainer/Tabs/PrebuiltQueries.json b/src/components/SearchContainer/Tabs/PrebuiltQueries.json index 42f628bf8..af222e101 100644 --- a/src/components/SearchContainer/Tabs/PrebuiltQueries.json +++ b/src/components/SearchContainer/Tabs/PrebuiltQueries.json @@ -384,6 +384,176 @@ "endNode": "{}" } ] + }, + { + "name": "Find all Certificate Templates", + "category": "PKI", + "queryList": [ + { + "final": true, + "query": "MATCH (n:CertificateTemplate) RETURN n" + } + ] + }, + { + "name": "Find enabled Certificate Templates", + "category": "PKI", + "queryList": [ + { + "final": true, + "query": "MATCH (n:CertificateTemplate) WHERE n.Enabled = true RETURN n" + } + ] + }, + { + "name": "Find Certificate Authorities", + "category": "PKI", + "queryList": [ + { + "final": true, + "query": "MATCH (n:CA) RETURN n" + } + ] + }, + { + "name": "Find Misconfigured Certificate Templates (ESC1)", + "category": "PKI", + "queryList": [ + { + "final": true, + "query": "MATCH (n:CertificateTemplate) WHERE n.`Enrollee Supplies Subject` = true and n.`Client Authentication` = true and n.`Enabled` = true RETURN n" + } + ] + }, + { + "name": "Shortest Paths to Misconfigured Certificate Templates from Owned Principals (ESC1)", + "category": "PKI", + "queryList": [ + { + "final": true, + "query": "MATCH p=allShortestPaths((g {owned:true})-[r*1..]->(n:CertificateTemplate)) WHERE g<>n and n.`Enrollee Supplies Subject` = true and n.`Client Authentication` = true and n.`Enabled` = true and NONE(rel in r WHERE type(rel) in ['EnabledBy','Read','ManageCa','ManageCertificates']) return p" + } + ] + }, + { + "name": "Find Misconfigured Certificate Templates (ESC2)", + "category": "PKI", + "queryList": [ + { + "final": true, + "query": "MATCH (n:CertificateTemplate) WHERE n.`Enabled` = true and n.`Any Purpose` = true RETURN n" + } + ] + }, + { + "name": "Shortest Paths to Misconfigured Certificate Templates from Owned Principals (ESC2)", + "category": "PKI", + "queryList": [ + { + "final": true, + "query": "MATCH p=allShortestPaths((g {owned:true})-[r*1..]->(n:CertificateTemplate)) WHERE g<>n and n.`Enabled` = true and n.`Any Purpose` = true and NONE(rel in r WHERE type(rel) in ['EnabledBy','Read','ManageCa','ManageCertificates']) return p" + } + ] + }, + { + "name": "Find Enrollment Agent Templates (ESC3)", + "category": "PKI", + "queryList": [ + { + "final": true, + "query": "MATCH (n:CertificateTemplate) WHERE n.`Enabled` = true and n.`Enrollment Agent` = true RETURN n" + } + ] + }, + { + "name": "Shortest Paths to Enrollment Agent Templates from Owned Principals (ESC3)", + "category": "PKI", + "queryList": [ + { + "final": true, + "query": "MATCH p=allShortestPaths((g {owned:true})-[r*1..]->(n:CertificateTemplate)) WHERE g<>n and n.`Enabled` = true and n.`Enrollment Agent` = true and NONE(rel in r WHERE type(rel) in ['EnabledBy','Read','ManageCa','ManageCertificates']) return p" + } + ] + }, + { + "name": "Shortest Paths to Vulnerable Certificate Template Access Control (ESC4)", + "category": "PKI", + "queryList": [ + { + "final": true, + "query": "MATCH p=shortestPath((g)-[r*1..]->(n:CertificateTemplate)) WHERE g<>n and n.`Enabled` = true and NONE(rel in r WHERE type(rel) in ['EnabledBy','Read','ManageCa','ManageCertificates','Enroll','AutoEnroll']) RETURN p" + } + ] + }, + { + "name": "Shortest Paths to Vulnerable Certificate Template Access Control from Owned Principals (ESC4)", + "category": "PKI", + "queryList": [ + { + "final": true, + "query": "MATCH p=allShortestPaths((g {owned:true})-[r*1..]->(n:CertificateTemplate)) WHERE g<>n and n.Enabled = true and NONE(rel in r WHERE type(rel) in ['EnabledBy','Read','ManageCa','ManageCertificates','Enroll','AutoEnroll']) return p" + } + ] + }, + { + "name": "Find Certificate Authorities with User Specified SAN (ESC6)", + "category": "PKI", + "queryList": [ + { + "final": true, + "query": "MATCH (n:CA) WHERE n.`User Specified SAN` = 'Enabled' RETURN n" + } + ] + }, + { + "name": "Shortest Paths to Vulnerable Certificate Authority Access Control (ESC7)", + "category": "PKI", + "queryList": [ + { + "final": true, + "query": "MATCH p=allShortestPaths((g)-[r*1..]->(n:CA)) WHERE g<>n and NONE(rel in r WHERE type(rel) in ['EnabledBy','Read','Enroll','AutoEnroll']) RETURN p" + } + ] + }, + { + "name": "Shortest Paths to Vulnerable Certificate Authority Access Control from Owned Principals (ESC7)", + "category": "PKI", + "queryList": [ + { + "final": true, + "query": "MATCH p=allShortestPaths((g {owned:true})-[r*1..]->(n:CA)) WHERE g<>n and NONE(rel in r WHERE type(rel) in ['EnabledBy','Read','Enroll','AutoEnroll']) RETURN p" + } + ] + }, + { + "name": "Find Certificate Authorities with HTTP Web Enrollment (ESC8)", + "category": "PKI", + "queryList": [ + { + "final": true, + "query": "MATCH (n:CA) WHERE n.`Web Enrollment` = 'Enabled' RETURN n" + } + ] + }, + { + "name": "Find Unsecured Certificate Templates (ESC9)", + "category": "PKI", + "queryList": [ + { + "final": true, + "query": "MATCH (n:CertificateTemplate) WHERE 'NoSecurityExtension' in n.`Enrollment Flag` and n.`Enabled` = true RETURN n" + } + ] + }, + { + "name": "Shortest Paths to Unsecured Certificate Templates from Owned Principals (ESC9)", + "category": "PKI", + "queryList": [ + { + "final": true, + "query": "MATCH p=allShortestPaths((g {owned:true})-[r*1..]->(n:CertificateTemplate)) WHERE g<>n and 'NoSecurityExtension' in n.`Enrollment Flag` and n.`Enabled` = true and NONE(rel in r WHERE type(rel) in ['EnabledBy','Read','ManageCa','ManageCertificates']) return p" + } + ] } ] } From cbc46f227080e13c5858d7630aa2b07f42defc37 Mon Sep 17 00:00:00 2001 From: 1mm0rt41PC <5358076+1mm0rt41PC@users.noreply.github.com> Date: Tue, 4 Jul 2023 22:38:40 +0200 Subject: [PATCH 10/15] Support for copy/past queries --- .../Tabs/PrebuiltQueryNode.jsx | 106 +++++++++++++++++- 1 file changed, 101 insertions(+), 5 deletions(-) diff --git a/src/components/SearchContainer/Tabs/PrebuiltQueryNode.jsx b/src/components/SearchContainer/Tabs/PrebuiltQueryNode.jsx index 7aa7853f3..942d89495 100644 --- a/src/components/SearchContainer/Tabs/PrebuiltQueryNode.jsx +++ b/src/components/SearchContainer/Tabs/PrebuiltQueryNode.jsx @@ -1,7 +1,37 @@ -import React, { Component } from 'react'; +import React, { Component, useContext } from 'react'; import './PrebuiltQueries.module.css'; +import { motion } from 'framer-motion'; +import { AppContext } from '../../../AppContext'; + +import GlyphiconSpan from '../../GlyphiconSpan'; +import Icon from '../../Icon'; +import { withAlert } from 'react-alert'; + export default class PrebuiltQueryNode extends Component { + static contextType = AppContext; + + constructor(props) { + super(props) + + this.state = { + hovered: false + } + } + + enterQuery() { + this.setState({ + hovered: true + }) + }; + + + exitQuery() { + this.setState({ + hovered: false + }) + }; + render() { let c; @@ -14,11 +44,77 @@ export default class PrebuiltQueryNode extends Component { } }.bind(this); + const copyQuery = (e) => { + let containsProps = false; + let queries = [] + let queryList = this.props.info.queryList + + let containsMultipleQueries = queryList.length > 1; + + for (var i = 0; i < queryList.length; i++) { + let query = queryList[i].query; + + if (queries.length > 0) { + queries.push(""); + } + + let props = queryList[i].props; + if (props) { + containsProps = true; + for (const [key, value] of Object.entries(props)) { + query = query.replace(`\$${key}`, JSON.stringify(value)) + } + } + queries.push(query); + } + + navigator.clipboard.writeText(queries.join("\n")) + + this.props.alert.info("Copied query") + + if (containsProps) { + this.props.alert.show(WARNING Query contains props. These might not be properly formatted, { type: 'error' }) + } + + if (containsMultipleQueries) { + this.props.alert.show(WARNING Query contains multiple queries, { type: 'error' }) + } + }; + + const variants = { + open: { height: 'auto', opacity: 1 }, + closed: { height: 0, opacity: 0 }, + }; + return ( - - {this.props.info.name} - - + + {this.props.info.name} + + + copyQuery()} + > + + + + + + + ); } } +export default withAlert()(PrebuiltQueryNode) From 892740e7837cf10bfcfacd79095395424651464c Mon Sep 17 00:00:00 2001 From: 1mm0rt41PC <5358076+1mm0rt41PC@users.noreply.github.com> Date: Tue, 4 Jul 2023 22:39:40 +0200 Subject: [PATCH 11/15] Create TemplateNodeData.jsx --- .../SearchContainer/Tabs/TemplateNodeData.jsx | 171 ++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 src/components/SearchContainer/Tabs/TemplateNodeData.jsx diff --git a/src/components/SearchContainer/Tabs/TemplateNodeData.jsx b/src/components/SearchContainer/Tabs/TemplateNodeData.jsx new file mode 100644 index 000000000..6a854200b --- /dev/null +++ b/src/components/SearchContainer/Tabs/TemplateNodeData.jsx @@ -0,0 +1,171 @@ +/****************************************************************************************** +* The credit goes to https://github.com/ly4k/BloodHound. Thank you for the excellent work! +*/ +import clsx from 'clsx'; +import React, { useContext, useEffect, useState } from 'react'; +import { Table } from 'react-bootstrap'; +import { AppContext } from '../../../AppContext'; +import CollapsibleSection from './Components/CollapsibleSection'; +import ExtraNodeProps from './Components/ExtraNodeProps'; +import MappedNodeProps from './Components/MappedNodeProps'; +import NodeCypherLink from './Components/NodeCypherLink'; +import NodeCypherNoNumberLink from './Components/NodeCypherNoNumberLink'; +import styles from './NodeData.module.css'; + +const TemplateNodeData = () => { + const [visible, setVisible] = useState(false); + const [objectid, setObjectid] = useState(null); + const [label, setLabel] = useState(null); + const [domain, setDomain] = useState(null); + const [nodeProps, setNodeProps] = useState({}); + const [blocksInheritance, setBlocksInheritance] = useState(false); + const context = useContext(AppContext); + + useEffect(() => { + emitter.on('nodeClicked', nodeClickEvent); + + return () => { + emitter.removeListener('nodeClicked', nodeClickEvent); + }; + }, []); + + const nodeClickEvent = (type, id, blocksinheritance, domain) => { + if (type === 'CertificateTemplate') { + setVisible(true); + setObjectid(id); + setDomain(domain); + setBlocksInheritance(blocksinheritance); + let session = driver.session(); + session + .run(`MATCH (n:CertificateTemplate {objectid: $objectid}) RETURN n AS node`, { + objectid: id, + }) + .then((r) => { + let props = r.records[0].get('node').properties; + setNodeProps(props); + setLabel(props.name); + session.close(); + }); + } else { + setObjectid(null); + setVisible(false); + } + }; + + const displayMap = { + objectid: 'Object ID', + 'Template Name': 'Template Name', + 'Display Name': 'Display Name', + }; + + return objectid === null ? ( +
+ ) : ( +
+
+
{label || objectid}
+ + +
+ + + + + +
+
+
+ +
+ + + +
+ + + +
+ + +
+ + + + (u1:CertificateTemplate {objectid: $objectid}) WHERE r.isacl=true' + } + end={label} + distinct + /> + (g:Group)-[r1:AllExtendedRights|GenericAll|GenericWrite|WriteDacl|WriteOwner|WriteProperty|Owns]->(u:CertificateTemplate {objectid: $objectid}) WITH LENGTH(p) as pathLength, p, n WHERE NONE (x in NODES(p)[1..(pathLength-1)] WHERE x.objectid = u.objectid) AND NOT n.objectid = u.objectid' + } + end={label} + distinct + /> + +
+
+
+ +
+ + +
+ + + + (u1:CertificateTemplate {objectid: $objectid}) WHERE r.isacl=true' + } + end={label} + distinct + /> + (g:Group)-[r1:AutoEnroll|Enroll]->(u:CertificateTemplate {objectid: $objectid}) WITH LENGTH(p) as pathLength, p, n WHERE NONE (x in NODES(p)[1..(pathLength-1)] WHERE x.objectid = u.objectid) AND NOT n.objectid = u.objectid' + } + end={label} + distinct + /> + +
+
+
+ +
+
+
+ ); +}; + +TemplateNodeData.propTypes = {}; +export default TemplateNodeData; From da2f27c7b0222b1a510eb842d859923e48394add Mon Sep 17 00:00:00 2001 From: 1mm0rt41PC <5358076+1mm0rt41PC@users.noreply.github.com> Date: Tue, 4 Jul 2023 22:40:39 +0200 Subject: [PATCH 12/15] Add support color scheme for PKI --- src/index.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/index.js b/src/index.js index 03e5815a4..a5df54f48 100644 --- a/src/index.js +++ b/src/index.js @@ -142,6 +142,18 @@ global.appStore = { scale: 1.25, color: '#FFAA00', }, + CA: { + font: "'Font Awesome 5 Free'", + content: '\uF19C', + scale: 1.25, + color: '#FFAA00', + }, + CertificateTemplate: { + font: "'Font Awesome 5 Free'", + content: '\uF2C2', + scale: 1.25, + color: '#73E6A1', + }, Container: { font: "'Font Awesome 5 Free'", content: '\uF466', From df069f60c9acbea68f73abd4c3d09520f5e4d7e3 Mon Sep 17 00:00:00 2001 From: 1mm0rt41PC <5358076+1mm0rt41PC@users.noreply.github.com> Date: Tue, 4 Jul 2023 22:43:41 +0200 Subject: [PATCH 13/15] Add support for ingestion of new PKI repr by Certipy --- src/js/newingestion.js | 62 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/src/js/newingestion.js b/src/js/newingestion.js index 9e91bfddb..4002bbde4 100644 --- a/src/js/newingestion.js +++ b/src/js/newingestion.js @@ -20,6 +20,8 @@ export const ADLabels = { Computer: 'Computer', OU: 'OU', GPO: 'GPO', + CertificateTemplate: 'CertificateTemplate', + CA: 'CA', Domain: 'Domain', Container: 'Container', MemberOf: 'MemberOf', @@ -34,6 +36,7 @@ export const ADLabels = { Contains: 'Contains', GPLink: 'GPLink', TrustedBy: 'TrustedBy', + EnabledBy: 'EnabledBy', DumpSMSAPassword: 'DumpSMSAPassword', }; @@ -224,6 +227,65 @@ export function buildGroupJsonNew(chunk) { return queries; } +/** + * + * @param {Array.} chunk + * @returns {{}} + */ +export function buildTemplateJsonNew(chunk) { + let queries = {}; + + queries.properties = {}; + queries.properties.statement = PROP_QUERY.format(ADLabels.CertificateTemplate); + queries.properties.props = []; + + for (let template of chunk) { + let properties = template.Properties; + let identifier = template.ObjectIdentifier; + let aces = template.Aces; + let cas = template.cas_ids; + + queries.properties.props.push({ objectid: identifier, map: properties }); + + processAceArrayNew(aces, identifier, ADLabels.CertificateTemplate, queries); + + if (cas) { + let format = [ADLabels.CertificateTemplate, ADLabels.CA, ADLabels.EnabledBy, NON_ACL_PROPS]; + let props = cas.map((ca) => { + return { source: identifier, target: ca }; + }); + insertNew(queries, format, props); + } + } + + return queries; +} + +/** + * + * @param {Array.} chunk + * @returns {{}} + */ +export function buildCaJsonNew(chunk) { + let queries = {}; + + queries.properties = {}; + queries.properties.statement = PROP_QUERY.format(ADLabels.CA); + queries.properties.props = []; + + for (let ca of chunk) { + let properties = ca.Properties; + let identifier = ca.ObjectIdentifier; + let aces = ca.Aces; + + queries.properties.props.push({ objectid: identifier, map: properties }); + + processAceArrayNew(aces, identifier, ADLabels.CA, queries); + } + + return queries; +} + /** * * @param {Array.} chunk From ad5cec600565fa64d1830830aa0649fcea0bead9 Mon Sep 17 00:00:00 2001 From: 1mm0rt41PC <5358076+1mm0rt41PC@users.noreply.github.com> Date: Tue, 4 Jul 2023 22:47:47 +0200 Subject: [PATCH 14/15] Added ESC9 --- src/components/SearchContainer/Tabs/TemplateNodeData.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/SearchContainer/Tabs/TemplateNodeData.jsx b/src/components/SearchContainer/Tabs/TemplateNodeData.jsx index 6a854200b..572dbe226 100644 --- a/src/components/SearchContainer/Tabs/TemplateNodeData.jsx +++ b/src/components/SearchContainer/Tabs/TemplateNodeData.jsx @@ -142,7 +142,7 @@ const TemplateNodeData = () => { property='First Degree Enrollment Rights' target={objectid} baseQuery={ - 'MATCH p=(n)-[r:AutoEnroll|Enroll]->(u1:CertificateTemplate {objectid: $objectid}) WHERE r.isacl=true' + 'MATCH p=(n)-[r:AutoEnroll|Enroll|GenericAll]->(u1:CertificateTemplate {objectid: $objectid}) WHERE r.isacl=true' } end={label} distinct @@ -151,7 +151,7 @@ const TemplateNodeData = () => { property='Group Delegated Enrollment Rights' target={objectid} baseQuery={ - 'MATCH p=(n)-[r:MemberOf*1..]->(g:Group)-[r1:AutoEnroll|Enroll]->(u:CertificateTemplate {objectid: $objectid}) WITH LENGTH(p) as pathLength, p, n WHERE NONE (x in NODES(p)[1..(pathLength-1)] WHERE x.objectid = u.objectid) AND NOT n.objectid = u.objectid' + 'MATCH p=(n)-[r:MemberOf*1..]->(g:Group)-[r1:AutoEnroll|Enroll|GenericAll]->(u:CertificateTemplate {objectid: $objectid}) WITH LENGTH(p) as pathLength, p, n WHERE NONE (x in NODES(p)[1..(pathLength-1)] WHERE x.objectid = u.objectid) AND NOT n.objectid = u.objectid' } end={label} distinct From f9ace41bb31ee910f7a183ec3bbd6fe88211020f Mon Sep 17 00:00:00 2001 From: 1mm0rt41PC <5358076+1mm0rt41PC@users.noreply.github.com> Date: Tue, 4 Jul 2023 23:25:07 +0200 Subject: [PATCH 15/15] temp fix for building --- src/components/SearchContainer/Tabs/PrebuiltQueryNode.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/SearchContainer/Tabs/PrebuiltQueryNode.jsx b/src/components/SearchContainer/Tabs/PrebuiltQueryNode.jsx index 942d89495..68c24580e 100644 --- a/src/components/SearchContainer/Tabs/PrebuiltQueryNode.jsx +++ b/src/components/SearchContainer/Tabs/PrebuiltQueryNode.jsx @@ -117,4 +117,4 @@ export default class PrebuiltQueryNode extends Component { ); } } -export default withAlert()(PrebuiltQueryNode) +//export default withAlert()(PrebuiltQueryNode)