Enhancing Application Security Using Application Transformation
In theory, an organization is able to see exactly code will do if they develop their own proprietary code libraries. However, this is a fallacy, since often simply being able to read the source code for a program does not imply you understand what it is capable of doing. The perfect example of this is the buffer overflow/overrun exploit that has plagued many applications for many years. Yet still to this day code is still being written that is vulnerable to this well-known and understood exploit.
When an organization recognizes that its program is vulnerable there are two options. They can either ignore the problem and hope it doesn’t cost them too much or they fix it. However, most organizations do not have the luxury of being able to avoid common security exploits. Therefore, the organization is left with one of two options in how they address the problem. They can search through the code for the problem and hope that the problem doesn’t exist elsewhere. Otherwise, they can recognize that if the problem exists in one place then it likely exists in other places. As those in the pest control industry are oft to remark about their own breed of bugs, “Where there is one, there are bound to more”.
But how can an organization effectively track down every occurrence of a certain type of bug/exploit? Enter application transformation. Application transformation, specifically source transformation, allows developers to identify patterns in code and fix all occurrences of those patterns instead of simply one occurrence.
Using the programming language C++, we can contrive a simple example of using find/replace. Suppose the problem is a result of using a particular class within a particular library. Further, suppose that the company has decided not to use that class and instead has found a class from a different organization that addresses the problem. So the issue becomes one of removing references to the original class and inserting references to the new class they will use.
The expectation might be that this can be achieved using a simple find/replace mechanism. For example in the following C++ code:
class MySecurityClass{
StringPtr m_stringPtr;
public:
MySecurityClass (){}
MySecurityClass (char *
charPtr_){
m_stringPtr = StringPtr (new
String (charPtr_));
}
void foo (int someInt, StringPtr stringPtr){
}
};
It is conceivable that the organization decides that they no longer want to make use of the StringPtr class because it happens that it is vulnerable to the buffer overflow/overrun exploit. So they will switch to using a different String class implementation (TCStringPtr) by making use of a simple find/replace:
class MySecurityClass{
TCStringPtr m_stringPtr;
public:
MySecurityClass (){}
MySecurityClass (char *
charPtr_){
m_stringPtr = TCStringPtr (new
String (charPtr_));
}
};
The above can easily be achieved using a simple find/replace, however most “real” code will be doing something more complicated than invoking a single constructor and in many cases the interfaces between classes will NOT be identical. The code that uses those classes may have to be changed as well – for example:
class MySecurityClass{
SomeClass m_someObj;
public:
void foo (int someInt_){
m_someObj.foo(someInt_);
m_someObj.anotherFoo();
}
void aDifferentFoo (int someInt_){
m_someObjWithDifferentName.foo(someInt_);
m_someObjWithDifferentName.anotherFoo();
}
};
Now let’s assume that the organization using the above code wants to make use of a different class that has a different interface than the class they were using before. Now they need to ensure that instead of instantiating an object of type SomeClass, they instantiate an object of type SomeOtherClass. However, as it turns out the interface of SomeOtherClass isn’t the same as the interface of SomeClass. In fact, SomeOtherClass can use one method/function named “betterFunction” everywhere that SomeClass was previously using both “foo” and “anotherFoo”. So the above code should become:
class MySecurityClass{
SomeOtherClass m_someObj;
SomeOtherClass m_someObjWithDifferentName;
public:
void foo (int someInt_){
m_someObj.betterFunction(someInt_);
}
void aDifferentFoo (int someInt_){
m_someObjWithDifferentName.betterFunction(someInt_);
}
};
However, this simply cannot be achieved properly using a simple find/replace. The main problem is that simple find/replace mechanisms lack code comprehension. Therefore, there is no way to tell the find/replace mechanism to find each instance of a SomeClass object and its use of:
1. The “foo” method/function that takes an int as an argument
2. Followed by an invocation of “anotherFoo” method/argument
And then replace it with the single invocation of SomeOtherClass’s “betterFunction” method/function.
The only way to teach a computer a language is to give that computer a grammar. A grammar, as it applies to a language like English, is something that can be used to understand how words can be combined to form sentences. The concept is the same for grammars of languages like C++ and Java. It describes how the various parts of a computer language can be combined to form valid computer programs.
By making use of a grammar the computer is able to “understand” the semantics of almost any language. Most source transformation tools make use of a grammar so that they can go beyond the power of simple find/replace mechanisms.
A popular source transformation tool that can be obtained free of charge is a program called TXL (James R. Cordy, Thomas R. Dean, Andrew J. Malton, and Kevin A.
Schneider, 2002). Without getting into the technical details of how TXL works, TXL allows a developer to specify their grammar and then a set of rules for how they would like to transform an existing program.
By leveraging the transformational capabilities of TXL, a developer is able to “write code that will itself write code” (Cassidy, 2004). However, the power of TXL goes far beyond the ability to simply determine the type of an object and change its method invocations according to a change in the requirements for an application.
TXL has been used for a wide variety of applications, such as Programming Language Processing, Program Analysis and Instrumentation, Software Engineering, Database and Document Processing.
In addition, TXL has already been successfully used to reduce the occurrence of buffer overflows/overruns in C programs (Dahn, C. and Mancoridis, S., 2003).
Application security is often approached in a point solution manner instead of in a holistic manner. This results in an iterative process of finding and solving each instance of a particular problem/exploit rather than identifying the common pattern and addressing all instances. By making use of transformational software like TXL an organization can effectively reduce the amount of time required to find and fix security problems.
Cassidy, Tim, Concurrency Analysis of Java RMI Using Source Transformation and Verisoft, Queen’s University, 2004.
Dahn, C. and Mancoridis, S., Using Program Transformation to Secure C Programs Against Buffer Overflows, 10th Working Conference on Reverse Engineering, November, 323, 2003.
James R. Cordy, Thomas R. Dean, Andrew J. Malton, and Kevin A.
Schneider. Source Transformation in Software Engineering Using the TXL
Transformation System. Journal of Information and Software Technology,
44(13):827-837, October 2002.