From da872f5c27257c8b4a8c55bf6cb178a1d0711d5d Mon Sep 17 00:00:00 2001 From: roxanne-tampus <51393035+roxanne-tampus@users.noreply.github.com> Date: Tue, 24 May 2022 09:37:01 +0800 Subject: [PATCH] modified Alibaba detector to use standard library (#568) * added alibaba detector * enhancement * enhancement and ran mod tidy * fixed --- go.mod | 5 -- go.sum | 11 --- pkg/detectors/alibaba/alibaba.go | 119 ++++++++++++++++++-------- pkg/detectors/alibaba/alibaba_test.go | 30 +++++-- 4 files changed, 105 insertions(+), 60 deletions(-) diff --git a/go.mod b/go.mod index bb9fa0b30..b883c1fe5 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,6 @@ replace github.com/zricethezav/gitleaks/v8 => github.com/trufflesecurity/gitleak require ( cloud.google.com/go/secretmanager v1.4.0 github.com/Azure/go-autorest/autorest/azure/auth v0.5.11 - github.com/aliyun/alibaba-cloud-sdk-go v1.61.1465 github.com/aws/aws-sdk-go v1.44.9 github.com/aws/aws-sdk-go-v2/credentials v1.12.0 github.com/aws/aws-sdk-go-v2/service/sts v1.16.4 @@ -93,12 +92,9 @@ require ( github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jpillora/s3 v1.1.4 // indirect - github.com/json-iterator/go v1.1.11 // indirect github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect github.com/mattn/go-isatty v0.0.14 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.1 // indirect github.com/pkg/diff v0.0.0-20200914180035-5b29258ca4f7 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/xanzy/ssh-agent v0.3.0 // indirect @@ -113,7 +109,6 @@ require ( google.golang.org/api v0.74.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/grpc v1.45.0 // indirect - gopkg.in/ini.v1 v1.66.2 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect ) diff --git a/go.sum b/go.sum index 8223ffab4..5f615478d 100644 --- a/go.sum +++ b/go.sum @@ -87,8 +87,6 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafo github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc= github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= -github.com/aliyun/alibaba-cloud-sdk-go v1.61.1465 h1:8i+XtPz4IuZEM6biUBnfQbKdJPKek9/QaPEbRCfnIBw= -github.com/aliyun/alibaba-cloud-sdk-go v1.61.1465/go.mod h1:RcDobYh8k5VP6TNybz9m++gL3ijVI5wueVr0EM10VsU= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= @@ -198,7 +196,6 @@ github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6Wezm github.com/gobwas/ws v1.0.4/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= @@ -334,7 +331,6 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= -github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= @@ -343,8 +339,6 @@ github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/jpillora/s3 v1.1.4 h1:YCCKDWzb/Ye9EBNd83ATRF/8wPEy0xd43Rezb6u6fzc= github.com/jpillora/s3 v1.1.4/go.mod h1:yedE603V+crlFi1Kl/5vZJaBu9pUzE9wvKegU/lF2zs= -github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= @@ -388,10 +382,7 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 h1:W6apQkHrMkS0Muv8G/TipAy/FJl/rCYT0+EuS8+Z0z4= github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= @@ -938,8 +929,6 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/h2non/gock.v1 v1.1.2 h1:jBbHXgGBK/AoPVfJh5x4r/WxIrElvbLel8TCZkkZJoY= gopkg.in/h2non/gock.v1 v1.1.2/go.mod h1:n7UGz/ckNChHiK05rDoiC4MYSunEC/lyaUm2WWaDva0= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI= -gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/pkg/detectors/alibaba/alibaba.go b/pkg/detectors/alibaba/alibaba.go index b280bc148..6b77617dd 100644 --- a/pkg/detectors/alibaba/alibaba.go +++ b/pkg/detectors/alibaba/alibaba.go @@ -2,11 +2,18 @@ package alibaba import ( "context" + "crypto/hmac" + "crypto/sha1" + "encoding/base64" + "math/rand" + "net/http" + "net/url" "regexp" + "strconv" + "strings" "time" - "github.com/aliyun/alibaba-cloud-sdk-go/services/ecs" - log "github.com/sirupsen/logrus" + "github.com/trufflesecurity/trufflehog/v3/pkg/common" "github.com/trufflesecurity/trufflehog/v3/pkg/detectors" "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" ) @@ -17,8 +24,11 @@ type Scanner struct{} var _ detectors.Detector = (*Scanner)(nil) var ( - keyPat = regexp.MustCompile(`\b(LTAI[a-zA-Z0-9]{17,21})[\"' ;\s]*`) - secretPat = regexp.MustCompile(`\b([a-zA-Z0-9]{30})\b`) + client = common.SaneHttpClient() + + // Make sure that your group is surrounded in boundary characters such as below to reduce false positives. + keyPat = regexp.MustCompile(`\b([a-zA-Z0-9]{30})\b`) + idPat = regexp.MustCompile(`\b(LTAI[a-zA-Z0-9]{17,21})[\"';\s]*`) ) // Keywords are used for efficiently pre-filtering chunks. @@ -27,58 +37,95 @@ func (s Scanner) Keywords() []string { return []string{"LTAI"} } +func randString(n int) string { + rand.Seed(time.Now().UnixNano()) + const alphanum = "0123456789abcdefghijklmnopqrstuvwxyz" + var bytes = make([]byte, n) + rand.Read(bytes) + for i, b := range bytes { + bytes[i] = alphanum[b%byte(len(alphanum))] + } + return string(bytes) +} + +func GetSignature(input, key string) string { + key_for_sign := []byte(key) + h := hmac.New(sha1.New, key_for_sign) + h.Write([]byte(input)) + return base64.StdEncoding.EncodeToString(h.Sum(nil)) +} +func buildStringToSign(method, input string) string { + filter := strings.Replace(input, "+", "%20", -1) + filter = strings.Replace(filter, "%7E", "~", -1) + filter = strings.Replace(filter, "*", "%2A", -1) + filter = method + "&%2F&" + url.QueryEscape(filter) + return filter +} + // FromData will find and optionally verify Alibaba secrets in a given set of bytes. func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) { dataStr := string(data) matches := keyPat.FindAllStringSubmatch(dataStr, -1) + idMatches := idPat.FindAllStringSubmatch(dataStr, -1) + for _, match := range matches { - //Plausible key pat found, look for secrets match - secMatches := secretPat.FindAllStringSubmatch(dataStr, -1) + if len(match) != 2 { + continue + } + resMatch := strings.TrimSpace(match[1]) - for _, secMatch := range secMatches { - - if len(match) != 2 { + for _, idMatch := range idMatches { + if len(idMatch) != 2 { continue } - s := detectors.Result{ + resIdMatch := strings.TrimSpace(idMatch[1]) + + s1 := detectors.Result{ DetectorType: detectorspb.DetectorType_Alibaba, - Raw: []byte(match[1]), - Redacted: match[1], + Raw: []byte(resMatch), } if verify { - ecsClient, err := ecs.NewClientWithAccessKey( - "us-east-1", // your region ID - match[1], // your AccessKey ID - secMatch[1]) // your AccessKey Secret + req, err := http.NewRequestWithContext(ctx, "GET", "http://ecs.aliyuncs.com/?", nil) if err != nil { - log.WithError(err).Debug("error creating alibaba client, skipping") continue } - // Create an API request and set parameters - request := ecs.CreateDescribeInstancesRequest() - request.ConnectTimeout = time.Duration(5) * time.Second - request.Scheme = "https" - request.Domain = "ecs.aliyuncs.com" - // Initiate the request and handle exceptions - _, err = ecsClient.DescribeInstances(request) - if err != nil { - s.Verified = false + dateISO := time.Now().UTC().Format("2006-01-02T15:04:05Z07:00") + params := req.URL.Query() + params.Add("AccessKeyId", resIdMatch) + params.Add("Action", "DescribeRegions") + params.Add("Format", "JSON") + params.Add("SignatureMethod", "HMAC-SHA1") + params.Add("SignatureNonce", randString(16)) + params.Add("SignatureVersion", "1.0") + params.Add("Timestamp", dateISO) + params.Add("Version", "2014-05-26") - } else { - s.Verified = true + stringToSign := buildStringToSign(req.Method, params.Encode()) + signature := GetSignature(stringToSign, resMatch+"&") //Get Signature HMAC SHA1 + params.Add("Signature", signature) + req.URL.RawQuery = params.Encode() + + req.Header.Add("Content-Type", "text/xml;charset=utf-8") + req.Header.Add("Content-Length", strconv.Itoa(len(params.Encode()))) + res, err := client.Do(req) + if err == nil { + defer res.Body.Close() + if res.StatusCode >= 200 && res.StatusCode < 300 { + s1.Verified = true + } else { + // This function will check false positives for common test words, but also it will make sure the key appears 'random' enough to be a real key. + if detectors.IsKnownFalsePositive(resMatch, detectors.DefaultFalsePositives, true) { + continue + } + } } } - if !s.Verified { - if detectors.IsKnownFalsePositive(string(s.Raw), detectors.DefaultFalsePositives, true) { - continue - } - } - - results = append(results, s) + results = append(results, s1) } } - return + + return detectors.CleanResults(results), nil } diff --git a/pkg/detectors/alibaba/alibaba_test.go b/pkg/detectors/alibaba/alibaba_test.go index 8a5478e60..538ee66ba 100644 --- a/pkg/detectors/alibaba/alibaba_test.go +++ b/pkg/detectors/alibaba/alibaba_test.go @@ -7,20 +7,21 @@ import ( "time" "github.com/kylelemons/godebug/pretty" - "github.com/trufflesecurity/trufflehog/v3/pkg/common" "github.com/trufflesecurity/trufflehog/v3/pkg/detectors" + + "github.com/trufflesecurity/trufflehog/v3/pkg/common" "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" ) func TestAlibaba_FromChunk(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) defer cancel() - testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors2") + testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors4") if err != nil { t.Fatalf("could not get test secrets from GCP: %s", err) } secret := testSecrets.MustGetField("ALIBABA_SECRET") - secretInactive := testSecrets.MustGetField("ALIBABA_SECRET_INACTIVE") + inactiveSecret := testSecrets.MustGetField("ALIBABA_SECRET_INACTIVE") id := testSecrets.MustGetField("ALIBABA_ID") type args struct { @@ -40,14 +41,13 @@ func TestAlibaba_FromChunk(t *testing.T) { s: Scanner{}, args: args{ ctx: context.Background(), - data: []byte(fmt.Sprintf("Alibaba keys are here: %s\n %s within", id, secret)), + data: []byte(fmt.Sprintf("You can find a alibaba secret %s within alibaba %s", secret, id)), verify: true, }, want: []detectors.Result{ { DetectorType: detectorspb.DetectorType_Alibaba, Verified: true, - Redacted: id, }, }, wantErr: false, @@ -57,14 +57,13 @@ func TestAlibaba_FromChunk(t *testing.T) { s: Scanner{}, args: args{ ctx: context.Background(), - data: []byte(fmt.Sprintf("Alibaba keys are here: %s\n %s within", id, secretInactive)), + data: []byte(fmt.Sprintf("You can find a alibaba secret %s within alibaba %s but not valid", inactiveSecret, id)), // the secret would satisfy the regex but not pass validation verify: true, }, want: []detectors.Result{ { DetectorType: detectorspb.DetectorType_Alibaba, Verified: false, - Redacted: id, }, }, wantErr: false, @@ -91,7 +90,7 @@ func TestAlibaba_FromChunk(t *testing.T) { } for i := range got { if len(got[i].Raw) == 0 { - t.Fatal("no raw secret present") + t.Fatalf("no raw secret present: \n %+v", got[i]) } got[i].Raw = nil } @@ -101,3 +100,18 @@ func TestAlibaba_FromChunk(t *testing.T) { }) } } + +func BenchmarkFromData(benchmark *testing.B) { + ctx := context.Background() + s := Scanner{} + for name, data := range detectors.MustGetBenchmarkData() { + benchmark.Run(name, func(b *testing.B) { + for n := 0; n < b.N; n++ { + _, err := s.FromData(ctx, false, data) + if err != nil { + b.Fatal(err) + } + } + }) + } +}