Lint / golangci-lint (push) Waiting to run
Lint / man-page-staleness (push) Waiting to run
Lint / semgrep (push) Waiting to run
Lint / checksecretparts (push) Waiting to run
Scan for secrets / test (push) Waiting to run
Test / test (push) Waiting to run
Test / test-community (push) Waiting to run
Release / mark-latest (push) Canceled after 0s
Release / Release (push) Canceled after 0s
* Fixed AWS detector producing non deterministic output * fixed bugbot comment --------- Co-authored-by: Amaan Ullah <[email protected]>
117 lines
3.2 KiB
Go
117 lines
3.2 KiB
Go
package aws
|
|
|
|
import (
|
|
"crypto/hmac"
|
|
"crypto/sha256"
|
|
"encoding/base32"
|
|
"encoding/binary"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"strings"
|
|
|
|
regexp "github.com/wasilibs/go-re2"
|
|
|
|
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
|
)
|
|
|
|
// ResourceTypes derived from: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html#identifiers-unique-ids
|
|
var ResourceTypes = map[string]string{
|
|
"ABIA": "AWS STS service bearer token",
|
|
"ACCA": "Context-specific credential",
|
|
"AGPA": "User group",
|
|
"AIDA": "IAM user",
|
|
"AIPA": "Amazon EC2 instance profile",
|
|
"AKIA": "Access key",
|
|
"ANPA": "Managed policy",
|
|
"ANVA": "Version in a managed policy",
|
|
"APKA": "Public key",
|
|
"AROA": "Role",
|
|
"ASCA": "Certificate",
|
|
"ASIA": "Temporary (AWS STS) access key IDs",
|
|
}
|
|
|
|
// UrlEncodedReplacer helps capture base64-encoded results that may be url-encoded.
|
|
// TODO: Add this as a decoder, or make it a more generic.
|
|
var UrlEncodedReplacer = strings.NewReplacer(
|
|
"%2B", "+",
|
|
"%2b", "+",
|
|
"%2F", "/",
|
|
"%2f", "/",
|
|
"%3d", "=",
|
|
"%3D", "=",
|
|
)
|
|
|
|
// Hashes, like those for git, do technically match the secret pattern.
|
|
// But they are extremely unlikely to be generated as an actual AWS secret.
|
|
// So when we find them, if they're not verified, we should ignore the result.
|
|
var FalsePositiveSecretPat = regexp.MustCompile(`[a-f0-9]{40}`)
|
|
|
|
func GetAccountNumFromID(id string) (string, error) {
|
|
// Function to get the account number from an AWS ID (no verification required)
|
|
// Source: https://medium.com/@TalBeerySec/a-short-note-on-aws-key-id-f88cc4317489
|
|
if len(id) < 4 {
|
|
return "", fmt.Errorf("AWSID is too short")
|
|
}
|
|
if id[4] == 'I' || id[4] == 'J' {
|
|
return "", fmt.Errorf("can't get account number from AKIAJ/ASIAJ or AKIAI/ASIAI keys")
|
|
}
|
|
trimmedAWSID := id[4:]
|
|
decodedBytes, err := base32.StdEncoding.WithPadding(base32.NoPadding).DecodeString(strings.ToUpper(trimmedAWSID))
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
if len(decodedBytes) < 6 {
|
|
return "", fmt.Errorf("decoded AWSID is too short")
|
|
}
|
|
|
|
data := make([]byte, 8)
|
|
copy(data[2:], decodedBytes[0:6])
|
|
z := binary.BigEndian.Uint64(data)
|
|
const mask uint64 = 0x7fffffffff80
|
|
accountNum := (z & mask) >> 7
|
|
return fmt.Sprintf("%012d", accountNum), nil
|
|
}
|
|
|
|
func GetHash(input string) string {
|
|
data := []byte(input)
|
|
hasher := sha256.New()
|
|
hasher.Write(data)
|
|
return hex.EncodeToString(hasher.Sum(nil))
|
|
}
|
|
|
|
func GetHMAC(key []byte, data []byte) []byte {
|
|
hasher := hmac.New(sha256.New, key)
|
|
hasher.Write(data)
|
|
return hasher.Sum(nil)
|
|
}
|
|
|
|
func CleanResults(results []detectors.Result, verificationEnabled bool) []detectors.Result {
|
|
if len(results) == 0 {
|
|
return results
|
|
}
|
|
if !verificationEnabled {
|
|
return results
|
|
}
|
|
// For every ID, we want at most one result, preferably verified.
|
|
idResults := map[string]detectors.Result{}
|
|
for _, result := range results {
|
|
// Always accept the verified result as the result for the given ID.
|
|
if result.Verified {
|
|
idResults[result.Redacted] = result
|
|
continue
|
|
}
|
|
|
|
// Only include an unverified result if we don't already have a result for a given ID.
|
|
if _, exist := idResults[result.Redacted]; !exist {
|
|
idResults[result.Redacted] = result
|
|
}
|
|
}
|
|
|
|
var out []detectors.Result
|
|
for _, r := range idResults {
|
|
out = append(out, r)
|
|
}
|
|
return out
|
|
}
|