Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into BED-3961
Browse files Browse the repository at this point in the history
  • Loading branch information
elikmiller committed Jan 19, 2024
2 parents 4930f61 + e51afb3 commit a29f153
Show file tree
Hide file tree
Showing 29 changed files with 715 additions and 5 deletions.
2 changes: 2 additions & 0 deletions cmd/api/src/api/v2/file_uploads_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ func Test_FileUploadWorkFlowVersion6(t *testing.T) {

//Assert that we created stuff we expected
testCtx.AssertIngest(fixtures.IngestAssertions)
testCtx.AssertIngest(fixtures.IngestAssertionsv6)
}

func Test_FileUploadVersion6AllOptionADCS(t *testing.T) {
Expand Down Expand Up @@ -234,4 +235,5 @@ func Test_CompressedFileUploadWorkFlowVersion6(t *testing.T) {

//Assert that we created stuff we expected
testCtx.AssertIngest(fixtures.IngestAssertions)
testCtx.AssertIngest(fixtures.IngestAssertionsv6)
}
15 changes: 15 additions & 0 deletions cmd/api/src/test/fixtures/fixtures/expected_ingest.go
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,14 @@ var (
query.Equals(query.EndProperty(common.ObjectID.String()), "S-1-5-21-3130019616-2776909439-2417379446-2117"),
query.Equals(query.RelationshipProperty(ad.LogonType.String()), 2)),
}
v6ingestRelationshipAssertionCriteria = []graph.Criteria{
query.And(
query.Kind(query.Start(), ad.Computer),
query.Equals(query.StartProperty(common.ObjectID.String()), "S-1-5-21-3130019616-2776909439-2417379446-1001"),
query.Kind(query.Relationship(), ad.DCFor),
query.Kind(query.End(), ad.Domain),
query.Equals(query.EndProperty(common.ObjectID.String()), "S-1-5-21-3130019616-2776909439-2417379446")),
}
)

func FormatQueryComponent(criteria graph.Criteria) string {
Expand All @@ -266,3 +274,10 @@ func IngestAssertions(testCtrl test.Controller, tx graph.Transaction) {
require.Nilf(testCtrl, err, "Unable to find an expected relationship: %s", FormatQueryComponent(assertionCriteria))
}
}

func IngestAssertionsv6(testCtrl test.Controller, tx graph.Transaction) {
for _, assertionCriteria := range v6ingestRelationshipAssertionCriteria {
_, err := tx.Relationships().Filter(assertionCriteria).First()
require.Nilf(testCtrl, err, "Unable to find an expected relationship: %s", FormatQueryComponent(assertionCriteria))
}
}
4 changes: 3 additions & 1 deletion cmd/api/src/test/fixtures/fixtures/v6/ingest/computers.json
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,9 @@
],
"ObjectIdentifier": "S-1-5-21-3130019616-2776909439-2417379446-1001",
"IsDeleted": false,
"IsACLProtected": false
"IsACLProtected": false,
"IsDC": true,
"DomainSID": "S-1-5-21-3130019616-2776909439-2417379446"
},
{
"Properties": {
Expand Down
3 changes: 2 additions & 1 deletion packages/cue/bh/ad/ad.cue
Original file line number Diff line number Diff line change
Expand Up @@ -1134,5 +1134,6 @@ PathfindingRelationships: [
ADCSESC4,
ADCSESC5,
ADCSESC6,
ADCSESC7
ADCSESC7,
DCFor
]
3 changes: 3 additions & 0 deletions packages/go/analysis/ad/filters.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,9 @@ func SelectComputersCandidateFilter(node *graph.Node) bool {
func SelectGPOTierZeroCandidateFilter(node *graph.Node) bool {
if tags, err := node.Properties.Get(common.SystemTags.String()).String(); err != nil {
return false
} else if node.Kinds.ContainsOneOf(ad.Group) {
// GPOs don’t apply to groups.
return false
} else {
return strings.Contains(tags, ad.AdminTierZero)
}
Expand Down
38 changes: 38 additions & 0 deletions packages/go/analysis/ad/filters_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright 2023 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

package ad_test

import (
ad2 "github.com/specterops/bloodhound/analysis/ad"
"github.com/specterops/bloodhound/dawgs/graph"
"github.com/specterops/bloodhound/graphschema/ad"
"github.com/specterops/bloodhound/graphschema/common"
"github.com/stretchr/testify/assert"
"testing"
)

func TestSelectGPOContainerCandidateFilter(t *testing.T) {
var (
computer = graph.NewNode(0, graph.NewProperties(), ad.Computer)
group = graph.NewNode(1, graph.NewProperties().Set(common.SystemTags.String(), ad.AdminTierZero), ad.Group)
user = graph.NewNode(2, graph.NewProperties().Set(common.SystemTags.String(), ad.AdminTierZero), ad.User)
)

assert.False(t, ad2.SelectGPOContainerCandidateFilter(computer))
assert.False(t, ad2.SelectGPOTierZeroCandidateFilter(group))
assert.True(t, ad2.SelectGPOTierZeroCandidateFilter(user))
}
13 changes: 12 additions & 1 deletion packages/go/ein/ad.go
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ func ParseDomainTrusts(domain Domain) ParsedDomainTrustData {
return parsedData
}

// ParseComputerMiscData parses AllowedToDelegate, AllowedToAct, HasSIDHistory,DumpSMSAPassword and Sessions
// ParseComputerMiscData parses AllowedToDelegate, AllowedToAct, HasSIDHistory,DumpSMSAPassword,DCFor and Sessions
func ParseComputerMiscData(computer Computer) []IngestibleRelationship {
relationships := make([]IngestibleRelationship, 0)
for _, target := range computer.AllowedToDelegate {
Expand Down Expand Up @@ -342,6 +342,17 @@ func ParseComputerMiscData(computer Computer) []IngestibleRelationship {
}
}

if computer.IsDC && computer.DomainSID != "" {
relationships = append(relationships, IngestibleRelationship{
Source: computer.ObjectIdentifier,
SourceType: ad.Computer,
TargetType: ad.Domain,
Target: computer.DomainSID,
RelProps: map[string]any{"isacl": false},
RelType: ad.DCFor,
})
}

return relationships
}

Expand Down
2 changes: 2 additions & 0 deletions packages/go/ein/incoming_models.go
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,8 @@ type Computer struct {
DCRegistryData DCRegistryData
Status ComputerStatus
HasSIDHistory []TypedPrincipal
IsDC bool
DomainSID string
}

type OU struct {
Expand Down
2 changes: 1 addition & 1 deletion packages/go/graphschema/ad/ad.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright 2024 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 General from './General';
import WindowsAbuse from './WindowsAbuse';
import LinuxAbuse from './LinuxAbuse';
import Opsec from './Opsec';
import References from './References';

const ADCSESC6a = {
general: General,
windowsAbuse: WindowsAbuse,
linuxAbuse: LinuxAbuse,
opsec: Opsec,
references: References,
};

export default ADCSESC6a;
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright 2024 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 { FC } from 'react';
import { groupSpecialFormat } from '../utils';
import { EdgeInfoProps } from '../index';
import { Typography } from '@mui/material';

const General: FC<EdgeInfoProps> = ({ sourceName, sourceType, targetName }) => {
return (
<>
<Typography variant='body2'>
{groupSpecialFormat(sourceType, sourceName)} the privileges to perform the ADCS ESC6 Scenario A attack
against the target domain.
</Typography>
<Typography variant='body2'>
The principal has permission to enroll on one or more certificate templates allowing for authentication.
They also have enrollment permission for an enterprise CA with the necessary templates published. This
enterprise CA is trusted for NT authentication in the forest, and chains up to a root CA for the forest.
The enterprise CA is configured with the EDITF_ATTRIBUTESUBJECTALTNAME2 flag allowing enrollees to
specify a Subject Alternate Name (SAN) identifying another principal during certificate enrollment of
any published certificate template. This setup allow an attacker principal to obtain a malicious
certificate as another principal. There is an affected Domain Controller configured to allow weak
certificate binding enforcement, which enables the attacker principal to authenticate with the malicious
certificate and thereby impersonating any AD forest user or computer without their credentials.
</Typography>
</>
);
};

export default General;
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright 2024 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 { FC } from 'react';
import { Typography } from '@mui/material';

const LinuxAbuse: FC = () => {
return (
<>
<Typography variant='body2'>An attacker may perform this attack in the following steps:</Typography>
<Typography variant='body2'>
<b>Step 1</b>: Use Certipy to request enrollment in the affected template, specifying the affected
enterprise CA and target principal to impersonate:
</Typography>
<Typography component={'pre'}>
{
'certipy req -u [email protected] -p Passw0rd -ca corp-DC-CA -target ca.corp.local -template ESC6 -upn [email protected]'
}
</Typography>
<Typography variant='body2'>
<b>Step 2</b>: Request a ticket granting ticket (TGT) from the domain, specifying the certificate
created in Step 1 and the IP of a domain controller:
</Typography>
<Typography component={'pre'}>{'certipy auth -pfx administrator.pfx -dc-ip 172.16.126.128'}</Typography>
</>
);
};

export default LinuxAbuse;
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright 2024 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 { FC } from 'react';
import { Typography } from '@mui/material';

const Opsec: FC = () => {
return (
<Typography variant='body2'>
When the affected certificate authority issues the certificate to the attacker, it will retain a local copy
of that certificate in its issued certificates store. Defenders may analyze those issued certificates to
identify illegitimately issued certificates and identify the principal that requested the certificate, as
well as the target identity the attacker is attempting to impersonate.
</Typography>
);
};

export default Opsec;
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright 2024 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 { FC } from 'react';
import { Link, Box } from '@mui/material';

const References: FC = () => {
return (
<Box sx={{ overflowX: 'auto' }}>
<Link
target='_blank'
rel='noopener'
href='https://specterops.io/wp-content/uploads/sites/3/2022/06/Certified_Pre-Owned.pdf'>
Certified Pre-Owned
</Link>
<br />
<Link
target='_blank'
rel='noopener'
href='https://research.ifcr.dk/certipy-4-0-esc9-esc10-bloodhound-gui-new-authentication-and-request-methods-and-more-7237d88061f7'>
Certipy 4.0
</Link>
<br />
<Link
target='_blank'
rel='noopener'
href='https://book.hacktricks.xyz/windows-hardening/active-directory-methodology/ad-certificates/domain-escalation#editf_attributesubjectaltname2-esc6'>
Domain Escalation Edit Attributes
</Link>
</Box>
);
};

export default References;
Loading

0 comments on commit a29f153

Please sign in to comment.