Skip to content

Commit

Permalink
fix(query): optimized passwords and secrets query (#3059)
Browse files Browse the repository at this point in the history
Signed-off-by: Felipe Avelar <[email protected]>
  • Loading branch information
felipe-avelar authored May 4, 2021
1 parent 51f283a commit f134433
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 78 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,65 +4,108 @@ import data.generic.common as commonLib

# search for harcoded secrets by looking for their values with a special chars and length
CxPolicy[result] {
docs := input.document[id]
treatedDoc = checkName(docs, name, docs[name])
keyDoc = treatedDoc[y][father]

clearParse := ["playbooks", "tasks", "command"]
not commonLib.equalsOrInArray(clearParse, father)

#get all string values from json
allValues = regex.find_n("\"[^\"]+\"\\s*:\\s*\"[^\"]+\"[]\n\r,}]", json.marshal(keyDoc), -1)

correctStrings := getCorrectStrings(replaceUniCode(allValues[m]), father)

checkforvulnerability(correctStrings)

docs := input.document[_]

[path, value] = walk(docs)
is_string(value)
value = replace_unicode(value)
checkObjects := prepare_object(path[minus(count(path), 1)], value)
checkObject := checkObjects[_]
check_vulnerability(checkObject)
allPath := [x | merge_path(path[i]) != ""; x := merge_path(path[i])]
result := {
"documentId": docs.id,
"searchKey": sprintf("{{%s}}.%s={{%s}}", [correctStrings.id, correctStrings.key, correctStrings.value]),
"searchKey": resolve_path(checkObject, allPath),
"issueType": "RedundantAttribute",
"keyExpectedValue": "Hardcoded secret key should not appear in source",
"keyActualValue": correctStrings.value,
"keyActualValue": value,
}
}

merge_path(pathItem) = item {
not is_string(pathItem)
item := ""
} else = item {
clearParse := ["playbooks", "tasks", "command", "original"]
commonLib.equalsOrInArray(clearParse, lower(pathItem))
item := ""
} else = item {
contains(pathItem, ".")
item := sprintf("{{%s}}", [pathItem])
} else = item {
item := pathItem
}

resolve_path(obj, path) = resolved {
obj.id != ""
resolved := sprintf("FROM=%s.{{%s}}", [concat(".", path), obj.id])
} else = resolved {
resolved := concat(".", path)
}

prepare_object(key, value) = obj {
#dockerfile
key == "Original"
args := split(value, " ")
obj := [x | x := create_docker_object(args[_], value)]
} else = obj {
obj := [{
"key": key,
"value": value,
"id": "",
}]
}

create_docker_object(value, original) = obj {
contains(value, "=")
splitted := split(value, "=")
count(splitted) > 1
k := splitted[0]
is_string(k)
v := concat("", array.slice(splitted, 1, count(splitted)))
obj := {
"key": k,
"value": v,
"id": original,
}
}

isUnderPasswordKey(p) {
is_under_password_key(p) {
ar = {"pas", "psw", "pwd"}
contains(lower(p), ar[_])
}

isUnderSekretKey(p) = res {
is_under_secret_key(p) = res {
ar = {"secret", "encrypt", "credential"}
res := contains(lower(p), ar[_])
}

#search for default passwords
checkforvulnerability(correctStrings) {
check_vulnerability(correctStrings) {
commonLib.isDefaultPassword(correctStrings.value)
isUnderPasswordKey(correctStrings.key)
is_under_password_key(correctStrings.key)

#remove common key and values
checkCommon(correctStrings)
check_common(correctStrings)
}

#search for non-default passwords under known names
checkforvulnerability(correctStrings) {
check_vulnerability(correctStrings) {
#remove short strings
count(correctStrings.value) > 4
count(correctStrings.value) < 30

#password should contain alpha and numeric and not contain spaces
count(regex.find_n("[a-zA-Z0-9]+", correctStrings.value, -1)) > 0
count(regex.find_n("^[^{{]+$", correctStrings.value, -1)) > 0
isUnderPasswordKey(correctStrings.key)
is_under_password_key(correctStrings.key)

#remove common key and values
checkCommon(correctStrings)
check_common(correctStrings)
}

#search for non-default passwords with upper, lower chars and digits
checkforvulnerability(correctStrings) { #ignore ascii cases
check_vulnerability(correctStrings) { #ignore ascii cases
#remove short strings
count(correctStrings.value) > 6
count(correctStrings.value) < 20
Expand All @@ -74,49 +117,49 @@ checkforvulnerability(correctStrings) { #ignore ascii cases
count(regex.find_n("^[^\\s_]+", correctStrings.value, -1)) > 0

#remove common key and values
checkCommon(correctStrings)
check_common(correctStrings)
}

#search for harcoded secrets with known prefixes
checkforvulnerability(correctStrings) {
check_vulnerability(correctStrings) {
#look for a known prefix
contains(correctStrings.value, "PRIVATE KEY")

#remove common key and values
checkCommon(correctStrings)
check_common(correctStrings)
}

#search for harcoded secret keys under known names
checkforvulnerability(correctStrings) {
check_vulnerability(correctStrings) {
#remove short strings
count(correctStrings.value) > 8

#remove string with non-keys characters
count(regex.find_n("^[^\\s$]+$", correctStrings.value, -1)) > 0

#look for a known names
isUnderSekretKey(correctStrings.key)
is_under_secret_key(correctStrings.key)

#remove string with non-keys characters
count(regex.find_n("^[^\\s/:@,.-_|]+$", correctStrings.value, -1)) > 0

#remove common key and values
checkCommon(correctStrings)
check_common(correctStrings)
}

#search for harcoded secrets by looking for their values with a special chars and length
checkforvulnerability(correctStrings) {
check_vulnerability(correctStrings) {
#remove short strings
count(correctStrings.value) > 30

#remove string with non-keys characters
count(regex.find_n("^[^\\s/:@,.-_|]+$", correctStrings.value, -1)) > 0

#remove common key and values
checkCommon(correctStrings)
check_common(correctStrings)
}

checkCommon(correctStrings) {
check_common(correctStrings) {
#remove common values
not commonLib.isCommonValue(correctStrings.value)

Expand All @@ -125,47 +168,7 @@ checkCommon(correctStrings) {
}

#replace unicode values to avoid false positives
replaceUniCode(allValues) = treatedValue {
replace_unicode(allValues) = treatedValue {
treatedValue_first := replace(allValues, "\\u003c", "<")
treatedValue = replace(treatedValue_first, "\\u003e", ">")
}

#construct correct strings based on dockerfile or other platform
getCorrectStrings(allValues, name) = correctStrings {
#other platforms
not contains(split(allValues, "\":")[0], "Original")
allStrings = {"key": split(allValues, "\":")[0], "value": split(allValues, "\":")[1]}

#remove trailling quotation marks
correctStrings = {
"key": substring(allStrings.key, 1, count(allStrings.key) - 1),
"value": substring(allStrings.value, 1, count(allStrings.value) - 3),
"id": name,
}
} else = correctStrings {
#dockerfile
contains(split(allValues, "\":")[0], "Original")

#replace "=" with spaces to check for problems with for the various formats of ENV in dockerfile
treatedValue := replace(allValues, "=", " ")
allStrings := {"key": split(split(treatedValue, ":")[1], " ")[1], "value": split(split(treatedValue, ":")[1], " ")[2]}

#remove trailling quotation marks
correctStrings := {
"key": substring(allStrings.key, 0, count(allStrings.key)),
"value": substring(allStrings.value, 0, count(allStrings.value) - 2),
"id": name,
}
}

# clear parser added feilds
checkName(document, name, docName) = treatedName {
clearAns := ["playbooks", "tasks"]
commonLib.equalsOrInArray(clearAns, name)
treatedName := [x | x := docName[int]]
} else = treatedName {
name == "command"
treatedName := [x | x := docName]
} else = treatedName {
treatedName := [x | x := document]
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@ resource "google_container_cluster" "primary" {
initial_node_count = 3

master_auth {
username = ""
password = ""

client_certificate_config {
issue_client_certificate = true
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
FROM baseImage

ARG password=pass!1213Fs


FROM test2
ARG password=pass!1213Fs
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,24 @@
"line": 29,
"fileName": "positive4.tf"
},
{
"queryName": "Passwords And Secrets In Infrastructure Code",
"severity": "HIGH",
"line": 49,
"fileName": "positive4.tf"
},
{
"queryName": "Passwords And Secrets In Infrastructure Code",
"severity": "HIGH",
"line": 69,
"fileName": "positive4.tf"
},
{
"queryName": "Passwords And Secrets In Infrastructure Code",
"severity": "HIGH",
"line": 89,
"fileName": "positive4.tf"
},
{
"queryName": "Passwords And Secrets In Infrastructure Code",
"severity": "HIGH",
Expand All @@ -53,6 +65,12 @@
"line": 3,
"fileName": "positive5.dockerfile"
},
{
"queryName": "Passwords And Secrets In Infrastructure Code",
"severity": "HIGH",
"line": 7,
"fileName": "positive5.dockerfile"
},
{
"queryName": "Passwords And Secrets In Infrastructure Code",
"severity": "HIGH",
Expand Down

0 comments on commit f134433

Please sign in to comment.