● 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.

Offline extractor and decryptor for SCCM/MECM Network Access Account (NAA) credentials and policy secrets from dead-disk WMI repositories and DPAPI master keys.

$ git clone https://shehzade.io/repos/naa-dump-offline.git Copy
Source ZIP (290.0 KB) Prebuilt Binaries
Code 15 Commits 3 Releases 5
naa-dump-offline / pkg / registry / bootkey.go
← Back to directory
95 lines · 2.2 KB
Raw
1package registry
2
3import (
4 "encoding/binary"
5 "encoding/hex"
6 "fmt"
7 "io"
8 "os"
9 "unicode/utf16"
10
11 "www.velocidex.com/golang/regparser"
12)
13
14var bootKeyPermutation = []int{8, 5, 4, 2, 11, 9, 13, 3, 0, 6, 1, 12, 14, 10, 15, 7}
15
16func readClassString(r io.ReaderAt, key *regparser.CM_KEY_NODE) (string, error) {
17 offset := key.Class()
18 length := key.ClassLength()
19 if length == 0 {
20 return "", fmt.Errorf("empty class")
21 }
22 buf := make([]byte, length)
23 _, err := r.ReadAt(buf, int64(4096+offset+4))
24 if err != nil {
25 return "", err
26 }
27 u16 := make([]uint16, length/2)
28 for i := 0; i < len(u16); i++ {
29 u16[i] = binary.LittleEndian.Uint16(buf[i*2 : (i+1)*2])
30 }
31 return string(utf16.Decode(u16)), nil
32}
33
34func GetBootKey(systemHivePath string) ([]byte, error) {
35 f, err := os.Open(systemHivePath)
36 if err != nil {
37 return nil, fmt.Errorf("failed to open SYSTEM hive: %w", err)
38 }
39 defer f.Close()
40
41 reg, err := regparser.NewRegistry(f)
42 if err != nil {
43 return nil, fmt.Errorf("failed to parse SYSTEM hive: %w", err)
44 }
45
46 selectKey := reg.OpenKey("Select")
47 if selectKey == nil {
48 return nil, fmt.Errorf("could not find Select key in SYSTEM hive")
49 }
50
51 var currentControlSet string
52 for _, val := range selectKey.Values() {
53 if val.ValueName() == "Current" {
54 currentControlSet = fmt.Sprintf("ControlSet%03d", val.ValueData().Uint64)
55 break
56 }
57 }
58 if currentControlSet == "" {
59 currentControlSet = "ControlSet001"
60 }
61
62 subkeys := []string{"JD", "Skew1", "GBG", "Data"}
63 var hexStr string
64
65 for _, sub := range subkeys {
66 path := fmt.Sprintf("%s\\Control\\Lsa\\%s", currentControlSet, sub)
67 k := reg.OpenKey(path)
68 if k == nil {
69 return nil, fmt.Errorf("could not find key: %s", path)
70 }
71 s, err := readClassString(f, k)
72 if err != nil {
73 return nil, fmt.Errorf("failed to read class for %s: %w", path, err)
74 }
75 if len(s) > 8 {
76 s = s[:8]
77 }
78 hexStr += s
79 }
80
81 rawBytes, err := hex.DecodeString(hexStr)
82 if err != nil {
83 return nil, fmt.Errorf("failed to decode bootkey hex: %w", err)
84 }
85 if len(rawBytes) != 16 {
86 return nil, fmt.Errorf("expected 16 scrambled bytes, got %d", len(rawBytes))
87 }
88
89 bootKey := make([]byte, len(rawBytes))
90 for i := range bootKey {
91 bootKey[i] = rawBytes[bootKeyPermutation[i]]
92 }
93
94 return bootKey, nil
95}