Create a .qll file to reuse the code and add check of Spring properties

This commit is contained in:
luchua-bc
2021-03-30 02:57:58 +00:00
parent 5ce3f9d6ff
commit 1349bf7b0b
8 changed files with 137 additions and 199 deletions

View File

@@ -1,5 +1,5 @@
| configuration.properties:6:1:6:25 | ldap.password=mysecpass | Plaintext credentials ldap.password are loaded in getProperty(...) |
| configuration.properties:18:1:18:35 | datasource1.password=Passw0rd@123 | Plaintext credentials datasource1.password are loaded in getProperty(...) |
| configuration.properties:25:1:25:31 | mail.password=MysecPWxWa@1993 | Plaintext credentials mail.password are loaded in getProperty(...) |
| configuration.properties:33:1:33:50 | com.example.aws.s3.access_key=AKMAMQPBYMCD6YSAYCBA | Plaintext credentials com.example.aws.s3.access_key are loaded in getProperty(...) |
| configuration.properties:34:1:34:70 | com.example.aws.s3.secret_key=8lMPSfWzZq+wcWtck5+QPLOJDZzE783pS09/IO3k | Plaintext credentials com.example.aws.s3.secret_key are loaded in getProperty(...) |
| configuration.properties:6:1:6:25 | ldap.password=mysecpass | Plaintext credentials ldap.password are loaded in Java Properties getProperty(...) |
| configuration.properties:18:1:18:35 | datasource1.password=Passw0rd@123 | Plaintext credentials datasource1.password are loaded in Java Properties getProperty(...) |
| configuration.properties:25:1:25:31 | mail.password=MysecPWxWa@1993 | Plaintext credentials mail.password are loaded in Spring annotation Value |
| configuration.properties:33:1:33:50 | com.example.aws.s3.access_key=AKMAMQPBYMCD6YSAYCBA | Plaintext credentials com.example.aws.s3.access_key are loaded in Java Properties getProperty(...) |
| configuration.properties:34:1:34:70 | com.example.aws.s3.secret_key=8lMPSfWzZq+wcWtck5+QPLOJDZzE783pS09/IO3k | Plaintext credentials com.example.aws.s3.secret_key are loaded in Java Properties getProperty(...) |

View File

@@ -18,98 +18,7 @@
*/
import java
import semmle.code.configfiles.ConfigFiles
import semmle.code.java.dataflow.FlowSources
private string possibleSecretName() {
result =
[
"%password%", "%passwd%", "%account%", "%accnt%", "%credential%", "%token%", "%secret%",
"%access%key%"
]
}
private string possibleEncryptedSecretName() { result = ["%hashed%", "%encrypted%", "%crypt%"] }
/** Holds if the value is not cleartext credentials. */
bindingset[value]
predicate isNotCleartextCredentials(string value) {
value = "" // Empty string
or
value.length() < 7 // Typical credentials are no less than 6 characters
or
value.matches("% %") // Sentences containing spaces
or
value.regexpMatch(".*[^a-zA-Z\\d]{3,}.*") // Contain repeated non-alphanumeric characters such as a fake password pass**** or ????
or
value.matches("@%") // Starts with the "@" sign
or
value.regexpMatch("\\$\\{.*\\}") // Variable placeholder ${credentials}
or
value.matches("%=") // A basic check of encrypted credentials ending with padding characters
or
value.matches("ENC(%)") // Encrypted value
or
// Could be a message property for UI display or fake passwords, e.g. login.password_expired=Your current password has expired.
value.toLowerCase().matches(possibleSecretName())
}
/** The credentials configuration property. */
class CredentialsConfig extends ConfigPair {
CredentialsConfig() {
this.getNameElement().getName().trim().toLowerCase().matches(possibleSecretName()) and
not this.getNameElement().getName().trim().toLowerCase().matches(possibleEncryptedSecretName()) and
not isNotCleartextCredentials(this.getValueElement().getValue().trim())
}
string getName() { result = this.getNameElement().getName().trim() }
string getValue() { result = this.getValueElement().getValue().trim() }
/** Returns a description of this vulnerability. */
string getConfigDesc() {
exists(
LoadCredentialsConfiguration cc, DataFlow::Node source, DataFlow::Node sink, MethodAccess ma
|
this.getName() = source.asExpr().(CompileTimeConstantExpr).getStringValue() and
cc.hasFlow(source, sink) and
ma.getArgument(0) = sink.asExpr() and
result = "Plaintext credentials " + this.getName() + " are loaded in " + ma
)
or
not exists(LoadCredentialsConfiguration cc, DataFlow::Node source, DataFlow::Node sink |
this.getName() = source.asExpr().(CompileTimeConstantExpr).getStringValue() and
cc.hasFlow(source, sink)
) and
result =
"Plaintext credentials " + this.getName() + " have cleartext value " + this.getValue() +
" in properties file"
}
}
/**
* A dataflow configuration tracking flow of a method that loads a credentials property.
*/
class LoadCredentialsConfiguration extends DataFlow::Configuration {
LoadCredentialsConfiguration() { this = "LoadCredentialsConfiguration" }
override predicate isSource(DataFlow::Node source) {
exists(CredentialsConfig cc |
source.asExpr().(CompileTimeConstantExpr).getStringValue() = cc.getName()
)
}
override predicate isSink(DataFlow::Node sink) {
sink.asExpr() =
any(MethodAccess ma |
ma.getMethod()
.getDeclaringType()
.getASupertype*()
.hasQualifiedName("java.util", "Properties") and
ma.getMethod().getName() = "getProperty"
).getArgument(0)
}
}
import experimental.semmle.code.java.frameworks.CredentialsInPropertiesFile
from CredentialsConfig cc
select cc, cc.getConfigDesc()

View File

@@ -0,0 +1,11 @@
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MailConfig {
@Value("${mail.password}")
private String mailPassword;
@Value("${mail.username}")
private String mailUserName;
}

View File

@@ -35,16 +35,6 @@ public class PropertiesUtils {
return properties.getProperty("datasource1.password");
}
/** Returns the mail account property value. */
public static String getMailUserName() {
return properties.getProperty("mail.username");
}
/** Returns the mail password property value. */
public static String getMailPassword() {
return properties.getProperty("mail.password");
}
/** Returns the AWS Access Key property value. */
public static String getAWSAccessKey() {
return properties.getProperty("com.example.aws.s3.access_key");

View File

@@ -0,0 +1 @@
// semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.2.3