Added query for Cleartext Storage in Android Filesystem

This commit is contained in:
Tony Torralba
2021-09-03 13:24:31 +02:00
parent 6a53b7b233
commit c1ac09a063
12 changed files with 642 additions and 14 deletions

View File

@@ -115,6 +115,7 @@ private module Frameworks {
private import semmle.code.java.security.AndroidIntentRedirection
private import semmle.code.java.security.ResponseSplitting
private import semmle.code.java.security.InformationLeak
private import semmle.code.java.security.Files
private import semmle.code.java.security.GroovyInjection
private import semmle.code.java.security.JexlInjectionSinkModels
private import semmle.code.java.security.JndiInjection
@@ -258,20 +259,6 @@ private predicate sinkModelCsv(string row) {
"java.net;URLClassLoader;false;URLClassLoader;(String,URL[],ClassLoader);;Argument[1];open-url",
"java.net;URLClassLoader;false;URLClassLoader;(String,URL[],ClassLoader,URLStreamHandlerFactory);;Argument[1];open-url",
"java.net;URLClassLoader;false;newInstance;;;Argument[0];open-url",
// Create file
"java.io;FileOutputStream;false;FileOutputStream;;;Argument[0];create-file",
"java.io;RandomAccessFile;false;RandomAccessFile;;;Argument[0];create-file",
"java.io;FileWriter;false;FileWriter;;;Argument[0];create-file",
"java.nio.file;Files;false;move;;;Argument[1];create-file",
"java.nio.file;Files;false;copy;;;Argument[1];create-file",
"java.nio.file;Files;false;newOutputStream;;;Argument[0];create-file",
"java.nio.file;Files;false;newBufferedReader;;;Argument[0];create-file",
"java.nio.file;Files;false;createDirectory;;;Argument[0];create-file",
"java.nio.file;Files;false;createFile;;;Argument[0];create-file",
"java.nio.file;Files;false;createLink;;;Argument[0];create-file",
"java.nio.file;Files;false;createSymbolicLink;;;Argument[0];create-file",
"java.nio.file;Files;false;createTempDirectory;;;Argument[0];create-file",
"java.nio.file;Files;false;createTempFile;;;Argument[0];create-file",
// Bean validation
"javax.validation;ConstraintValidatorContext;true;buildConstraintViolationWithTemplate;;;Argument[0];bean-validation",
// Set hostname

View File

@@ -0,0 +1,101 @@
/**
* Provides classes and predicates to reason about cleartext storage in the Android filesystem
* (external or internal storage).
*/
import java
import semmle.code.java.dataflow.DataFlow
import semmle.code.java.dataflow.ExternalFlow
import semmle.code.java.security.CleartextStorageQuery
import semmle.code.java.security.Files
import semmle.code.xml.AndroidManifest
private class AndroidFilesystemCleartextStorageSink extends CleartextStorageSink {
AndroidFilesystemCleartextStorageSink() {
filesystemInput(_, this.asExpr()) and
// Make sure we are in an Android application.
exists(AndroidManifestXmlFile manifest)
}
}
/** The creation of an object that can be used to write to files to the local filesystem. */
class LocalFileOpenCall extends Storable {
LocalFileOpenCall() {
this = any(DataFlow::Node sink | sinkNode(sink, "create-file")).asExpr().(Argument).getCall()
}
override Expr getAnInput() {
exists(FilesystemFlowConfig conf, DataFlow::Node n |
filesystemInput(n, result) and
conf.hasFlow(DataFlow::exprNode(this), n)
)
}
override Expr getAStore() {
exists(FilesystemFlowConfig conf, DataFlow::Node n |
filesystemStore(n, result) and
conf.hasFlow(DataFlow::exprNode(this), n)
)
}
}
/** Holds if `input` is written into `file`. */
private predicate filesystemInput(DataFlow::Node file, Argument input) {
exists(DataFlow::Node write | sinkNode(write, "write-file") |
input = write.asExpr() or
isVarargs(input, write)
) and
if input.getCall().getCallee().isStatic()
then file.asExpr() = input.getCall()
else file.asExpr() = input.getCall().getQualifier()
}
/** Holds if `arg` is part of `varargs`. */
private predicate isVarargs(Argument arg, DataFlow::ImplicitVarargsArray varargs) {
arg.isVararg() and arg.getCall() = varargs.getCall()
}
/** Holds if `store` closes `file`. */
private predicate filesystemStore(DataFlow::Node file, Call store) {
store.getCallee() instanceof CloseFileMethod and
if store.getCallee().isStatic()
then file.asExpr() = store
else file.asExpr() = store.getQualifier()
or
// try-with-resources automatically closes the file
any(TryStmt try).getAResource() = store.(LocalFileOpenCall).getEnclosingStmt() and
store = file.asExpr()
}
/** A method that closes a file. */
private class CloseFileMethod extends Method {
CloseFileMethod() {
this.hasQualifiedName("java.io", ["RandomAccessFile", "FileOutputStream", "PrintStream"],
"close")
or
this.getDeclaringType().getASupertype*().hasQualifiedName("java.io", "Writer") and
this.hasName("close")
or
this.hasQualifiedName("java.nio.file", "Files", ["write", "writeString"])
}
}
private class FilesystemFlowConfig extends DataFlow::Configuration {
FilesystemFlowConfig() { this = "FilesystemFlowConfig" }
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof LocalFileOpenCall }
override predicate isSink(DataFlow::Node sink) {
filesystemInput(sink, _) or
filesystemStore(sink, _)
}
override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
// Add nested Writer constructors as extra data flow steps
exists(ClassInstanceExpr cie |
cie.getConstructedType().getASupertype*().hasQualifiedName("java.io", "Writer") and
node1.asExpr() = cie.getArgument(0) and
node2.asExpr() = cie
)
}
}

View File

@@ -0,0 +1,70 @@
import java
import semmle.code.java.dataflow.ExternalFlow
private class CreateFileSinkModels extends SinkModelCsv {
override predicate row(string row) {
row =
[
"java.io;FileOutputStream;false;FileOutputStream;;;Argument[0];create-file",
"java.io;RandomAccessFile;false;RandomAccessFile;;;Argument[0];create-file",
"java.io;FileWriter;false;FileWriter;;;Argument[0];create-file",
"java.io;PrintStream;false;PrintStream;(File);;Argument[0];create-file",
"java.io;PrintStream;false;PrintStream;(File,String);;Argument[0];create-file",
"java.io;PrintStream;false;PrintStream;(File,Charset);;Argument[0];create-file",
"java.io;PrintStream;false;PrintStream;(String);;Argument[0];create-file",
"java.io;PrintStream;false;PrintStream;(String,String);;Argument[0];create-file",
"java.io;PrintStream;false;PrintStream;(String,Charset);;Argument[0];create-file",
"java.io;PrintWriter;false;PrintWriter;(File);;Argument[0];create-file",
"java.io;PrintWriter;false;PrintWriter;(File,String);;Argument[0];create-file",
"java.io;PrintWriter;false;PrintWriter;(File,Charset);;Argument[0];create-file",
"java.io;PrintWriter;false;PrintWriter;(String);;Argument[0];create-file",
"java.io;PrintWriter;false;PrintWriter;(String,String);;Argument[0];create-file",
"java.io;PrintWriter;false;PrintWriter;(String,Charset);;Argument[0];create-file",
"java.nio.file;Files;false;copy;;;Argument[1];create-file",
"java.nio.file;Files;false;createDirectories;;;Argument[0];create-file",
"java.nio.file;Files;false;createDirectory;;;Argument[0];create-file",
"java.nio.file;Files;false;createFile;;;Argument[0];create-file",
"java.nio.file;Files;false;createLink;;;Argument[0];create-file",
"java.nio.file;Files;false;createSymbolicLink;;;Argument[0];create-file",
"java.nio.file;Files;false;createTempDirectory;;;Argument[0];create-file",
"java.nio.file;Files;false;createTempFile;(Path,String,String,FileAttribute[]);;Argument[0];create-file",
"java.nio.file;Files;false;move;;;Argument[1];create-file",
"java.nio.file;Files;false;newBufferedWriter;;;Argument[0];create-file",
"java.nio.file;Files;false;newOutputStream;;;Argument[0];create-file",
"java.nio.file;Files;false;write;;;Argument[0];create-file",
"java.nio.file;Files;false;writeString;;;Argument[0];create-file"
]
}
}
private class WriteFileSinkModels extends SinkModelCsv {
override predicate row(string row) {
row =
[
"java.io;FileOutputStream;false;write;;;Argument[0];write-file",
"java.io;RandomAccessFile;false;write;;;Argument[0];write-file",
"java.io;RandomAccessFile;false;writeBytes;;;Argument[0];write-file",
"java.io;RandomAccessFile;false;writeChars;;;Argument[0];write-file",
"java.io;RandomAccessFile;false;writeUTF;;;Argument[0];write-file",
"java.io;Writer;true;append;;;Argument[0];write-file",
"java.io;Writer;true;write;;;Argument[0];write-file",
"java.io;PrintStream;true;append;;;Argument[0];write-file",
"java.io;PrintStream;true;format;(String,Object[]);;Argument[0..1];write-file",
"java.io;PrintStream;true;format;(Locale,String,Object[]);;Argument[1..2];write-file",
"java.io;PrintStream;true;print;;;Argument[0];write-file",
"java.io;PrintStream;true;printf;(String,Object[]);;Argument[0..1];write-file",
"java.io;PrintStream;true;printf;(Locale,String,Object[]);;Argument[1..2];write-file",
"java.io;PrintStream;true;println;;;Argument[0];write-file",
"java.io;PrintStream;true;write;;;Argument[0];write-file",
"java.io;PrintStream;true;writeBytes;;;Argument[0];write-file",
"java.io;PrintWriter;false;format;(String,Object[]);;Argument[0..1];write-file",
"java.io;PrintWriter;false;format;(Locale,String,Object[]);;Argument[1..2];write-file",
"java.io;PrintWriter;false;print;;;Argument[0];write-file",
"java.io;PrintWriter;false;printf;(String,Object[]);;Argument[0..1];write-file",
"java.io;PrintWriter;false;printf;(Locale,String,Object[]);;Argument[1..2];write-file",
"java.io;PrintWriter;false;println;;;Argument[0];write-file",
"java.nio.file;Files;false;write;;;Argument[1];write-file",
"java.nio.file;Files;false;writeString;;;Argument[1];write-file"
]
}
}