diff --git a/cmd/api/src/daemons/datapipe/convertors.go b/cmd/api/src/daemons/datapipe/convertors.go index 5c9a6e32f2..5832b9afa9 100644 --- a/cmd/api/src/daemons/datapipe/convertors.go +++ b/cmd/api/src/daemons/datapipe/convertors.go @@ -24,7 +24,7 @@ import ( ) func convertComputerData(computer ein.Computer, converted *ConvertedData) { - baseNodeProp := ein.ConvertObjectToNode(computer.IngestBase, ad.Computer) + baseNodeProp := ein.ConvertComputerToNode(computer, ad.Computer) converted.RelProps = append(converted.RelProps, ein.ParseACEData(baseNodeProp, computer.Aces, computer.ObjectIdentifier, ad.Computer)...) if primaryGroupRel := ein.ParsePrimaryGroup(computer.IngestBase, ad.Computer, computer.PrimaryGroupSID); primaryGroupRel.IsValid() { converted.RelProps = append(converted.RelProps, primaryGroupRel) diff --git a/cmd/ui/src/queryClient.ts b/cmd/ui/src/queryClient.ts index 0fd037d304..fd4470dcef 100644 --- a/cmd/ui/src/queryClient.ts +++ b/cmd/ui/src/queryClient.ts @@ -1,3 +1,19 @@ +// Copyright 2025 Specter Ops, Inc. +// +// Licensed under the Apache License, Version 2.0 +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 + import { QueryClient } from 'react-query'; export const queryClient = new QueryClient(); diff --git a/packages/go/ein/ad.go b/packages/go/ein/ad.go index 918eb2f1b4..4f177ee897 100644 --- a/packages/go/ein/ad.go +++ b/packages/go/ein/ad.go @@ -56,6 +56,44 @@ func ConvertObjectToNode(item IngestBase, itemType graph.Kind) IngestibleNode { } } +func ConvertComputerToNode(item Computer, itemType graph.Kind) IngestibleNode { + itemProps := item.Properties + if itemProps == nil { + itemProps = make(map[string]any) + } + + convertOwnsEdgeToProperty(item.IngestBase, itemProps) + + if item.IsWebClientRunning.Collected { + itemProps[ad.WebClientRunning.String()] = item.IsWebClientRunning.Result + } + + if item.SmbInfo.Collected { + itemProps[ad.SMBSigning.String()] = item.SmbInfo.SigningEnabled + } + + if item.RegistryData.Collected { + /* + RestrictSendingNtlmTraffic is sent to us as an uint + The possible values are + 0: Allow All + 1: Audit All + 2: Deny All + */ + if item.RegistryData.RestrictSendingNtlmTraffic == 0 { + itemProps[ad.RestrictOutboundNTLM.String()] = false + } else { + itemProps[ad.RestrictOutboundNTLM.String()] = true + } + } + + return IngestibleNode{ + ObjectID: item.ObjectIdentifier, + PropertyMap: itemProps, + Label: itemType, + } +} + // This function is to support our new method of doing Owns edges and makes older data sets backwards compatible func convertOwnsEdgeToProperty(item IngestBase, itemProps map[string]any) { for _, ace := range item.Aces { @@ -91,7 +129,7 @@ func stringToBool(itemProps map[string]any, keyName string) { itemProps[keyName] = final } case bool: - //pass + // pass default: slog.Debug(fmt.Sprintf("Removing %s with type %T", converted, converted)) delete(itemProps, keyName) @@ -109,7 +147,7 @@ func stringToInt(itemProps map[string]any, keyName string) { itemProps[keyName] = final } case int: - //pass + // pass default: slog.Debug(fmt.Sprintf("Removing %s with type %T", keyName, converted)) delete(itemProps, keyName) @@ -288,7 +326,7 @@ func ParseACEData(targetNode IngestibleNode, aces []ACE, targetID string, target } } - //TODO: When inheritance hashes are added, add them to these aces + // TODO: When inheritance hashes are added, add them to these aces // Process abusable permissions granted to the OWNER RIGHTS SID if any were found if len(ownerLimitedPrivs) > 0 { diff --git a/packages/go/ein/ad_test.go b/packages/go/ein/ad_test.go index 2655433d4d..10b4caa982 100644 --- a/packages/go/ein/ad_test.go +++ b/packages/go/ein/ad_test.go @@ -133,3 +133,37 @@ func TestParseDomainTrusts_TrustAttributesFix(t *testing.T) { assert.Contains(t, rel.RelProps, "trustattributes") assert.Equal(t, rel.RelProps["trustattributes"], 12345) } + +func TestConvertComputerToNode(t *testing.T) { + computer := ein.Computer{ + IngestBase: ein.IngestBase{ + Properties: map[string]any{ + "isdc": true, + }, + }, + RegistryData: ein.RegistryDataAPIResult{ + APIResult: ein.APIResult{ + Collected: true, + }, + RestrictSendingNtlmTraffic: 1, + }, + IsWebClientRunning: ein.BoolAPIResult{ + APIResult: ein.APIResult{ + Collected: true, + }, + Result: true, + }, + SmbInfo: ein.SMBSigningAPIResult{ + APIResult: ein.APIResult{ + Collected: true, + }, + SigningEnabled: true, + }, + } + + result := ein.ConvertComputerToNode(computer, ad.Computer) + assert.Equal(t, true, result.PropertyMap[ad.IsDC.String()]) + assert.Equal(t, true, result.PropertyMap[ad.WebClientRunning.String()]) + assert.Equal(t, true, result.PropertyMap[ad.RestrictOutboundNTLM.String()]) + assert.Equal(t, true, result.PropertyMap[ad.SMBSigning.String()]) +} diff --git a/packages/go/ein/incoming_models.go b/packages/go/ein/incoming_models.go index 9c774ee6cf..d9818edbb3 100644 --- a/packages/go/ein/incoming_models.go +++ b/packages/go/ein/incoming_models.go @@ -270,6 +270,24 @@ type UserRightsAssignmentAPIResult struct { Privilege string } +type BoolAPIResult struct { + APIResult + Result bool +} + +type SMBSigningAPIResult struct { + APIResult + SigningEnabled bool + OSVersion string + OSBuild string + DnsComputerName string +} + +type RegistryDataAPIResult struct { + APIResult + RestrictSendingNtlmTraffic uint +} + type Computer struct { IngestBase PrimaryGroupSID string @@ -287,6 +305,9 @@ type Computer struct { IsDC bool DomainSID string UnconstrainedDelegation bool + SmbInfo SMBSigningAPIResult + IsWebClientRunning BoolAPIResult + RegistryData RegistryDataAPIResult } type OU struct { diff --git a/packages/javascript/bh-shared-ui/src/components/HelpTexts/CoerceAndRelayNTLMToADCS/CoerceAndRelayNTLMToADCS.tsx b/packages/javascript/bh-shared-ui/src/components/HelpTexts/CoerceAndRelayNTLMToADCS/CoerceAndRelayNTLMToADCS.tsx index 35e34c4215..c14df80205 100644 --- a/packages/javascript/bh-shared-ui/src/components/HelpTexts/CoerceAndRelayNTLMToADCS/CoerceAndRelayNTLMToADCS.tsx +++ b/packages/javascript/bh-shared-ui/src/components/HelpTexts/CoerceAndRelayNTLMToADCS/CoerceAndRelayNTLMToADCS.tsx @@ -14,12 +14,12 @@ // // SPDX-License-Identifier: Apache-2.0 +import Composition from './Composition'; import General from './General'; import LinuxAbuse from './LinuxAbuse'; import Opsec from './Opsec'; import References from './References'; import WindowsAbuse from './WindowsAbuse'; -import Composition from "./Composition"; const CoerceAndRelayNTLMToADCS = { general: General, @@ -27,7 +27,7 @@ const CoerceAndRelayNTLMToADCS = { linuxabuse: LinuxAbuse, opsec: Opsec, references: References, - composition: Composition + composition: Composition, }; export default CoerceAndRelayNTLMToADCS; diff --git a/packages/javascript/bh-shared-ui/src/components/HelpTexts/CoerceAndRelayNTLMToSMB/CoerceAndRelayNTLMToSMB.tsx b/packages/javascript/bh-shared-ui/src/components/HelpTexts/CoerceAndRelayNTLMToSMB/CoerceAndRelayNTLMToSMB.tsx index 899028b44c..86e4db241b 100644 --- a/packages/javascript/bh-shared-ui/src/components/HelpTexts/CoerceAndRelayNTLMToSMB/CoerceAndRelayNTLMToSMB.tsx +++ b/packages/javascript/bh-shared-ui/src/components/HelpTexts/CoerceAndRelayNTLMToSMB/CoerceAndRelayNTLMToSMB.tsx @@ -14,12 +14,12 @@ // // SPDX-License-Identifier: Apache-2.0 +import Composition from './Composition'; import General from './General'; import LinuxAbuse from './LinuxAbuse'; import Opsec from './Opsec'; import References from './References'; import WindowsAbuse from './WindowsAbuse'; -import Composition from "./Composition"; const CoerceAndRelayNTLMToSMB = { general: General, @@ -27,7 +27,7 @@ const CoerceAndRelayNTLMToSMB = { linuxabuse: LinuxAbuse, opsec: Opsec, references: References, - composition: Composition + composition: Composition, }; export default CoerceAndRelayNTLMToSMB;