Security Dataflow - Manually configuring blackbox methods


Overview

When analyzing an application, this application has a defined analysis scope - i.e. some code is analyzed, some is not and is treated as external code. Any external code is “unknown” and cannot be accessed by the analyzer, and as such cannot be taken into account in the normal manner by the User Input Security feature. Therefore, security problems in this external source code would normally not be detected at all.

In order to resolve this problem, CAST uses the notion of Automatic Blackboxing methods as discussed in Security Dataflow. If the Automatic Blackboxing feature does not handle external code in the correct way then the recommended action is to create a black box manually to alter the way the automatic process functions. Once the blackbox has been created, a new snapshot should be generated to ensure the manual blackbox is taken into account.

Configuring a blackbox

A simple XML file is used to configure a blackbox method - this XML file is then taken into account at analysis time and the instructions in the file indicate what the analyzer should do in specific situation.

Basic configuration

  • Identify the method that needs to be black boxed: for an external method, it will belong to a .jar file or to a .NET assembly; for an internal method, it will be in the analyzed application source code.
  • Write an XML file with the extension .blackbox.xml containing the identification (package, host type, name, signature, etc.) of the method that needs to be black boxed. You can configure one or multiple methods in one XML file, or one or multiple methods in multiple XML files.
  • Put the XML file in the following location (files for all supported technologies can be put in this location - there is no need to separate them into technology specific sub-folders). If this folder does not exist, please create it manually:

%PROGRAMDATA%\CAST\CAST\[major_ver.minor_ver]\blackboxes

  • Ensure Security Dataflow is enabled for your technology, then run the analysis.

Use cases

  • You can black box an external method which is not yet black boxed by any of the black box configuration files provided by default by CAST.
  • You can override the black box of an external method which is already black boxed by default by CAST. In this case, the newly defined black box of such a method will replace the current configuration so that you can change the behavior of a black box method as defined by CAST.
  • You can black box an internal method (for example this may be useful for bypassing a limitation of the source code analyzer).
  • You can limit a blackbox configuration file to one single rule (and any reflected/persisted and/or “through API” associated rules), for example, you may want to blackbox specific methods and see results specific to a single rule. To do so, you should name your blackbox XML file using the following syntax, where [Quality rule ID] is equal to the rule you want to target and where XXX is free text:

QR[Quality rule ID]-XXXX.blackbox.xml

For example, to limit results only to the rule 8414 “Avoid weak cryptographic algorithm”, you could use the following name:

QR8414-Avoid_weak_cryptographic_algorithm.blackbox.xml

Writing a .blackbox.xml configuration file

The blackbox language is an xml-based language to help the user to describe external object semantics. Technically, blackbox files are translated into CAST Intermediate Language files (castil), which is the sort of assembly code that the User Input Security engine understands. In other words, the blackbox formalism uses the same concepts as programming languages (classes, interfaces and methods).

  • Each blackbox file corresponds to a jar file or dll (depending on if you are in the JEE or .NET world).
  • Each blackbox contains types (classes or interfaces)
  • Each type (class or interface) contains methods
  • Each method contains a flows
  • A flow explains where the data goes, from a source to a sink

You can use the blackbox XSD schema to help you write your blackbox XML files.

Example with java.util.Collections

This is a valid blackbox file that describes the semantics of java.util.Collection:

<Blackbox name="my_rt.jar" xmlns="http://tempuri.org/BlackBoxes.xsd">
	<Interface id="1" mangling="java.util.Collection">
		<Methods>
			<Method signature="add(java.lang.Object)">
				<Flow source="1" sink="0" mode="alternative" />
			</Method>
			<Method signature="clear()">
				<Flow source="0" sink="0" mode="clear" />
			</Method>
			<Method signature="iterator()">
				<Flow source="0" sink="-1" mode="assign" />
			</Method>
			<Method signature="toArray()">
				<Flow source="0" sink="-1" mode="assign" />
			</Method>
		</Methods>
	</Interface>
</BlackBox>

Blackbox name

The blackbox name is the id of your blackbox. Each black box file must have a unique name. If two blackboxes have the same name, only the last one will be kept.

Blackbox Types (Class or Interface)

Similarly to programming languages, blackboxes have types. Types are useful so you can avoid rewriting the same method behavior when an inheritance relationship is sufficient.

  • Mangling > The mangling type is the non-ambiguous name of the type. There are several ways to find out the mangling of a type:
    • User input security analyzer log files
    • Online documentation (docs.oracle.com, msdn.microsoft.com, etc.)
    • CAST Enlighten (this is by far the simplest way to do this)
    • Decompiler
  • Inheritance > There are two types of inheritance:
    • Extends
    • Implements

Extends example: the fact that java.util.List extends java.util.Collection will automatically copy the method add(java.lang.Object) into java.util.List. Moreover, an override relationship is added between the two add methods:

<BlackBox name="rt.jar" xmlns="http://tempuri.org/BlackBoxes.xsd">
	<Interface id="1" mangling="java.util.Collection">
		<Methods>
			<Method signature="add(java.lang.Object)">
				<Flow source="1" sink="0" mode="alternative" />
			</Method>
		</Methods>
	</Interface>
	<Interface id="2" mangling="java.util.List" extends id="1" debugMangling="java.util.Collection" />
	</Interface>
</BlackBox> 

Implements example: the behavior is the same as extends. The fact that java.util.ArrayList implements java.util.Collection will automatically copy the method add(java.lang.Object) into java.util.ArrayList. Moreover, an override relationship is added between the three add methods:

<Class id="3" mangling="java.util.ArrayList">
	<Implements id="1" debugMangling="java.util.Collection" />
	<Implements id="2" debugMangling="java.util.List" />
</Class>

Blackbox method

Similarly to programming languages, blackboxes have methods. Example:

<Method signature="add(java.lang.Object)">
	<Flow source="1" sink="0" mode="alternative" />
</Method>
  • Method Signature > The signature of the method is the mangling of the method, without the mangling of its type. Generally, it is the name of the method, followed by the mangling of its parameter types. To obtain the signature of a method, please refer to:
    • User input security analyzer log files
    • Online documentation (docs.oracle.com, msdn.microsoft.com, etc.)
    • CAST Enlighten
    • Decompiler
  • Blackbox method body: flows > The flows are arrows showing from where to where the data goes. In other words, the general pattern of a flow description is:
<Flow source=<source argument> sink==<sink argument> mode= <flow-mode> />

The <source argument> is the method’s argument number from the data comes:

  • -1 is the returned value
  • 0 is “this” pointer
  • 1 is the first argument
  • 2 is the second argument
  • n is the nth argument

The <sink argument> is the method’s argument number where the data goes:

  • -1 is the returned value
  • 0 is “this” pointer

The <flow-mode> explains how the data moves:

  • clear means: sink < null
  • assign means: sink < source
  • alternative means: sink < sink OR source
  • append means: sink < StringContatenation (sink, source)
Flow Clear example:
<Method signature="clear()">
	<Flow sink="0" mode="clear" />
</Method>

After calling clear, “this” pointer is emptied:

public Collection flowClearExample()
{
Collection col = buildCollectionWith("a");

col.clear();

return col;
}

Before calling clear(), the collection contains a. After calling clear(), the collection contains nothing. The returned value is an empty collection.

Flow Assign example:
<Method signature="set(int,java.lang.Object)">
	<Flow source="2" sink="0" mode="assign" />
</Method>

After calling set, the value of “this” pointer is replaced with the value of argument #2:

public Collection flowAssignExample()
{
List l = buildListWith("a");

l.set(0, buildListWith("b"));

return l;
}

Let’s suppose buildListWith is a helper function that builds a list with the given arguments. Before calling set(), the list contains a. After calling set(), the list contains b. The returned value is a collection that contains only b.

Flow Alternative example
<Method signature="add(java.lang.Object)">
	<Flow source="1" sink="0" mode="alternative" />
</Method>

Means: the new value of “this” pointer is one of these values:

  • The previous value of “this” pointer
  • The value of argument one

Now, if we have a look at some java source code using this blackbox:

public Collection flowAlternativeExample()
{
	Collection col = buildCollectionWith("a");

	col.add("b");

	return col;
}

Let’s suppose buildCollectionWith is a helper function that builds a collection with the given arguments. At the beginning, col contains a single string: a. After calling add, the new value of col is:

  • The previous value of “this” pointer, that means col itself, that is {"a"}.
  • The value of argument one, that is {"b"}

To summarize, the possible values are: {"a", "b"}. In conclusion, we have simulated the behavior of collections with the flow mode="alternative".

Flow Append example
<Method signature="concat(java.lang.String)">
	<Flow source="1" sink="0" mode="append" />
</Method>

This means that the new “this” value will contain the concatenation of its previous value, and the argument #1.

public String flowAppendExample()
{
String str = "a";

str.concat("b");

return str;
}

Before concat, the value of str is: a. After concat, the value of str is : ab.