From 6a238a497c080cacc8d6cf35289905954537f42a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Pluta?= Date: Fri, 5 Apr 2019 17:01:05 +0200 Subject: [PATCH] 10: Create ImplicitIntentsPlugin --- .../com/bartek/esa/core/di/CoreModule.java | 6 ++ .../com/bartek/esa/core/di/PluginModule.java | 7 ++ .../core/java/JavaSyntaxRegexProvider.java | 31 ++++++++ .../core/plugin/ImplicitIntentsPlugin.java | 74 +++++++++++++++++++ src/main/resources/description.properties | 7 +- 5 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/bartek/esa/core/java/JavaSyntaxRegexProvider.java create mode 100644 src/main/java/com/bartek/esa/core/plugin/ImplicitIntentsPlugin.java diff --git a/src/main/java/com/bartek/esa/core/di/CoreModule.java b/src/main/java/com/bartek/esa/core/di/CoreModule.java index bafe8ec..abb9f9d 100644 --- a/src/main/java/com/bartek/esa/core/di/CoreModule.java +++ b/src/main/java/com/bartek/esa/core/di/CoreModule.java @@ -2,6 +2,7 @@ package com.bartek.esa.core.di; import com.bartek.esa.core.desc.provider.DescriptionProvider; import com.bartek.esa.core.executor.PluginExecutor; +import com.bartek.esa.core.java.JavaSyntaxRegexProvider; import com.bartek.esa.core.xml.XmlHelper; import dagger.Module; import dagger.Provides; @@ -19,6 +20,11 @@ public class CoreModule { return new DescriptionProvider(); } + @Provides + public JavaSyntaxRegexProvider javaSyntaxRegexProvider() { + return new JavaSyntaxRegexProvider(); + } + @Provides public XmlHelper xmlHelper() { return new XmlHelper(); diff --git a/src/main/java/com/bartek/esa/core/di/PluginModule.java b/src/main/java/com/bartek/esa/core/di/PluginModule.java index c2c7dde..3718954 100644 --- a/src/main/java/com/bartek/esa/core/di/PluginModule.java +++ b/src/main/java/com/bartek/esa/core/di/PluginModule.java @@ -1,6 +1,7 @@ package com.bartek.esa.core.di; import com.bartek.esa.core.archetype.Plugin; +import com.bartek.esa.core.java.JavaSyntaxRegexProvider; import com.bartek.esa.core.plugin.*; import com.bartek.esa.core.xml.XmlHelper; import com.bartek.esa.file.matcher.GlobMatcher; @@ -50,4 +51,10 @@ public class PluginModule { public Plugin secureRandomPlugin(GlobMatcher globMatcher, XmlHelper xmlHelper) { return new SecureRandomPlugin(globMatcher, xmlHelper); } + + @Provides + @IntoSet + public Plugin implicitIntentsPlugin(GlobMatcher globMatcher, XmlHelper xmlHelper, JavaSyntaxRegexProvider javaSyntaxRegexProvider) { + return new ImplicitIntentsPlugin(globMatcher, xmlHelper, javaSyntaxRegexProvider); + } } diff --git a/src/main/java/com/bartek/esa/core/java/JavaSyntaxRegexProvider.java b/src/main/java/com/bartek/esa/core/java/JavaSyntaxRegexProvider.java new file mode 100644 index 0000000..552c193 --- /dev/null +++ b/src/main/java/com/bartek/esa/core/java/JavaSyntaxRegexProvider.java @@ -0,0 +1,31 @@ +package com.bartek.esa.core.java; + +import com.github.javaparser.ast.expr.Expression; + +import javax.inject.Inject; +import java.util.regex.Pattern; + +public class JavaSyntaxRegexProvider { + + @Inject + public JavaSyntaxRegexProvider() { + + } + + public Pattern constant() { + return Pattern.compile("^[A-Z0-9_$]*$"); + } + + public boolean isConstant(Expression expression) { + String value = expression.toString(); + if(expression.isNameExpr() && constant().matcher(value).matches()) { + return true; + } + + if(expression.isFieldAccessExpr()) { + return constant().matcher(expression.asFieldAccessExpr().getName().getIdentifier()).matches(); + } + + return false; + } +} diff --git a/src/main/java/com/bartek/esa/core/plugin/ImplicitIntentsPlugin.java b/src/main/java/com/bartek/esa/core/plugin/ImplicitIntentsPlugin.java new file mode 100644 index 0000000..7e104b3 --- /dev/null +++ b/src/main/java/com/bartek/esa/core/plugin/ImplicitIntentsPlugin.java @@ -0,0 +1,74 @@ +package com.bartek.esa.core.plugin; + +import com.bartek.esa.core.archetype.JavaPlugin; +import com.bartek.esa.core.java.JavaSyntaxRegexProvider; +import com.bartek.esa.core.model.enumeration.Severity; +import com.bartek.esa.core.xml.XmlHelper; +import com.bartek.esa.file.matcher.GlobMatcher; +import com.github.javaparser.ast.CompilationUnit; +import com.github.javaparser.ast.NodeList; +import com.github.javaparser.ast.body.VariableDeclarator; +import com.github.javaparser.ast.expr.*; + +import javax.inject.Inject; +import java.util.List; +import java.util.stream.Collectors; + +public class ImplicitIntentsPlugin extends JavaPlugin { + private final JavaSyntaxRegexProvider java; + + @Inject + public ImplicitIntentsPlugin(GlobMatcher globMatcher, XmlHelper xmlHelper, JavaSyntaxRegexProvider javaSyntaxRegexProvider) { + super(globMatcher, xmlHelper); + this.java = javaSyntaxRegexProvider; + } + + @Override + public void run(CompilationUnit compilationUnit) { + List intentVariables = getIntentVariables(compilationUnit); + findAllSetActionMethodInvocations(compilationUnit, intentVariables); + compilationUnit.findAll(ObjectCreationExpr.class).stream() + .filter(expr -> expr.getType().getName().getIdentifier().equals("Intent")) + .filter(this::checkConstructor) + .forEach(objectCreation -> addIssue(Severity.INFO, getLineNumberFromExpression(objectCreation), objectCreation.toString())); + + } + + private boolean checkConstructor(ObjectCreationExpr objectCreation) { + NodeList arguments = objectCreation.getArguments(); + boolean isImplicit = false; + if (arguments.size() == 1) { + Expression argument = arguments.get(0); + isImplicit = java.isConstant(argument); + } + + if(arguments.size() == 2) { + Expression argument = arguments.get(0); + isImplicit = !argument.isThisExpr(); + } + + return isImplicit; + } + + private void findAllSetActionMethodInvocations(CompilationUnit compilationUnit, List intentVariables) { + compilationUnit.findAll(MethodCallExpr.class).forEach(methodCall -> { + boolean isCalledOnIntentObject = methodCall.getScope() + .map(Expression::toString) + .filter(intentVariables::contains) + .isPresent(); + if(isCalledOnIntentObject && methodCall.getName().getIdentifier().equals("setAction")) { + addIssue(Severity.INFO, getLineNumberFromExpression(methodCall), methodCall.toString()); + } + }); + } + + private List getIntentVariables(CompilationUnit compilationUnit) { + return compilationUnit.findAll(VariableDeclarationExpr.class).stream() + .filter(expr -> expr.getElementType().toString().equals("Intent")) + .map(VariableDeclarationExpr::getVariables) + .flatMap(NodeList::stream) + .map(VariableDeclarator::getName) + .map(SimpleName::getIdentifier) + .collect(Collectors.toList()); + } +} diff --git a/src/main/resources/description.properties b/src/main/resources/description.properties index 5f75bcc..4f0141d 100644 --- a/src/main/resources/description.properties +++ b/src/main/resources/description.properties @@ -49,4 +49,9 @@ com.bartek.esa.core.plugin.PermissionsRaceConditionPlugin=Potential permissions com.bartek.esa.core.plugin.SecureRandomPlugin=Initializing SecureRandom object with custom seed. \n\ Specifying custom seed for SecureRandom can produce predictable sequence of numbers. \n\ - Please create SecureRandom object without any arguments instead. \ No newline at end of file + Please create SecureRandom object without any arguments instead. + +com.bartek.esa.core.plugin.ImplicitIntentsPlugin=Creating implicit intent. Potential data leakage. \n\ + Implicit intents can be abused in man-in-the-middle attack. Malicious application can hijack intent and start its\n\ + activity/send service etc. to steal sent data. \n\ + Also make sure that no sensitive information is passing to this intent. \ No newline at end of file