From 0f589d669324cc56ac4b69fa921065e72ec0a695 Mon Sep 17 00:00:00 2001 From: DrieVlad Date: Fri, 27 Sep 2024 12:15:32 +0500 Subject: [PATCH 1/2] Create IPAUser node --- src/components/Menu/MenuContainer.jsx | 2 + src/components/SearchContainer/SearchRow.jsx | 6 + .../SearchContainer/TabContainer.jsx | 29 ++ .../SearchContainer/Tabs/IPAHostNodeData.jsx | 456 ++++++++++++++++++ .../SearchContainer/Tabs/IPAUserNodeData.jsx | 388 +++++++++++++++ src/index.js | 12 + src/js/newingestion.js | 232 +++++++++ 7 files changed, 1125 insertions(+) create mode 100644 src/components/SearchContainer/Tabs/IPAHostNodeData.jsx create mode 100644 src/components/SearchContainer/Tabs/IPAUserNodeData.jsx diff --git a/src/components/Menu/MenuContainer.jsx b/src/components/Menu/MenuContainer.jsx index 5fb5b41a0..e3c427abc 100644 --- a/src/components/Menu/MenuContainer.jsx +++ b/src/components/Menu/MenuContainer.jsx @@ -37,6 +37,8 @@ const IngestFuncMap = { ous: NewIngestion.buildOuJsonNew, gpos: NewIngestion.buildGpoJsonNew, containers: NewIngestion.buildContainerJsonNew, + IPAcomputers: NewIngestion.buildIPAComputerJsonNew, + IPAusers: NewIngestion.buildIPAUserJsonNew, azure: NewIngestion.convertAzureData, }; diff --git a/src/components/SearchContainer/SearchRow.jsx b/src/components/SearchContainer/SearchRow.jsx index 74c9fe3aa..6f75061d4 100644 --- a/src/components/SearchContainer/SearchRow.jsx +++ b/src/components/SearchContainer/SearchRow.jsx @@ -46,6 +46,12 @@ const SearchRow = ({ item, search }) => { case 'Container': icon.className = 'fa fa-box' break + case 'IPAUser': + icon.className = 'fa fa-user'; + break; + case 'IPAComputer': + icon.className = 'fa fa-desktop'; + break; case 'AZUser': icon.className = 'fa fa-user'; break; diff --git a/src/components/SearchContainer/TabContainer.jsx b/src/components/SearchContainer/TabContainer.jsx index 3fa5b51d3..dd167d3ad 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 IPAUserNodeData from './Tabs/IPAUserNodeData'; +import IPAComputerNodeData from './Tabs/IPAHostNodeData'; import AZGroupNodeData from './Tabs/AZGroupNodeData'; import AZUserNodeData from './Tabs/AZUserNodeData'; import AZContainerRegistryNodeData from './Tabs/AZContainerRegistryNodeData'; @@ -49,6 +51,8 @@ class TabContainer extends Component { gpoVisible: false, ouVisible: false, containerVisible: false, + IPAuserVisible: false, + IPAcomputerVisible: false, azGroupVisible: false, azUserVisible: false, azContainerRegistryVisible: false, @@ -94,6 +98,10 @@ class TabContainer extends Component { this._ouNodeClicked(); } else if (type === 'GPO') { this._gpoNodeClicked(); + } else if (type === 'IPAComputer') { + this._computerNodeClicked(); + } else if (type === 'IPAUser') { + this._computerNodeClicked(); } else if (type === 'AZGroup') { this._azGroupNodeClicked(); } else if (type === 'AZUser') { @@ -225,6 +233,23 @@ class TabContainer extends Component { }); } + + _IPAuserNodeClicked() { + this.clearVisible() + this.setState({ + userVisible: true, + selected: 2 + }); + } + + _IPAcomputerNodeClicked() { + this.clearVisible() + this.setState({ + computerVisible: true, + selected: 2 + }); + } + _azGroupNodeClicked() { this.clearVisible() this.setState({ @@ -405,6 +430,8 @@ class TabContainer extends Component { !this.state.domainVisible && !this.state.gpoVisible && !this.state.ouVisible && + !this.state.IPAuserVisible && + !this.state.IPAcomputerVisible && !this.state.azGroupVisible && !this.state.azUserVisible && !this.state.azContainerRegistryVisible && @@ -437,6 +464,8 @@ class TabContainer extends Component { + + diff --git a/src/components/SearchContainer/Tabs/IPAHostNodeData.jsx b/src/components/SearchContainer/Tabs/IPAHostNodeData.jsx new file mode 100644 index 000000000..6c987137c --- /dev/null +++ b/src/components/SearchContainer/Tabs/IPAHostNodeData.jsx @@ -0,0 +1,456 @@ +import React, { useContext, useEffect, useState } from 'react'; +import clsx from 'clsx'; +import CollapsibleSection from './Components/CollapsibleSection'; +import NodeCypherLinkComplex from './Components/NodeCypherLinkComplex'; +import NodeCypherLink from './Components/NodeCypherLink'; +import NodeCypherNoNumberLink from './Components/NodeCypherNoNumberLink'; +import MappedNodeProps from './Components/MappedNodeProps'; +import ExtraNodeProps from './Components/ExtraNodeProps'; +import NodePlayCypherLink from './Components/NodePlayCypherLink'; +import { Table } from 'react-bootstrap'; +import styles from './NodeData.module.css'; +import { AppContext } from '../../../AppContext'; + +const IPAComputerNodeData = () => { + 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 context = useContext(AppContext); + + useEffect(() => { + emitter.on('nodeClicked', nodeClickEvent); + + return () => { + emitter.removeListener('nodeClicked', nodeClickEvent); + }; + }, []); + + const nodeClickEvent = (type, id, blocksinheritance, domain) => { + if (type === 'IPAComputer') { + setVisible(true); + setObjectid(id); + setDomain(domain); + let session = driver.session(); + session + .run( + `MATCH (n:IPAComputer {objectid: $objectid}) RETURN n AS node`, + { + objectid: id, + } + ) + .then((r) => { + let props = r.records[0].get('node').properties; + setNodeProps(props); + setLabel(props.name || props.azname || objectid); + session.close(); + }); + } else { + setObjectid(null); + setVisible(false); + } + }; + + const displayMap = { + objectid: 'Object ID', + operatingsystem: 'OS', + enabled: 'Enabled', + unconstraineddelegation: 'Allows Unconstrained Delegation', + owned: 'Compromised', + haslaps: 'LAPS Enabled', + pwdlastset: 'Password Last Changed', + lastlogon: 'Last Logon', + lastlogontimestamp: 'Last Logon (Replicated)', + }; + + return objectid === null ? ( +
+ ) : ( +
+
+
{label || objectid}
+ + +
+ + + + (n:User) WHERE NOT n.objectid ENDS WITH '$'" + } + start={label} + distinct + /> + (n)) WHERE NONE (r IN relationships(p) WHERE type(r)= "GetChanges") AND NONE (r in relationships(p) WHERE type(r)="GetChangesAll") AND NOT m=n' + } + start={label} + /> + (o2:IPAComputer {objectid: $objectid}) WITH o1 OPTIONAL MATCH p1=(d)-[r2:Contains*1..]->(o1) OPTIONAL MATCH p2=(o1)-[r3:Contains]->(n) WHERE n:User OR n:IPAComputer RETURN count(distinct(n))' + } + graphQuery={ + 'MATCH (o1)-[r1:Contains]->(o2:IPAComputer {objectid: $objectid}) WITH o1 OPTIONAL MATCH p1=(d)-[r2:Contains*1..]->(o1) OPTIONAL MATCH p2=(o1)-[r3:Contains]->(n) WHERE n:User OR n:IPAComputer RETURN p1,p2' + } + /> + (container1)-[r2:Contains*1..]->(c) OPTIONAL MATCH p2 = (g2:GPO)-[r3:GPLink {enforced:false}]->(container2)-[r4:Contains*1..]->(c) WHERE NONE (x in NODES(p2) WHERE x.blocksinheritance = true AND x:OU AND NOT (g2)-->(x)) WITH COLLECT(g1) + COLLECT(g2) AS tempVar UNWIND tempVar AS GPOs RETURN COUNT(DISTINCT(GPOs))' + } + graphQuery={ + 'MATCH (c:IPAComputer {objectid: $objectid}) OPTIONAL MATCH p1 = (g1:GPO)-[r1:GPLink {enforced:true}]->(container1)-[r2:Contains*1..]->(c) OPTIONAL MATCH p2 = (g2:GPO)-[r3:GPLink {enforced:false}]->(container2)-[r4:Contains*1..]->(c) WHERE NONE (x in NODES(p2) WHERE x.blocksinheritance = true AND x:OU AND NOT (g2)-->(x)) RETURN p1,p2' + } + /> + + +
+
+
+ + + + + +
+ + + + (c:IPAComputer {objectid: $objectid})' + } + end={label} + /> + (m:IPAComputer {objectid: $objectid}) WHERE NOT n:Group' + } + end={label} + distinct + /> + (c) WHERE NOT u1.domain = c.domain WITH u1,c OPTIONAL MATCH (u2)-[:MemberOf*1..]->(:Group)-[:AdminTo]->(c) WHERE NOT u2.domain = c.domain WITH COLLECT(u1) + COLLECT(u2) as tempVar,c UNWIND tempVar as principals RETURN COUNT(DISTINCT(principals))' + } + graphQuery={ + 'MATCH (c:IPAComputer {objectid: $objectid}) OPTIONAL MATCH p1 = (u1)-[:AdminTo]->(c) WHERE NOT u1.domain = c.domain WITH p1,c OPTIONAL MATCH p2 = (u2)-[:MemberOf*1..]->(:Group)-[:AdminTo]->(c) WHERE NOT u2.domain = c.domain RETURN p1,p2' + } + /> + (m:IPAComputer {objectid: $objectid}))' + } + end={label} + distinct + /> + +
+
+
+ + +
+ + + + (m:IPAComputer {objectid: $objectid})' + } + end={label} + distinct + /> + (g:Group)-[r:CanRDP]->(m:IPAComputer {objectid: $objectid})' + } + end={label} + distinct + /> + (m:IPAComputer {objectid: $objectid})' + } + end={label} + distinct + /> + (g:Group)-[r:ExecuteDCOM]->(m:IPAComputer {objectid: $objectid})' + } + end={label} + distinct + /> + (m:IPAComputer {objectid: $objectid})' + } + start={label} + distinct + /> + +
+
+
+ + +
+ + + + (n)' + } + start={label} + /> + (n:Group)' + } + start={label} + distinct + /> + (n:Group) WHERE NOT n.domain = c.domain' + } + start={label} + distinct + /> + +
+
+
+ + +
+ + + + (n)' + } + start={label} + distinct + /> + (g:Group)-[r2:AdminTo]->(n:IPAComputer) WHERE NOT n.objectid=$objectid' + } + start={label} + distinct + /> + (n))' + } + start={label} + distinct + /> + +
+
+
+ + +
+ + + + (n:IPAComputer)' + } + start={label} + distinct + /> + (g:Group)-[r2:CanRDP]->(n:IPAComputer)' + } + start={label} + distinct + /> + (n:IPAComputer)' + } + start={label} + distinct + /> + (g:Group)-[r2:ExecuteDCOM]->(n:IPAComputer)' + } + start={label} + distinct + /> + (n:IPAComputer)' + } + start={label} + distinct + /> + +
+
+
+ + +
+ + + + (u1:IPAComputer {objectid:$objectid}) WHERE r.isacl=true' + } + end={label} + distinct + /> + (g:Group)-[r1:AddMember|AddSelf|WriteSPN|AddKeyCredentialLink|AllExtendedRights|GenericAll|GenericWrite|WriteDacl|WriteOwner|Owns]->(u:IPAComputer {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:IPAComputer {objectid:$objectid}))' + } + end={label} + distinct + /> + +
+
+
+ + +
+ + + + (n) WHERE r.isacl=true' + } + start={label} + distinct + /> + (g:Group)-[r2]->(n) WHERE r2.isacl=true' + } + start={label} + distinct + /> + (n))' + } + start={label} + distinct + /> + +
+
+
+ {/* + */} +
+
+ ); +}; + +IPAComputerNodeData.propTypes = {}; +export default IPAComputerNodeData; diff --git a/src/components/SearchContainer/Tabs/IPAUserNodeData.jsx b/src/components/SearchContainer/Tabs/IPAUserNodeData.jsx new file mode 100644 index 000000000..ccd9cedc8 --- /dev/null +++ b/src/components/SearchContainer/Tabs/IPAUserNodeData.jsx @@ -0,0 +1,388 @@ +import React, { useEffect, useState } from 'react'; +import clsx from 'clsx'; +import CollapsibleSection from './Components/CollapsibleSection'; +import NodeCypherLinkComplex from './Components/NodeCypherLinkComplex'; +import NodeCypherLink from './Components/NodeCypherLink'; +import NodeCypherNoNumberLink from './Components/NodeCypherNoNumberLink'; +import MappedNodeProps from './Components/MappedNodeProps'; +import ExtraNodeProps from './Components/ExtraNodeProps'; +import NodePlayCypherLink from './Components/NodePlayCypherLink'; +import { withAlert } from 'react-alert'; +import { Table } from 'react-bootstrap'; +import styles from './NodeData.module.css'; +import { useContext } from 'react'; +import { AppContext } from '../../../AppContext'; + +const IPAUserNodeData = () => { + 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 context = useContext(AppContext); + + useEffect(() => { + emitter.on('nodeClicked', nodeClickEvent); + + return () => { + emitter.removeListener('nodeClicked', nodeClickEvent); + }; + }, []); + + const nodeClickEvent = (type, id, blocksinheritance, domain) => { + if (type === 'IPAUser') { + setVisible(true); + setObjectId(id); + setDomain(domain); + let session = driver.session(); + session + .run(`MATCH (n:IPAUser {objectid: $objectid}) RETURN n AS node`, { + objectid: id, + }) + .then((r) => { + let props = r.records[0].get('node').properties; + setNodeProps(props); + setLabel(props.name || props.azname || objectid); + session.close(); + }); + } else { + setObjectId(null); + setVisible(false); + } + }; + + const displayMap = { + displayname: 'Display Name', + objectid: 'Object ID', + pwdlastset: 'Password Last Changed', + lastlogon: 'Last Logon', + lastlogontimestamp: 'Last Logon (Replicated)', + enabled: 'Enabled', + email: 'Email', + title: 'Title', + homedirectory: 'Home Directory', + description: 'Description', + userpassword: 'User Password', + admincount: 'AdminCount', + owned: 'Compromised', + pwdneverexpires: 'Password Never Expires', + sensitive: 'Cannot Be Delegated', + dontreqpreauth: 'ASREP Roastable', + serviceprincipalnames: 'Service Principal Names', + allowedtodelegate: 'Allowed To Delegate', + sidhistory: 'SID History', + }; + + return objectId === null ? ( +
+ ) : ( +
+
+
{label || objectId}
+ + +
+ + + + (n:IPAUser {objectid: $objectid})' + } + end={label} + /> + (o2:IPAUser {objectid: $objectid}) WITH o1 OPTIONAL MATCH p1=(d)-[r2:Contains*1..]->(o1) OPTIONAL MATCH p2=(o1)-[r3:Contains]->(n) WHERE n:IPAUser OR n:Computer RETURN count(distinct(n))' + } + graphQuery={ + 'MATCH (o1)-[r1:Contains]->(o2:IPAUser {objectid: $objectid}) WITH o1 OPTIONAL MATCH p1=(d)-[r2:Contains*1..]->(o1) OPTIONAL MATCH p2=(o1)-[r3:Contains]->(n) WHERE n:IPAUser OR n:Computer RETURN p1,p2' + } + /> + (n)) WHERE NONE (r IN relationships(p) WHERE type(r)= "GetChanges") AND NONE (r in relationships(p) WHERE type(r)="GetChangesAll") AND NOT m=n' + } + start={label} + /> + (container1)-[r2:Contains*1..]->(c) OPTIONAL MATCH p2 = (g2:GPO)-[r3:GPLink {enforced:false}]->(container2)-[r4:Contains*1..]->(c) WHERE NONE (x in NODES(p2) WHERE x.blocksinheritance = true AND x:OU AND NOT (g2)-->(x)) WITH COLLECT(g1) + COLLECT(g2) AS tempVar UNWIND tempVar AS GPOs RETURN COUNT(DISTINCT(GPOs))' + } + graphQuery={ + 'MATCH (c:IPAUser {objectid: $objectid}) OPTIONAL MATCH p1 = (g1:GPO)-[r1:GPLink {enforced:true}]->(container1)-[r2:Contains*1..]->(c) OPTIONAL MATCH p2 = (g2:GPO)-[r3:GPLink {enforced:false}]->(container2)-[r4:Contains*1..]->(c) WHERE NONE (x in NODES(p2) WHERE x.blocksinheritance = true AND x:OU AND NOT (g2)-->(x)) RETURN p1,p2' + } + /> + + +
+
+
+ +
+ + + +
+ + + +
+ + +
+ + + + (n)' + } + start={label} + /> + (n:Group)' + } + start={label} + distinct + /> + (n)' + } + start={label} + domain={domain} + /> + +
+
+
+ +
+ + +
+ + + + (n:Computer)' + } + start={label} + distinct + /> + (g:Group)-[r2:AdminTo]->(n:Computer)' + } + start={label} + distinct + /> + (n:Computer))' + } + start={label} + distinct + /> + +
+
+
+ +
+ + +
+ + + + (n:Computer)' + } + start={label} + distinct + /> + (g:Group)-[r2:CanRDP]->(n:Computer)' + } + start={label} + distinct + /> + (n:Computer)' + } + start={label} + distinct + /> + (g:Group)-[r2:ExecuteDCOM]->(n:Computer)' + } + start={label} + distinct + /> + (n:Computer)' + } + start={label} + distinct + /> + (n:Computer)' + } + start={label} + distinct + /> + +
+
+
+ +
+ + +
+ + + + (n) WHERE r1.isacl=true' + } + end={label} + distinct + /> + (g:Group)-[r2]->(n) WHERE r2.isacl=true' + } + start={label} + distinct + /> + (n))' + } + start={label} + distinct + /> + +
+
+
+ +
+ + +
+ + + + (u1:IPAUser {objectid: $objectid}) WHERE r.isacl=true' + } + end={label} + distinct + /> + (g:Group)-[r1:AddMember|AddSelf|WriteSPN|AddKeyCredentialLink|AllExtendedRights|GenericAll|GenericWrite|WriteDacl|WriteOwner|Owns]->(u:IPAUser {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:IPAUser {objectid: $objectid}))' + } + end={label} + distinct + /> + +
+
+
+ + {/* + */} +
+
+ ); +}; + +IPAUserNodeData.propTypes = {}; +export default withAlert()(IPAUserNodeData); diff --git a/src/index.js b/src/index.js index 03e5815a4..7d182e6de 100644 --- a/src/index.js +++ b/src/index.js @@ -154,6 +154,18 @@ global.appStore = { scale: 1.25, color: '#7F72FD', }, + IPAUser: { + font: "'Font Awesome 5 Free'", + content: '\uf007', + scale: 1.5, + color: '#17B2E6', + }, + IPAComputer: { + font: "'Font Awesome 5 Free'", + content: '\uF108', + scale: 1.2, + color: '#171AE6', + }, AZUser: { font: "'Font Awesome 5 Free'", content: '\uf007', diff --git a/src/js/newingestion.js b/src/js/newingestion.js index 9e91bfddb..459d33981 100644 --- a/src/js/newingestion.js +++ b/src/js/newingestion.js @@ -22,6 +22,8 @@ export const ADLabels = { GPO: 'GPO', Domain: 'Domain', Container: 'Container', + IPAUser: 'IPAUser', + IPAHost: 'IPAHost', MemberOf: 'MemberOf', AllowedToDelegate: 'AllowedToDelegate', AllowedToAct: 'AllowedToAct', @@ -906,6 +908,236 @@ export function buildDomainJsonNew(chunk) { return queries; } +/** + * + * @param {Array.} chunk + * @returns {{}} + */ +export function buildIPAComputerJsonNew(chunk) { + let queries = {}; + queries.properties = {}; + queries.properties.statement = PROP_QUERY.format(ADLabels.IPAComputer); + queries.properties.props = []; + + for (let computer of chunk) { + let identifier = computer.ObjectIdentifier; + let properties = computer.Properties; + let localAdmins = computer.LocalAdmins.Results; + let rdp = computer.RemoteDesktopUsers.Results; + let dcom = computer.DcomUsers.Results; + let psremote = computer.PSRemoteUsers.Results; + let primaryGroup = computer.PrimaryGroupSID; + let allowedToAct = computer.AllowedToAct; + let allowedToDelegate = computer.AllowedToDelegate; + let sessions = computer.Sessions.Results; + let privSessions = computer.PrivilegedSessions.Results; + let regSessions = computer.RegistrySessions.Results; + let aces = computer.Aces; + let dumpSMSAPassword = computer.DumpSMSAPassword; + + queries.properties.props.push({ + objectid: identifier, + map: properties, + }); + + processAceArrayNew(aces, identifier, ADLabels.IPAComputer, queries); + + let format = [ + ADLabels.IPAComputer, + ADLabels.Group, + ADLabels.MemberOf, + NON_ACL_PROPS, + ]; + if (primaryGroup !== null) { + insertNew(queries, format, { + source: identifier, + target: primaryGroup, + }); + } + + format = [ + ADLabels.IPAComputer, + ADLabels.IPAComputer, + ADLabels.AllowedToDelegate, + NON_ACL_PROPS, + ]; + + let props = allowedToDelegate.map((delegate) => { + return { source: identifier, target: delegate.ObjectIdentifier }; + }); + + insertNew(queries, format, props); + + format = ['', ADLabels.IPAComputer, ADLabels.AllowedToAct, NON_ACL_PROPS]; + let grouped = groupBy(allowedToAct, GROUP_OBJECT_TYPE); + for (let objectType in grouped) { + format[0] = objectType; + props = grouped[objectType].map((principal) => { + return { + source: principal.ObjectIdentifier, + target: identifier, + }; + }); + insertNew(queries, format, props); + } + + format = [ + ADLabels.IPAComputer, + ADLabels.IPAUser, + ADLabels.DumpSMSAPassword, + NON_ACL_PROPS, + ]; + + if (dumpSMSAPassword === undefined) + dumpSMSAPassword = []; + + props = dumpSMSAPassword.map((principal) => { + return { source: identifier, target: principal.ObjectIdentifier }; + }); + + insertNew(queries, format, props); + + format = [ + ADLabels.IPAComputer, + ADLabels.IPAUser, + ADLabels.HasSession, + '{isacl:false, source:"netsessionenum"}', + ]; + props = sessions.map((session) => { + return { source: session.ComputerSID, target: session.UserSID }; + }); + insertNew(queries, format, props); + + format = [ + ADLabels.IPAComputer, + ADLabels.IPAUser, + ADLabels.HasSession, + '{isacl:false, source:"netwkstauserenum"}', + ]; + props = privSessions.map((session) => { + return { source: session.ComputerSID, target: session.UserSID }; + }); + insertNew(queries, format, props); + + format = [ + ADLabels.IPAComputer, + ADLabels.IPAUser, + ADLabels.HasSession, + '{isacl:false, source:"registry"}', + ]; + props = regSessions.map((session) => { + return { source: session.ComputerSID, target: session.UserSID }; + }); + insertNew(queries, format, props); + + format = [ + '', + ADLabels.IPAComputer, + ADLabels.AdminTo, + '{isacl:false, fromgpo: false}', + ]; + grouped = groupBy(localAdmins, GROUP_OBJECT_TYPE); + for (let objectType in grouped) { + format[0] = objectType; + props = grouped[objectType].map((principal) => { + return { + source: principal.ObjectIdentifier, + target: identifier, + }; + }); + insertNew(queries, format, props); + } + + format = [ + '', + ADLabels.IPAComputer, + ADLabels.CanRDP, + '{isacl:false, fromgpo: false}', + ]; + grouped = groupBy(rdp, GROUP_OBJECT_TYPE); + for (let objectType in grouped) { + format[0] = objectType; + props = grouped[objectType].map((principal) => { + return { + source: principal.ObjectIdentifier, + target: identifier, + }; + }); + insertNew(queries, format, props); + } + + format = [ + '', + ADLabels.IPAComputer, + ADLabels.ExecuteDCOM, + '{isacl:false, fromgpo: false}', + ]; + grouped = groupBy(dcom, GROUP_OBJECT_TYPE); + for (let objectType in grouped) { + format[0] = objectType; + props = grouped[objectType].map((principal) => { + return { + source: principal.ObjectIdentifier, + target: identifier, + }; + }); + insertNew(queries, format, props); + } + + format = [ + '', + ADLabels.IPAComputer, + ADLabels.CanPSRemote, + '{isacl:false, fromgpo: false}', + ]; + grouped = groupBy(psremote || [], GROUP_OBJECT_TYPE); + for (let objectType in grouped) { + format[0] = objectType; + props = grouped[objectType].map((principal) => { + return { + source: principal.ObjectIdentifier, + target: identifier, + }; + }); + insertNew(queries, format, props); + } + } + return queries; +} + +/** + * + * @param {Array.}chunk + * @return {{}} + */ +export function buildIPAUserJsonNew(chunk) { + let queries = {}; + queries.properties = { + statement: PROP_QUERY.format(ADLabels.IPAUser), + props: [], + }; + + for (let user of chunk) { + let properties = user.Properties; + let ipantsecurityidentifier = user.ipantsecurityidentifier; + //let identifier = user.ObjectIdentifier; + //let primaryGroup = user.PrimaryGroupSID; + //let allowedToDelegate = user.AllowedToDelegate; + //let spnTargets = user.SPNTargets; + //let sidHistory = user.HasSIDHistory; + let aces = user.Aces; + + processAceArrayNew(aces, ipantsecurityidentifier, ADLabels.IPAUser, queries); + + queries.properties.props.push({ + objectid: ipantsecurityidentifier, + map: properties, + }); + + } + return queries; +} + const baseInsertStatement = 'UNWIND $props AS prop MERGE (n:Base {objectid: prop.source}) SET n:{0} MERGE (m:Base {objectid: prop.target}) SET m:{1} MERGE (n)-[r:{2} {3}]->(m)'; From 859d8970ce143937039e6f58b17c6c78cd17a126 Mon Sep 17 00:00:00 2001 From: DrieVlad Date: Wed, 2 Oct 2024 18:30:48 +0500 Subject: [PATCH 2/2] Created hosts edges --- src/components/Menu/MenuContainer.jsx | 2 +- src/components/SearchContainer/SearchRow.jsx | 2 +- .../SearchContainer/TabContainer.jsx | 12 +- .../SearchContainer/Tabs/IPAHostNodeData.jsx | 82 ++++---- src/index.js | 2 +- src/js/newingestion.js | 198 ++---------------- 6 files changed, 70 insertions(+), 228 deletions(-) diff --git a/src/components/Menu/MenuContainer.jsx b/src/components/Menu/MenuContainer.jsx index e3c427abc..f2ea11876 100644 --- a/src/components/Menu/MenuContainer.jsx +++ b/src/components/Menu/MenuContainer.jsx @@ -37,7 +37,7 @@ const IngestFuncMap = { ous: NewIngestion.buildOuJsonNew, gpos: NewIngestion.buildGpoJsonNew, containers: NewIngestion.buildContainerJsonNew, - IPAcomputers: NewIngestion.buildIPAComputerJsonNew, + IPAhosts: NewIngestion.buildIPAHostJsonNew, IPAusers: NewIngestion.buildIPAUserJsonNew, azure: NewIngestion.convertAzureData, }; diff --git a/src/components/SearchContainer/SearchRow.jsx b/src/components/SearchContainer/SearchRow.jsx index 6f75061d4..f4ab824e8 100644 --- a/src/components/SearchContainer/SearchRow.jsx +++ b/src/components/SearchContainer/SearchRow.jsx @@ -49,7 +49,7 @@ const SearchRow = ({ item, search }) => { case 'IPAUser': icon.className = 'fa fa-user'; break; - case 'IPAComputer': + case 'IPAHost': icon.className = 'fa fa-desktop'; break; case 'AZUser': diff --git a/src/components/SearchContainer/TabContainer.jsx b/src/components/SearchContainer/TabContainer.jsx index dd167d3ad..821c25bcc 100644 --- a/src/components/SearchContainer/TabContainer.jsx +++ b/src/components/SearchContainer/TabContainer.jsx @@ -9,7 +9,7 @@ import DomainNodeData from './Tabs/DomainNodeData'; import GpoNodeData from './Tabs/GPONodeData'; import OuNodeData from './Tabs/OUNodeData'; import IPAUserNodeData from './Tabs/IPAUserNodeData'; -import IPAComputerNodeData from './Tabs/IPAHostNodeData'; +import IPAHostNodeData from './Tabs/IPAHostNodeData'; import AZGroupNodeData from './Tabs/AZGroupNodeData'; import AZUserNodeData from './Tabs/AZUserNodeData'; import AZContainerRegistryNodeData from './Tabs/AZContainerRegistryNodeData'; @@ -52,7 +52,7 @@ class TabContainer extends Component { ouVisible: false, containerVisible: false, IPAuserVisible: false, - IPAcomputerVisible: false, + IPAhostVisible: false, azGroupVisible: false, azUserVisible: false, azContainerRegistryVisible: false, @@ -98,7 +98,7 @@ class TabContainer extends Component { this._ouNodeClicked(); } else if (type === 'GPO') { this._gpoNodeClicked(); - } else if (type === 'IPAComputer') { + } else if (type === 'IPAHost') { this._computerNodeClicked(); } else if (type === 'IPAUser') { this._computerNodeClicked(); @@ -242,7 +242,7 @@ class TabContainer extends Component { }); } - _IPAcomputerNodeClicked() { + _IPAhostNodeClicked() { this.clearVisible() this.setState({ computerVisible: true, @@ -431,7 +431,7 @@ class TabContainer extends Component { !this.state.gpoVisible && !this.state.ouVisible && !this.state.IPAuserVisible && - !this.state.IPAcomputerVisible && + !this.state.IPAhostVisible && !this.state.azGroupVisible && !this.state.azUserVisible && !this.state.azContainerRegistryVisible && @@ -464,7 +464,7 @@ class TabContainer extends Component { - + diff --git a/src/components/SearchContainer/Tabs/IPAHostNodeData.jsx b/src/components/SearchContainer/Tabs/IPAHostNodeData.jsx index 6c987137c..4b30930b6 100644 --- a/src/components/SearchContainer/Tabs/IPAHostNodeData.jsx +++ b/src/components/SearchContainer/Tabs/IPAHostNodeData.jsx @@ -11,7 +11,7 @@ import { Table } from 'react-bootstrap'; import styles from './NodeData.module.css'; import { AppContext } from '../../../AppContext'; -const IPAComputerNodeData = () => { +const IPAHostNodeData = () => { const [visible, setVisible] = useState(false); const [objectid, setObjectid] = useState(null); const [label, setLabel] = useState(null); @@ -28,14 +28,14 @@ const IPAComputerNodeData = () => { }, []); const nodeClickEvent = (type, id, blocksinheritance, domain) => { - if (type === 'IPAComputer') { + if (type === 'IPAHost') { setVisible(true); setObjectid(id); setDomain(domain); let session = driver.session(); session .run( - `MATCH (n:IPAComputer {objectid: $objectid}) RETURN n AS node`, + `MATCH (n:IPAHost {objectid: $objectid}) RETURN n AS node`, { objectid: id, } @@ -85,7 +85,7 @@ const IPAComputerNodeData = () => { property='Sessions' target={objectid} baseQuery={ - "MATCH p=(m:IPAComputer {objectid: $objectid})-[r:HasSession]->(n:User) WHERE NOT n.objectid ENDS WITH '$'" + "MATCH p=(m:IPAHost {objectid: $objectid})-[r:HasSession]->(n:User) WHERE NOT n.objectid ENDS WITH '$'" } start={label} distinct @@ -94,7 +94,7 @@ const IPAComputerNodeData = () => { property='Reachable High Value Targets' target={objectid} baseQuery={ - 'MATCH (m:IPAComputer {objectid: $objectid}),(n {highvalue:true}),p=shortestPath((m)-[r*1..]->(n)) WHERE NONE (r IN relationships(p) WHERE type(r)= "GetChanges") AND NONE (r in relationships(p) WHERE type(r)="GetChangesAll") AND NOT m=n' + 'MATCH (m:IPAHost {objectid: $objectid}),(n {highvalue:true}),p=shortestPath((m)-[r*1..]->(n)) WHERE NONE (r IN relationships(p) WHERE type(r)= "GetChanges") AND NONE (r in relationships(p) WHERE type(r)="GetChangesAll") AND NOT m=n' } start={label} /> @@ -102,26 +102,26 @@ const IPAComputerNodeData = () => { property='Sibling Objects in the Same OU' target={objectid} countQuery={ - 'MATCH (o1)-[r1:Contains]->(o2:IPAComputer {objectid: $objectid}) WITH o1 OPTIONAL MATCH p1=(d)-[r2:Contains*1..]->(o1) OPTIONAL MATCH p2=(o1)-[r3:Contains]->(n) WHERE n:User OR n:IPAComputer RETURN count(distinct(n))' + 'MATCH (o1)-[r1:Contains]->(o2:IPAHost {objectid: $objectid}) WITH o1 OPTIONAL MATCH p1=(d)-[r2:Contains*1..]->(o1) OPTIONAL MATCH p2=(o1)-[r3:Contains]->(n) WHERE n:User OR n:IPAHost RETURN count(distinct(n))' } graphQuery={ - 'MATCH (o1)-[r1:Contains]->(o2:IPAComputer {objectid: $objectid}) WITH o1 OPTIONAL MATCH p1=(d)-[r2:Contains*1..]->(o1) OPTIONAL MATCH p2=(o1)-[r3:Contains]->(n) WHERE n:User OR n:IPAComputer RETURN p1,p2' + 'MATCH (o1)-[r1:Contains]->(o2:IPAHost {objectid: $objectid}) WITH o1 OPTIONAL MATCH p1=(d)-[r2:Contains*1..]->(o1) OPTIONAL MATCH p2=(o1)-[r3:Contains]->(n) WHERE n:User OR n:IPAHost RETURN p1,p2' } /> (container1)-[r2:Contains*1..]->(c) OPTIONAL MATCH p2 = (g2:GPO)-[r3:GPLink {enforced:false}]->(container2)-[r4:Contains*1..]->(c) WHERE NONE (x in NODES(p2) WHERE x.blocksinheritance = true AND x:OU AND NOT (g2)-->(x)) WITH COLLECT(g1) + COLLECT(g2) AS tempVar UNWIND tempVar AS GPOs RETURN COUNT(DISTINCT(GPOs))' + 'MATCH (c:IPAHost {objectid: $objectid}) OPTIONAL MATCH p1 = (g1:GPO)-[r1:GPLink {enforced:true}]->(container1)-[r2:Contains*1..]->(c) OPTIONAL MATCH p2 = (g2:GPO)-[r3:GPLink {enforced:false}]->(container2)-[r4:Contains*1..]->(c) WHERE NONE (x in NODES(p2) WHERE x.blocksinheritance = true AND x:OU AND NOT (g2)-->(x)) WITH COLLECT(g1) + COLLECT(g2) AS tempVar UNWIND tempVar AS GPOs RETURN COUNT(DISTINCT(GPOs))' } graphQuery={ - 'MATCH (c:IPAComputer {objectid: $objectid}) OPTIONAL MATCH p1 = (g1:GPO)-[r1:GPLink {enforced:true}]->(container1)-[r2:Contains*1..]->(c) OPTIONAL MATCH p2 = (g2:GPO)-[r3:GPLink {enforced:false}]->(container2)-[r4:Contains*1..]->(c) WHERE NONE (x in NODES(p2) WHERE x.blocksinheritance = true AND x:OU AND NOT (g2)-->(x)) RETURN p1,p2' + 'MATCH (c:IPAHost {objectid: $objectid}) OPTIONAL MATCH p1 = (g1:GPO)-[r1:GPLink {enforced:true}]->(container1)-[r2:Contains*1..]->(c) OPTIONAL MATCH p2 = (g2:GPO)-[r3:GPLink {enforced:false}]->(container2)-[r4:Contains*1..]->(c) WHERE NONE (x in NODES(p2) WHERE x.blocksinheritance = true AND x:OU AND NOT (g2)-->(x)) RETURN p1,p2' } /> @@ -148,7 +148,7 @@ const IPAComputerNodeData = () => { property='Explicit Admins' target={objectid} baseQuery={ - 'MATCH p=(n)-[b:AdminTo]->(c:IPAComputer {objectid: $objectid})' + 'MATCH p=(n)-[b:AdminTo]->(c:IPAHost {objectid: $objectid})' } end={label} /> @@ -156,7 +156,7 @@ const IPAComputerNodeData = () => { property='Unrolled Admins' target={objectid} baseQuery={ - 'MATCH p=(n)-[r:MemberOf|AdminTo*1..]->(m:IPAComputer {objectid: $objectid}) WHERE NOT n:Group' + 'MATCH p=(n)-[r:MemberOf|AdminTo*1..]->(m:IPAHost {objectid: $objectid}) WHERE NOT n:Group' } end={label} distinct @@ -165,17 +165,17 @@ const IPAComputerNodeData = () => { property='Foreign Admins' target={objectid} countQuery={ - 'MATCH (c:IPAComputer {objectid: $objectid}) OPTIONAL MATCH (u1)-[:AdminTo]->(c) WHERE NOT u1.domain = c.domain WITH u1,c OPTIONAL MATCH (u2)-[:MemberOf*1..]->(:Group)-[:AdminTo]->(c) WHERE NOT u2.domain = c.domain WITH COLLECT(u1) + COLLECT(u2) as tempVar,c UNWIND tempVar as principals RETURN COUNT(DISTINCT(principals))' + 'MATCH (c:IPAHost {objectid: $objectid}) OPTIONAL MATCH (u1)-[:AdminTo]->(c) WHERE NOT u1.domain = c.domain WITH u1,c OPTIONAL MATCH (u2)-[:MemberOf*1..]->(:Group)-[:AdminTo]->(c) WHERE NOT u2.domain = c.domain WITH COLLECT(u1) + COLLECT(u2) as tempVar,c UNWIND tempVar as principals RETURN COUNT(DISTINCT(principals))' } graphQuery={ - 'MATCH (c:IPAComputer {objectid: $objectid}) OPTIONAL MATCH p1 = (u1)-[:AdminTo]->(c) WHERE NOT u1.domain = c.domain WITH p1,c OPTIONAL MATCH p2 = (u2)-[:MemberOf*1..]->(:Group)-[:AdminTo]->(c) WHERE NOT u2.domain = c.domain RETURN p1,p2' + 'MATCH (c:IPAHost {objectid: $objectid}) OPTIONAL MATCH p1 = (u1)-[:AdminTo]->(c) WHERE NOT u1.domain = c.domain WITH p1,c OPTIONAL MATCH p2 = (u2)-[:MemberOf*1..]->(:Group)-[:AdminTo]->(c) WHERE NOT u2.domain = c.domain RETURN p1,p2' } /> (m:IPAComputer {objectid: $objectid}))' + 'MATCH (n) WHERE NOT n.objectid=$objectid WITH n MATCH p = shortestPath((n)-[r:AdminTo|MemberOf|HasSession*1..]->(m:IPAHost {objectid: $objectid}))' } end={label} distinct @@ -194,7 +194,7 @@ const IPAComputerNodeData = () => { property='First Degree Remote Desktop Users' target={objectid} baseQuery={ - 'MATCH p=(n)-[r:CanRDP]->(m:IPAComputer {objectid: $objectid})' + 'MATCH p=(n)-[r:CanRDP]->(m:IPAHost {objectid: $objectid})' } end={label} distinct @@ -203,7 +203,7 @@ const IPAComputerNodeData = () => { property='Group Delegated Remote Desktop Users' target={objectid} baseQuery={ - 'MATCH p=(n)-[r1:MemberOf*1..]->(g:Group)-[r:CanRDP]->(m:IPAComputer {objectid: $objectid})' + 'MATCH p=(n)-[r1:MemberOf*1..]->(g:Group)-[r:CanRDP]->(m:IPAHost {objectid: $objectid})' } end={label} distinct @@ -212,7 +212,7 @@ const IPAComputerNodeData = () => { property='First Degree Distributed COM Users' target={objectid} baseQuery={ - 'MATCH p=(n)-[r:ExecuteDCOM]->(m:IPAComputer {objectid: $objectid})' + 'MATCH p=(n)-[r:ExecuteDCOM]->(m:IPAHost {objectid: $objectid})' } end={label} distinct @@ -221,7 +221,7 @@ const IPAComputerNodeData = () => { property='Group Delegated Distributed COM Users' target={objectid} baseQuery={ - 'MATCH p=(n)-[r1:MemberOf*1..]->(g:Group)-[r:ExecuteDCOM]->(m:IPAComputer {objectid: $objectid})' + 'MATCH p=(n)-[r1:MemberOf*1..]->(g:Group)-[r:ExecuteDCOM]->(m:IPAHost {objectid: $objectid})' } end={label} distinct @@ -230,7 +230,7 @@ const IPAComputerNodeData = () => { property='SQL Admins' target={objectid} baseQuery={ - 'MATCH p=(n:User)-[r:SQLAdmin]->(m:IPAComputer {objectid: $objectid})' + 'MATCH p=(n:User)-[r:SQLAdmin]->(m:IPAHost {objectid: $objectid})' } start={label} distinct @@ -249,7 +249,7 @@ const IPAComputerNodeData = () => { property='First Degree Group Membership' target={objectid} baseQuery={ - 'MATCH (m:IPAComputer {objectid: $objectid}),(n:Group), p=(m)-[r:MemberOf]->(n)' + 'MATCH (m:IPAHost {objectid: $objectid}),(n:Group), p=(m)-[r:MemberOf]->(n)' } start={label} /> @@ -257,7 +257,7 @@ const IPAComputerNodeData = () => { property='Unrolled Group Membership' target={objectid} baseQuery={ - 'MATCH p=(c:IPAComputer {objectid: $objectid})-[r:MemberOf*1..]->(n:Group)' + 'MATCH p=(c:IPAHost {objectid: $objectid})-[r:MemberOf*1..]->(n:Group)' } start={label} distinct @@ -266,7 +266,7 @@ const IPAComputerNodeData = () => { property='Foreign Group Membership' target={objectid} baseQuery={ - 'MATCH p=(c:IPAComputer {objectid: $objectid})-[r:MemberOf*1..]->(n:Group) WHERE NOT n.domain = c.domain' + 'MATCH p=(c:IPAHost {objectid: $objectid})-[r:MemberOf*1..]->(n:Group) WHERE NOT n.domain = c.domain' } start={label} distinct @@ -285,7 +285,7 @@ const IPAComputerNodeData = () => { property='First Degree Local Admin' target={objectid} baseQuery={ - 'MATCH (m:IPAComputer {objectid: $objectid}), (n:IPAComputer), p=(m)-[r:AdminTo]->(n)' + 'MATCH (m:IPAHost {objectid: $objectid}), (n:IPAHost), p=(m)-[r:AdminTo]->(n)' } start={label} distinct @@ -294,7 +294,7 @@ const IPAComputerNodeData = () => { property='Group Delegated Local Admin' target={objectid} baseQuery={ - 'MATCH p=(m:IPAComputer {objectid: $objectid})-[r1:MemberOf*1..]->(g:Group)-[r2:AdminTo]->(n:IPAComputer) WHERE NOT n.objectid=$objectid' + 'MATCH p=(m:IPAHost {objectid: $objectid})-[r1:MemberOf*1..]->(g:Group)-[r2:AdminTo]->(n:IPAHost) WHERE NOT n.objectid=$objectid' } start={label} distinct @@ -303,7 +303,7 @@ const IPAComputerNodeData = () => { property='Derivative Local Admin' target={objectid} baseQuery={ - 'MATCH (m:IPAComputer {objectid: $objectid}), (n:IPAComputer) WHERE NOT n.objectid=$objectid MATCH p=shortestPath((m)-[r:AdminTo|MemberOf*1..]->(n))' + 'MATCH (m:IPAHost {objectid: $objectid}), (n:IPAHost) WHERE NOT n.objectid=$objectid MATCH p=shortestPath((m)-[r:AdminTo|MemberOf*1..]->(n))' } start={label} distinct @@ -322,7 +322,7 @@ const IPAComputerNodeData = () => { property='First Degree RDP Privileges' target={objectid} baseQuery={ - 'MATCH p=(m:IPAComputer {objectid: $objectid})-[r:CanRDP]->(n:IPAComputer)' + 'MATCH p=(m:IPAHost {objectid: $objectid})-[r:CanRDP]->(n:IPAHost)' } start={label} distinct @@ -331,7 +331,7 @@ const IPAComputerNodeData = () => { property='Group Delegated RDP Privileges' target={objectid} baseQuery={ - 'MATCH p=(m:IPAComputer {objectid: $objectid})-[r1:MemberOf*1..]->(g:Group)-[r2:CanRDP]->(n:IPAComputer)' + 'MATCH p=(m:IPAHost {objectid: $objectid})-[r1:MemberOf*1..]->(g:Group)-[r2:CanRDP]->(n:IPAHost)' } start={label} distinct @@ -340,7 +340,7 @@ const IPAComputerNodeData = () => { property='First Degree DCOM Privileges' target={objectid} baseQuery={ - 'MATCH p=(m:IPAComputer {objectid: $objectid})-[r:ExecuteDCOM]->(n:IPAComputer)' + 'MATCH p=(m:IPAHost {objectid: $objectid})-[r:ExecuteDCOM]->(n:IPAHost)' } start={label} distinct @@ -349,7 +349,7 @@ const IPAComputerNodeData = () => { property='Group Delegated DCOM Privileges' target={objectid} baseQuery={ - 'MATCH p=(m:IPAComputer {objectid: $objectid})-[r1:MemberOf*1..]->(g:Group)-[r2:ExecuteDCOM]->(n:IPAComputer)' + 'MATCH p=(m:IPAHost {objectid: $objectid})-[r1:MemberOf*1..]->(g:Group)-[r2:ExecuteDCOM]->(n:IPAHost)' } start={label} distinct @@ -358,7 +358,7 @@ const IPAComputerNodeData = () => { property='Constrained Delegation Privileges' target={objectid} baseQuery={ - 'MATCH p=(m:IPAComputer {objectid: $objectid})-[r:AllowedToDelegate]->(n:IPAComputer)' + 'MATCH p=(m:IPAHost {objectid: $objectid})-[r:AllowedToDelegate]->(n:IPAHost)' } start={label} distinct @@ -377,7 +377,7 @@ const IPAComputerNodeData = () => { property='Explicit Object Controllers' target={objectid} baseQuery={ - 'MATCH p=(n)-[r]->(u1:IPAComputer {objectid:$objectid}) WHERE r.isacl=true' + 'MATCH p=(n)-[r]->(u1:IPAHost {objectid:$objectid}) WHERE r.isacl=true' } end={label} distinct @@ -386,7 +386,7 @@ const IPAComputerNodeData = () => { property='Unrolled Object Controllers' target={objectid} baseQuery={ - 'MATCH p=(n)-[r:MemberOf*1..]->(g:Group)-[r1:AddMember|AddSelf|WriteSPN|AddKeyCredentialLink|AllExtendedRights|GenericAll|GenericWrite|WriteDacl|WriteOwner|Owns]->(u:IPAComputer {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:AddMember|AddSelf|WriteSPN|AddKeyCredentialLink|AllExtendedRights|GenericAll|GenericWrite|WriteDacl|WriteOwner|Owns]->(u:IPAHost {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 @@ -395,7 +395,7 @@ const IPAComputerNodeData = () => { property='Transitive Object Controllers' target={objectid} baseQuery={ - 'MATCH (n) WHERE NOT n.objectid=$objectid WITH n MATCH p = shortestPath((n)-[r1:MemberOf|AllExtendedRights|AddSelf|WriteSPN|AddKeyCredentialLink|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner*1..]->(u1:IPAComputer {objectid:$objectid}))' + 'MATCH (n) WHERE NOT n.objectid=$objectid WITH n MATCH p = shortestPath((n)-[r1:MemberOf|AllExtendedRights|AddSelf|WriteSPN|AddKeyCredentialLink|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner*1..]->(u1:IPAHost {objectid:$objectid}))' } end={label} distinct @@ -414,7 +414,7 @@ const IPAComputerNodeData = () => { property='First Degree Object Control' target={objectid} baseQuery={ - 'MATCH p = (c:IPAComputer {objectid: $objectid})-[r]->(n) WHERE r.isacl=true' + 'MATCH p = (c:IPAHost {objectid: $objectid})-[r]->(n) WHERE r.isacl=true' } start={label} distinct @@ -423,7 +423,7 @@ const IPAComputerNodeData = () => { property='Group Delegated Object Control' target={objectid} baseQuery={ - 'MATCH p = (c:IPAComputer {objectid: $objectid})-[r1:MemberOf*1..]->(g:Group)-[r2]->(n) WHERE r2.isacl=true' + 'MATCH p = (c:IPAHost {objectid: $objectid})-[r1:MemberOf*1..]->(g:Group)-[r2]->(n) WHERE r2.isacl=true' } start={label} distinct @@ -432,7 +432,7 @@ const IPAComputerNodeData = () => { property='Transitive Object Control' target={objectid} baseQuery={ - 'MATCH (n) WHERE NOT n.objectid=$objectid WITH n MATCH p = shortestPath((c:IPAComputer {objectid: $objectid})-[r:MemberOf|AddMember|AddSelf|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner|Owns*1..]->(n))' + 'MATCH (n) WHERE NOT n.objectid=$objectid WITH n MATCH p = shortestPath((c:IPAHost {objectid: $objectid})-[r:MemberOf|AddMember|AddSelf|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner|Owns*1..]->(n))' } start={label} distinct @@ -441,10 +441,10 @@ const IPAComputerNodeData = () => { - {/* + {/* */} @@ -452,5 +452,5 @@ const IPAComputerNodeData = () => { ); }; -IPAComputerNodeData.propTypes = {}; -export default IPAComputerNodeData; +IPAHostNodeData.propTypes = {}; +export default IPAHostNodeData; diff --git a/src/index.js b/src/index.js index 7d182e6de..323f90f22 100644 --- a/src/index.js +++ b/src/index.js @@ -160,7 +160,7 @@ global.appStore = { scale: 1.5, color: '#17B2E6', }, - IPAComputer: { + IPAHost: { font: "'Font Awesome 5 Free'", content: '\uF108', scale: 1.2, diff --git a/src/js/newingestion.js b/src/js/newingestion.js index 459d33981..e79cf047b 100644 --- a/src/js/newingestion.js +++ b/src/js/newingestion.js @@ -910,197 +910,39 @@ export function buildDomainJsonNew(chunk) { /** * - * @param {Array.} chunk + * @param {Array.} chunk * @returns {{}} */ -export function buildIPAComputerJsonNew(chunk) { +export function buildIPAHostJsonNew(chunk) { let queries = {}; queries.properties = {}; - queries.properties.statement = PROP_QUERY.format(ADLabels.IPAComputer); + queries.properties.statement = PROP_QUERY.format(ADLabels.IPAHost); queries.properties.props = []; for (let computer of chunk) { - let identifier = computer.ObjectIdentifier; + let ipauniqueid = computer.ipauniqueid; let properties = computer.Properties; - let localAdmins = computer.LocalAdmins.Results; - let rdp = computer.RemoteDesktopUsers.Results; - let dcom = computer.DcomUsers.Results; - let psremote = computer.PSRemoteUsers.Results; - let primaryGroup = computer.PrimaryGroupSID; - let allowedToAct = computer.AllowedToAct; - let allowedToDelegate = computer.AllowedToDelegate; - let sessions = computer.Sessions.Results; - let privSessions = computer.PrivilegedSessions.Results; - let regSessions = computer.RegistrySessions.Results; + //let localAdmins = computer.LocalAdmins.Results; + //let rdp = computer.RemoteDesktopUsers.Results; + //let dcom = computer.DcomUsers.Results; + //let psremote = computer.PSRemoteUsers.Results; + //let primaryGroup = computer.PrimaryGroupSID; + //let allowedToAct = computer.AllowedToAct; + //let allowedToDelegate = computer.AllowedToDelegate; + //let sessions = computer.Sessions.Results; + //let privSessions = computer.PrivilegedSessions.Results; + //let regSessions = computer.RegistrySessions.Results; let aces = computer.Aces; - let dumpSMSAPassword = computer.DumpSMSAPassword; + //let dumpSMSAPassword = computer.DumpSMSAPassword; queries.properties.props.push({ - objectid: identifier, + objectid: ipauniqueid, map: properties, }); - processAceArrayNew(aces, identifier, ADLabels.IPAComputer, queries); - - let format = [ - ADLabels.IPAComputer, - ADLabels.Group, - ADLabels.MemberOf, - NON_ACL_PROPS, - ]; - if (primaryGroup !== null) { - insertNew(queries, format, { - source: identifier, - target: primaryGroup, - }); - } - - format = [ - ADLabels.IPAComputer, - ADLabels.IPAComputer, - ADLabels.AllowedToDelegate, - NON_ACL_PROPS, - ]; - - let props = allowedToDelegate.map((delegate) => { - return { source: identifier, target: delegate.ObjectIdentifier }; - }); - - insertNew(queries, format, props); - - format = ['', ADLabels.IPAComputer, ADLabels.AllowedToAct, NON_ACL_PROPS]; - let grouped = groupBy(allowedToAct, GROUP_OBJECT_TYPE); - for (let objectType in grouped) { - format[0] = objectType; - props = grouped[objectType].map((principal) => { - return { - source: principal.ObjectIdentifier, - target: identifier, - }; - }); - insertNew(queries, format, props); - } - - format = [ - ADLabels.IPAComputer, - ADLabels.IPAUser, - ADLabels.DumpSMSAPassword, - NON_ACL_PROPS, - ]; - - if (dumpSMSAPassword === undefined) - dumpSMSAPassword = []; - - props = dumpSMSAPassword.map((principal) => { - return { source: identifier, target: principal.ObjectIdentifier }; - }); - - insertNew(queries, format, props); + processAceArrayNew(aces, ipauniqueid, ADLabels.IPAHost, queries); - format = [ - ADLabels.IPAComputer, - ADLabels.IPAUser, - ADLabels.HasSession, - '{isacl:false, source:"netsessionenum"}', - ]; - props = sessions.map((session) => { - return { source: session.ComputerSID, target: session.UserSID }; - }); - insertNew(queries, format, props); - format = [ - ADLabels.IPAComputer, - ADLabels.IPAUser, - ADLabels.HasSession, - '{isacl:false, source:"netwkstauserenum"}', - ]; - props = privSessions.map((session) => { - return { source: session.ComputerSID, target: session.UserSID }; - }); - insertNew(queries, format, props); - - format = [ - ADLabels.IPAComputer, - ADLabels.IPAUser, - ADLabels.HasSession, - '{isacl:false, source:"registry"}', - ]; - props = regSessions.map((session) => { - return { source: session.ComputerSID, target: session.UserSID }; - }); - insertNew(queries, format, props); - - format = [ - '', - ADLabels.IPAComputer, - ADLabels.AdminTo, - '{isacl:false, fromgpo: false}', - ]; - grouped = groupBy(localAdmins, GROUP_OBJECT_TYPE); - for (let objectType in grouped) { - format[0] = objectType; - props = grouped[objectType].map((principal) => { - return { - source: principal.ObjectIdentifier, - target: identifier, - }; - }); - insertNew(queries, format, props); - } - - format = [ - '', - ADLabels.IPAComputer, - ADLabels.CanRDP, - '{isacl:false, fromgpo: false}', - ]; - grouped = groupBy(rdp, GROUP_OBJECT_TYPE); - for (let objectType in grouped) { - format[0] = objectType; - props = grouped[objectType].map((principal) => { - return { - source: principal.ObjectIdentifier, - target: identifier, - }; - }); - insertNew(queries, format, props); - } - - format = [ - '', - ADLabels.IPAComputer, - ADLabels.ExecuteDCOM, - '{isacl:false, fromgpo: false}', - ]; - grouped = groupBy(dcom, GROUP_OBJECT_TYPE); - for (let objectType in grouped) { - format[0] = objectType; - props = grouped[objectType].map((principal) => { - return { - source: principal.ObjectIdentifier, - target: identifier, - }; - }); - insertNew(queries, format, props); - } - - format = [ - '', - ADLabels.IPAComputer, - ADLabels.CanPSRemote, - '{isacl:false, fromgpo: false}', - ]; - grouped = groupBy(psremote || [], GROUP_OBJECT_TYPE); - for (let objectType in grouped) { - format[0] = objectType; - props = grouped[objectType].map((principal) => { - return { - source: principal.ObjectIdentifier, - target: identifier, - }; - }); - insertNew(queries, format, props); - } } return queries; } @@ -1119,7 +961,7 @@ export function buildIPAUserJsonNew(chunk) { for (let user of chunk) { let properties = user.Properties; - let ipantsecurityidentifier = user.ipantsecurityidentifier; + let ipauniqueid = user.ipauniqueid; //let identifier = user.ObjectIdentifier; //let primaryGroup = user.PrimaryGroupSID; //let allowedToDelegate = user.AllowedToDelegate; @@ -1127,10 +969,10 @@ export function buildIPAUserJsonNew(chunk) { //let sidHistory = user.HasSIDHistory; let aces = user.Aces; - processAceArrayNew(aces, ipantsecurityidentifier, ADLabels.IPAUser, queries); + processAceArrayNew(aces, ipauniqueid, ADLabels.IPAUser, queries); queries.properties.props.push({ - objectid: ipantsecurityidentifier, + objectid: ipauniqueid, map: properties, });