Tuesday, September 23, 2014 At 9:25AM
Here at GDS we have noticed an increase in the use of the Scala programming language by our clients. We have been looking for good tools to perform static analysis of Scala to facilitate our code audits. Although there are static analysis tools for Scala, they are not capable of identifying security issues with their out of the box rule-sets. In this blog post we cover how FindBugs can be leveraged to scan Scala for the purposes of identifying insecure code patterns.
Why FindBugs?
FindBugs is an open source static analysis tool that detects bugs in Java applications. Unlike static analysis tools PMD or Jlint, FindBugs operates on bytecode rather than source code. Because Scala classes compile to Java bytecode, this means we can run FindBugs against them! Additionally, FindBugs exposes a plugin interface making it possible to write custom bug detectors to find vulnerabilities in Scala applications. It is possible to run FindBugs without custom detectors against a Scala code base, however there will certainly be false positives and false negatives since the bug detectors are tuned against javac compiler generated bytecode. To start finding security flaws we need to write Scala specific detectors. Finally, because FindBugs is a well-known open source project already common to developer toolchains, the learning curve for extending is potentially reduced and existing development workflows do not need to be altered. It is also worth mentioning that FindBugs is integrated into the enterprise security static analysis tool Fortify SCA, and so the approach we suggest here could be a low cost alternative for these organizations.
Implementing Your First Security Detector
We will implement a very small ‘Hello World’ detector which does nothing more than to flag every time a dangerous MongoDB function is executed. We will be writing a rule targeting Casbah, the official MongoDB driver for Scala. The Casbah library has an ‘eval’ method which can lead to the execution of arbitrary Javascript code if unvalidated user input is passed in. We will walk through how to write a rule to identify potential insecure usage of the Casbah ‘eval’ method within Scala applications.
For an introductory tutorial on how to write custom detector for FindBugs have a look at https://code.google.com/p/findbugs/wiki/DetectorPluginTutorial. For the rest of this blog post it will be assumed that you know the basics shown in the above link.
- Since we are operating on bytecode we will extend the BytecodeScanningDetector
- We will override the visit method, since it is called every time new code is executed.
- When we find the ‘eval’ method we will log a bug using the standard FindBugs logging interface.
We start with extending the BytecodeScanningDetector so Findbugs knows what code we are interested in.
public class HelloworldRule extends BytecodeScanningDetector {
Next, we declare the function we are looking for. Invokevirtual means that a new function is being invoked.
private final String VULNERABLE_METHOD = "com.mongodb.casbah.MongoDB.eval"; private final String FUNCTION_DECLARATION = "invokevirtual"; BugReporter bugReporter;
We also need to define a constructor which will take in a ‘bugreporter’ object which is used to report back found bugs to FindBugs.
public HelloworldRule(BugReporter bugReporter) { this.bugReporter = bugReporter; }
Next we chose to implement the visit function. The documentation around this method is a bit shorthanded but the returned object “represents a chunk of Java byte code contained in a method” according to the Javadocs. Using this method allows us to analyze a function line by line.
public void visit(Code someObj) {
ByteSequence stream = new ByteSequence(someObj.getCode());
while (stream.available() > 0) {
String line = Utility.codeToString(stream, someObj.getConstantPool(), true);
We use two helper functions to identify the function call. getCommand will give us the current instruction being executed. In this example we are mainly interested in the invokevirtual instruction mentioned above.
String command = getCommand(line);
We also use getFunction to parse out a function signature. It might look like the following:
com.mongodb.casbah.MongoClient$.apply (Ljava/lang/String;I)Lcom/mongodb/casbah/MongoClient
The signature will always start with the full package name followed by the function name. For this example, this is all we need. For more involved rules, the function arguments could also be analyzed.
String function = getFunction(line);
if(command.equals(FUNCTION_DECLARATION) &&
function.startsWith(VULNERABLE_METHOD)) {
If the function matches what we are looking for we will log a bug. We state that it’s a normal priority bug and we pass in an identifier which we will define below.
BugInstance instance = new BugInstance("MONGO_INJECTION",
NORMAL_PRIORITY).addClassAndMethod(this).addSourceLine(this);
bugReporter.reportBug(instance);
}
}
protected String getCommand(String line) {
String[] parts = line.split("\\t");
return (parts.length > 0) ? parts[0] : "";
}
protected String getFunction(String line) {
String[] parts = line.split("\\t");
return (parts.length > 1) ? parts[1] : "";
}
We also need to reference our new rule so FindBugs knows where to find it. Create a new folder in the project directory and name it “etc”. Create a new file called findbugs.xml in this folder. In here we can reference the rule by adding the following text:
<FindbugsPlugin>
<Detector class="com.package.HelloworldRule" speed="fast" />
</FindbugsPlugin>
Lastly we need to give a short description of our plugin. Create a new file called messages.xml in that same folder. Put the following content in there:
<MessageCollection> <Detector class="com.package.HelloworldRule"> <Details> <p> A Simple Mongo Injection Detection Rule</p> </Details> </Detector> </MessageCollection>
The plugin is now ready to go, let’s give it a test!
Running FindBugs is pretty simple, all you need to do is to download the Jar and specify the source to run against. Adding new plugins is simple as well. You can either supply the plugin jar as a command line argument or you can add it to the default plugins folder for FindBugs. For this example we’ll add it on the command line:
java -jar /path-to-findbugs/findbugs.jar -textui -pluginList /path-to-your-new-jar.jar -home . -auxclasspath /path-to-scala-installation/:casbah-alldep.jar /path-to-class-files/
It is important to specify the auxclasspath option since this is how we will specify the classpath to the Scala installation. If the auxclasspath is not set, running Findbugs on Scala code will result in various errors. Additionally we add the Casbah jar to the path since it is a dependency to our sample application. Any other dependencies to the application being scanned should be added to the auxclasspath option when running FindBugs. The sample output below shows how FindBugs will report usage of the Casbah eval function within a Scala application.
M S GDS: A Simple Mongo Injection Detection Rule. At CasbahExample.scala:[line 18]
This is just a short introduction on how to leverage FindBugs to analyze Scala code. Hopefully this code can be used as a foundation to write more involved and more complex rules. Popular web frameworks such as Play and Vert.x run in Scala and FindBugs can certainly be used to evaluate them.
The code referenced in this blog post can be found on our GitHub page: https://github.com/GDSSecurity/Scala-Findbugs-Sample
Author: Erik Larsson
©Aon plc 2023