Skip to content

Commit bd0600b

Browse files
rgmzRichard Gomez
authored and
Richard Gomez
committed
feat(azure): improve connstring matching
1 parent aabfec4 commit bd0600b

File tree

2 files changed

+87
-44
lines changed

2 files changed

+87
-44
lines changed

pkg/detectors/azurestorage/azurestorage.go

+85-44
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ import (
66
"crypto/sha256"
77
"encoding/base64"
88
"fmt"
9+
"io"
910
"net/http"
1011
"regexp"
11-
"strings"
1212
"time"
1313

1414
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
@@ -23,72 +23,113 @@ var _ detectors.Detector = (*Scanner)(nil)
2323

2424
var (
2525
defaultClient = http.DefaultClient
26-
keyPat = regexp.MustCompile(`DefaultEndpointsProtocol=https;AccountName=(?P<account_name>[^;]+);AccountKey=(?P<account_key>[^;]+);EndpointSuffix=core\.windows\.net`)
26+
namePat = regexp.MustCompile(`AccountName=([a-z0-9]{3,24})`) // Names can only be lowercase alphanumeric.
27+
keyPat = regexp.MustCompile(`AccountKey=([a-zA-Z0-9+/-]{86,88}={0,2})`)
28+
key1Pat = regexp.MustCompile(`DefaultEndpointsProtocol=https;AccountName=(?P<account_name>[^;]+);AccountKey=(?P<account_key>[^;]+);EndpointSuffix=core\.windows\.net`)
29+
30+
// https://learn.microsoft.com/en-us/azure/storage/common/storage-use-emulator
31+
testNames = map[string]struct{}{
32+
"devstoreaccount1": {},
33+
"storagesample": {},
34+
}
35+
testKeys = map[string]struct{}{
36+
"Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==": {},
37+
}
2738
)
2839

2940
func (s Scanner) Keywords() []string {
30-
return []string{"DefaultEndpointsProtocol=https;AccountName="}
41+
return []string{"DefaultEndpointsProtocol=http", "EndpointSuffix="}
3142
}
3243

3344
func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) {
3445
dataStr := string(data)
3546

36-
matches := keyPat.FindAllStringSubmatch(dataStr, -1)
47+
// Deduplicate results.
48+
names := make(map[string]struct{})
49+
for _, matches := range namePat.FindAllStringSubmatch(dataStr, -1) {
50+
name := matches[1]
51+
if _, ok := testNames[name]; ok {
52+
continue
53+
}
54+
names[name] = struct{}{}
55+
}
56+
if len(names) == 0 {
57+
return results, nil
58+
}
3759

38-
for _, match := range matches {
39-
if len(match) != 3 {
60+
keys := make(map[string]struct{})
61+
for _, matches := range keyPat.FindAllStringSubmatch(dataStr, -1) {
62+
key := matches[1]
63+
if _, ok := testKeys[key]; ok {
4064
continue
4165
}
42-
accountName := strings.TrimSpace(match[1])
43-
accountKey := strings.TrimSpace(match[2])
66+
keys[key] = struct{}{}
67+
}
68+
if len(keys) == 0 {
69+
return results, nil
70+
}
4471

72+
// Check results.
73+
for name := range names {
4574
s1 := detectors.Result{
46-
DetectorType: detectorspb.DetectorType_AzureStorage,
47-
Raw: []byte(accountName),
75+
DetectorType: s.Type(),
76+
Raw: []byte(name),
4877
}
4978

50-
if verify {
51-
client := s.client
52-
if client == nil {
53-
client = defaultClient
79+
for key := range keys {
80+
if verify {
81+
isVerified, verificationErr := s.verifyMatch(ctx, name, key)
82+
s1.Verified = isVerified
83+
s1.VerificationError = verificationErr
5484
}
5585

56-
now := time.Now().UTC().Format(http.TimeFormat)
57-
stringToSign := "GET\n\n\n\n\n\n\n\n\n\n\n\nx-ms-date:" + now + "\nx-ms-version:2019-12-12\n/" + accountName + "/\ncomp:list"
58-
accountKeyBytes, _ := base64.StdEncoding.DecodeString(accountKey)
59-
h := hmac.New(sha256.New, accountKeyBytes)
60-
h.Write([]byte(stringToSign))
61-
signature := base64.StdEncoding.EncodeToString(h.Sum(nil))
62-
63-
url := "https://" + accountName + ".blob.core.windows.net/?comp=list"
64-
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
65-
req.Header.Set("x-ms-date", now)
66-
req.Header.Set("x-ms-version", "2019-12-12")
67-
req.Header.Set("Authorization", "SharedKey "+accountName+":"+signature)
68-
69-
if err != nil {
70-
continue
71-
}
72-
res, err := client.Do(req)
73-
if err == nil {
74-
defer res.Body.Close()
75-
if res.StatusCode >= 200 && res.StatusCode < 300 {
76-
s1.Verified = true
77-
} else if res.StatusCode == 403 {
78-
} else {
79-
s1.VerificationError = fmt.Errorf("unexpected HTTP response status %d", res.StatusCode)
80-
}
81-
} else {
82-
s1.VerificationError = err
83-
}
86+
results = append(results, s1)
8487
}
85-
86-
results = append(results, s1)
8788
}
8889

8990
return results, nil
9091
}
9192

93+
func (s Scanner) verifyMatch(ctx context.Context, name string, key string) (bool, error) {
94+
client := s.client
95+
if client == nil {
96+
client = defaultClient
97+
}
98+
99+
now := time.Now().UTC().Format(http.TimeFormat)
100+
stringToSign := "GET\n\n\n\n\n\n\n\n\n\n\n\nx-ms-date:" + now + "\nx-ms-version:2019-12-12\n/" + name + "/\ncomp:list"
101+
accountKeyBytes, _ := base64.StdEncoding.DecodeString(key)
102+
h := hmac.New(sha256.New, accountKeyBytes)
103+
h.Write([]byte(stringToSign))
104+
signature := base64.StdEncoding.EncodeToString(h.Sum(nil))
105+
106+
url := "https://" + name + ".blob.core.windows.net/?comp=list"
107+
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
108+
if err != nil {
109+
return false, err
110+
}
111+
112+
req.Header.Set("x-ms-date", now)
113+
req.Header.Set("x-ms-version", "2019-12-12")
114+
req.Header.Set("Authorization", "SharedKey "+name+":"+signature)
115+
116+
res, err := client.Do(req)
117+
if err == nil {
118+
_, _ = io.Copy(io.Discard, res.Body)
119+
_ = res.Body.Close()
120+
121+
if res.StatusCode >= 200 && res.StatusCode < 300 {
122+
return true, nil
123+
} else if res.StatusCode == 403 {
124+
return false, nil
125+
} else {
126+
return false, fmt.Errorf("unexpected HTTP response status %d", res.StatusCode)
127+
}
128+
} else {
129+
return false, err
130+
}
131+
}
132+
92133
func (s Scanner) Type() detectorspb.DetectorType {
93134
return detectorspb.DetectorType_AzureStorage
94135
}

pkg/engine/defaults.go

+2
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ import (
6565
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors/azure"
6666
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors/azurebatch"
6767
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors/azurecontainerregistry"
68+
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors/azurestorage"
6869
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors/bannerbear"
6970
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors/baremetrics"
7071
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors/beamer"
@@ -1575,6 +1576,7 @@ func DefaultDetectors() []detectors.Detector {
15751576
grafana.Scanner{},
15761577
logzio.Scanner{},
15771578
eventbrite.Scanner{},
1579+
&azurestorage.Scanner{},
15781580
}
15791581

15801582
}

0 commit comments

Comments
 (0)