Page tree
Skip to end of metadata
Go to start of metadata

On this page:

Target audience:

CAST Administrators

Summary: this page explains how to configure "blackbox methods" for the User Input Security feature.

Introduction

When analyzing a source code 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 is not taken into account 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 has introduced the notion of blackbox methods: by telling the User Input Security feature how methods in external code behave, flaw and security vulnerabilities can be detected even though the method itself is not actually analyzed.

Another situation where blackbox method configuration can be used successfully is when CAST's source code analyzers are confronted with a limitation that prevents them from producing all the necessary information for the User Input Security feature even when the entire source code of an application is available and analyzed. This can occur, for example, when a method produces and then executes some dynamically generated code using Reflection.Emit in .NET. If you know what the dynamically generated code does, then you can write a blackbox method that emulates its behavior in terms of input(s) and output(s) for the User Input Security feature - in exactly the same way as is done for external methods.

In summary, configuring blackbox methods means that the analysis of security problems will never be stopped because of unknown or external source code and the analyses will not be prevented from detecting and flagging User Input Security flaws.

Example of why you may need to configure blackbox methods

The following sample code uses an external class called ExternalObject, on which we have no implementation, since ExternalObject is out of the application analysis scope.

public void run(ExternalObject o)
 {
 String flaw= getFlawItem();
 o.setValue(flaw);
 String value= o.getValue();
 String query = "select username from users where id=" + value;
 executeSqlQuery(query);
 }

On the other hand, we know there is a potential SQL Injection starting from:

String flaw= getFlawItem();

//and ending in:

executeSqlQuery(query);

 

getFlawItem cab considered as a specific user input method (parameterized in the User Input Security tab) and executeSqlQuery can be considered as a specific target method (parameterized in the User Input Security tab):

Unfortunately, if we try to detect security flaws on this sample code, the analyzer will not detect anything: it will be stopped because there is no implementation found for setValue:


What can we do?

A workaround would be to add the source code of this external class into the application's scope. However, this approach is not advisable because:

  • This external class will be processed as if it was in your application, Quality Rules will be calculated on it and your application results will be impacted
  • This external class also depends on other external classes, and their source code will need to be analyzed too. And so on...

This is precisely where configuring a blackbox can resolve the issue and avoid the workaround: you can describe the behavior of the external object in terms of data flow, without using the actual source code of these external objects.

If we go back to the example, here is the class that need to be "blackboxed":

class ExternalObject
{
void setValue(Object value);
Object getValue();
}

For these two methods, we will specify the behavior as (in pseudo code):

class ExternalObject
{
    void setValue(Object value) =>   put "value"  into "this"  
    Object getValue() =>  return "this"
}

With this new information, the analyzer will able to traverse these two external methods, and reach "executeSqlQuery", which is the target of the security flaw.

In the figure below, the arrows symbolize the data flow engine's deductions. The blue arrows are those automatically computed by CAST. Green arrows are deduced thanks to the blackboxes we have provided:

Finding out which methods need blackboxing

Whilst it is possible to manually work out which methods need to be blackboxed, this can be a time consuming task. CAST has therefore provided a mechanism for you find out which methods have either not been found or have caused the User Input Security feature to stop and pass on to the next method.

To use this mechanism, you need to first generate a Snapshot - this will cause the User Input Security analyzer to be invoked and run. On completion of the snapshot, you can consult the User Input Security analyzer log to find out which methods require blackboxing. The log file in question is called SecurityAnalyzer.log.secondary - this is located in the same folder as the main SecurityAnalyzer.log. You can access the log file as follows:

  • On completion of the snapshot, click the Run J2EE Data Flow Security for "<application_name>" item in the snapshot summary window:

  • In the lower half of the summary window, you will see the location of the SecurityAnalyzer.log file.
  • Browse to this location using Windows Explorer and locate and open the SecurityAnalyzer.log.secondary log file with a text editor.

Example:

Let's suppose we are using an external method called doFinal. The method doFinal is located for example in rt.jar. There is no source code available for it as rt.jar is outside the analysis scope and is therefore considered external:

package mypackage;

class myClass
{
public javax.crypto.Cipher aes;
public void f(java.sql.Statement s, String text)throws Exception
{

String value= new String(aes.doFinal(text.getBytes())); 
s.executeQuery(value);
}
}

As we can see, this method is involved in a potential SQL Injection, but a blackbox is needed for doFinal. In this case, you will find the following information in the SecurityAnalyzer.log.secondary:

19 oct. 2016 15:15:49 com.castsoftware.castil.resolution.controllers.errorhandler.ErrorHandlerController check
INFO: No Implementation found for method "java.cypto.Cipher.doFinal(byte[])" at mypackage.myClass.f(java.sql.Statement,java.lang.String) (Example.java:7:18)

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 applications' source code.
  • Write an XML file with the extension .blackbox.xml and contains 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 appropriate location depending on the target technology:
    • .NET - <CAST-installation-directory>\configuration\BlackBoxes\DotNet\
    • J2EE - <CAST-installation-directory>\configuration\BlackBoxes\J2EE\
  • Ensure the User Input Security tab is configured correctly, 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).

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 : The log file is indicated by the super-linker of the task dataflow in the CAST Management Studio
    • 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:

<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> 

The fact 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.

Implements example:

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

The behavior is the same as extends. The fact 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.

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".

  • No labels