Writing a detector
FindSecurityBugs is project that support mostly Test Driven Development. Their are few reason why testing is crucial to the project.
- First, you don't want to reload the plugin in an IDE or an external tool each time you need to test your rules. You can run quickly FindSecurityBugs against specific samples.
- Second, the number of code variation is infinite. When rules or utility classes are modified, we need to make sure that nothing was broken.
- Third, test samples are importants because it's easy to write a rule that seems to find the right signature but doesn't. (Blacebo code)
First create a simple class that illustrate the weakness you are trying to illustrate. Vulnerable sample are place in
find-sec-bugs/plugin/src/test/java/testcode
.
The code sample doesn't need to be a working application. Write the minimum code to trigger your rule.
For example, this class is create to illustrate deserialization of XML done with XMLDecoder
:
public class XmlDecodeUtil {
public static Object handleXml(InputStream in) {
XMLDecoder d = new XMLDecoder(in);
try {
return d.readObject(); //Deserialization happen here
}
finally {
d.close();
}
}
}
You can copy-paste the basic test structure from a other test class. For example, here is a test that will validate that XmlDecodeUtil
source will trigger the vulnerability "XML_DECODER" at the line 9.
public class XmlDecoderDetectorTest extends BaseDetectorTest {
@Test
public void detectXmlDecoder() throws Exception {
//Locate test code
String[] files = {
getClassFilePath("testcode/xmldecoder/XmlDecodeUtil")
};
//Run the analysis
EasyBugReporter reporter = spy(new EasyBugReporter());
analyze(files, reporter);
//Assertions
verify(reporter).doReportBug(
bugDefinition()
.bugType("XML_DECODER")
.inClass("XmlDecodeUtil").inMethod("handleXml").atLine(9)
.build()
);
}
}
You can run test and it should failed as you have not written any detector to identify the issue.
findbugs.xml
<Detector class="com.h3xstream.findsecbugs.XmlDecoderDetector" reports="XML_DECODER"/>
[...]
<BugPattern type="XML_DECODER" abbrev="XMLDEC" category="SECURITY"/>
The class reference will soon be created.
You need to create the appropriate description in the messages.xml
. You can leave the Details
XML node empty at this point and fill it later.
messages.xml
<!-- XML decoder -->
<Detector class="com.h3xstream.findsecbugs.XmlDecoderDetector">
<Details>Identify use of XMLDecoder (a dangerous XML serializer).</Details>
</Detector>
<BugPattern type="XML_DECODER">
<ShortDescription>XMLDecoder usage</ShortDescription>
<LongDescription>It is not safe to use an XMLDecoder to parse user supplied data</LongDescription>
<Details>
<![CDATA[
<p>
XMLDecoder should not be used to parse untrusted data. Deserializing user input can lead to arbitrary code execution.
This is possible because XMLDecoder supports arbitrary method invocation. This capability is intended to call setter methods,
but in practice, any method can be called.
</p>
[...]
]]>
</Details>
</BugPattern>
<BugCode abbrev="XMLDEC">XMLDecoder usage</BugCode>
There are many possibility in order to implements a detector.
- OpcodeStackDetector : Look for a specific method call
- ConfiguredBasicInjectionDetector : To implement an injection-like detector
- Detector : To analyze the complete class context
In order to detect the constructor call, we will use the InstructionDSL
utility.
import static com.h3xstream.findsecbugs.common.matcher.InstructionDSL.*;
public class XmlDecoderDetector extends OpcodeStackDetector {
private static final String XML_DECODER = "XML_DECODER";
private static InvokeMatcherBuilder XML_DECODER_CONSTRUCTOR = invokeInstruction().atClass("java/beans/XMLDecoder").atMethod("<init>");
private BugReporter bugReporter;
public XmlDecoderDetector(BugReporter bugReporter) {
this.bugReporter = bugReporter;
}
@Override
public void sawOpcode(int seen) {
if (seen == Constants.INVOKESPECIAL && XML_DECODER_CONSTRUCTOR.matches(this)) {
bugReporter.reportBug(new BugInstance(this, XML_DECODER, Priorities.HIGH_PRIORITY) //
.addClass(this).addMethod(this).addSourceLine(this));
}
}
}
Here are additional articles about more advanced detectors that were implemented in Find Security Bugs.
- Taint analysis added to FindBugs | YSofters by David Formanek
- Detection of hard-coded passwords improved | YSofters by David Formanek
- Extending FindBugs to detect hard-coded passwords | YSofters by David Formanek
Find Security Bugs : Website | OWASP Page