● Notice //GitHub (@shehzade) is temporarily suspended pending an automated false-positive review. All tools are hosted on this Code Mirror and available on request (contact); GitHub links will return once reinstated.
PUBLIC MIRRORGo v1.0.0

Offline Active Directory database (ntds.dit) parser and BloodHound graph reconstructor in pure Go. Extracts directory objects, group memberships, domain trusts, and binary DACLs from dead-disk ESE database pages and registry hives.

$ git clone https://shehzade.io/repos/ntds-to-bloodhound.git Copy
Source ZIP (246.9 KB) Prebuilt Binaries
Code 21 Commits 1 Releases 5
ntds-to-bloodhound / pkg / ad / tree.go
← Back to directory
68 lines · 1.0 KB
Raw
1package ad
2
3import (
4 "fmt"
5 "strings"
6)
7
8type TreeNode struct {
9 DNT uint64
10 PDNT uint64
11 RDN string
12 Prefix string
13}
14
15type Tree struct {
16 nodes map[uint64]*TreeNode
17}
18
19func NewTree() *Tree {
20 return &Tree{
21 nodes: make(map[uint64]*TreeNode),
22 }
23}
24
25func (t *Tree) AddNode(dnt, pdnt uint64, rdn, prefix string) {
26 if prefix == "" {
27 prefix = "CN="
28 }
29 t.nodes[dnt] = &TreeNode{
30 DNT: dnt,
31 PDNT: pdnt,
32 RDN: rdn,
33 Prefix: prefix,
34 }
35}
36
37func (t *Tree) GetRDN(dnt uint64) string {
38 if n, ok := t.nodes[dnt]; ok {
39 return n.RDN
40 }
41 return ""
42}
43
44func (t *Tree) ResolveDN(startDNT uint64) string {
45 curr := startDNT
46 var parts []string
47 visited := make(map[uint64]bool)
48
49 for curr != 0 && curr != 2 {
50 if visited[curr] {
51 break
52 }
53 visited[curr] = true
54
55 node, exists := t.nodes[curr]
56 if !exists || node.RDN == "" {
57 break
58 }
59
60 parts = append(parts, fmt.Sprintf("%s%s", node.Prefix, node.RDN))
61 if node.PDNT == 0 || node.PDNT == curr {
62 break
63 }
64 curr = node.PDNT
65 }
66
67 return strings.Join(parts, ",")
68}