Вы находитесь на странице: 1из 17

Back door into Java EE application servers

Seventy percent of attacks originate within the company. The Kerviel affair is an obvious example. Java EE projects are very common in the business world and are generally developed by outside consultants or service providers. That represents a significant group of people with the potential opportunity to indulge in unscrupulous behaviour. No audits are performed to ensure that a developer with malicious intent or coping with pressure has not left an invisible back door in the code. We are going to put ourselves in the place of a Java developer to look at the various techniques for adding a back door to a Java EE application that remains invisible to other project developers.

1 Introduction
Thirty to forty percent of those who work in a given company are not employees. This may explain why the majority of cyberattacks come from within. A malicious developer or one pushed into wrongdoing by outside psychological pressure (of the type well known to Mafia organizations) may insert code that can be used to open doors to the application server. What techniques can a Java developer use to hide his or her code? To run a process unbeknownst to the application? To gain entry into the workflow and thereby capture all HTTP queries? We will offer answers to all these questions. Two demonstration videos are being shown. The first is a simple demonstration of how powerful a back door can be, while the second explains how to protect yourself against this type of threat. These videos, along with a number of tools, are available here: http://macaron.googlecode.com

2 The goal of the hacker


From a hacker's perspective, a back door should:

withstand an audit of the application's code. Otherwise, any developer who takes part in the project could discover it by chance; survive any future upgrades to the code. The back door should not be directly dependent on the existing code. Subsequent modifications to the application should not cause the back door to fail; bypass the network firewall and the WAF (Web Application Firewall). Communication with the back door must be invisible or difficult to differentiate from a legitimate workflow; bypass tools for analysing vulnerability in the bytecode, using tainted propagation on the variables.

Given these requirements, we sought out various techniques for meeting all the objectives we had set. In order to withstand an audit, the back door code should not be present in the sources. The application should not invoke it directly. In that way the door is generally excluded from audits. For that purpose, we simply need the presence of an archive that is mistakenly viewed as healthy in order to trigger the attack. To ensure that it is not affected by upgrades to the application code, the back door code should use generic attacks that operate regardless of the application. To bypass firewalls, the code should simulate navigation by a user. It needs to comply with all the requirements imposed on URLs, the fields found in queries, the format of each field, etc. It cannot add new URLs or new fields. In order to bypass tools that are used to analyse bytecodei for the purpose of identifying tainted variables whenever risky processes are invoked, code must be written specifically to block tainted propagation on variables. The following method blocks tainted propagation simply by changing the data type: private static String sanitize(String s) { char[] buf=new char[s.length()]; System.arraycopy(s.toCharArray(), 0, buf, 0, s.length()); return new String(buf); }

3 Implementation
The back door code must follow several steps in order to establish a permanent foothold in the application server and remain capable of bypassing workflows. These steps are described below in chronological order:

Back door in the application Injection into the process flow for HTTP queries Detection of the opening Discreet communication

3.1 Back doors


The first step consists of activating the back door. It must be able to launch while the application code is unaware of its presence. For this purpose, a back door must be used in order to execute the code by the simple presence of a Java archive (JAR) file. Back doors are hidden processes that are shielded from the application. The application code or application server does not need to invoke the code explicitly in order for the malicious processes to run. Various techniques were discovered in the course of the research. Several strategies are available for implementing them:

The addition of a configuration file; The use of "services"; The use of aspect-oriented programming (AOP); The use of a Resource Bundle; The use of annotations.

3.1.1 Configuration-based back doors


Numerous frameworks use configuration files that indicate class names. Some search for parameter files at various locations within the archives. Code can be executed by placing a parameter file at a priority location.
3.1.1.1 The "Axis" configuration back doors

The primary example is the Axis framework from the Apache Software Foundation, which is used to invoke and publish webservices. It looks for configuration files in the following order (see the class EngineConfigurationFactoryServlet): The file <warpath>/WEB-INF/<param.wsdd> The resource /WEB-INF/<param.wsdd> The resource /<param.wsdd> The file's presence in /WEB-INF, in any archive, is sufficient to execute the code when the first webservice is invoked. Since these files are rarely modified in the course of projects, there is little chance of a conflict with another project function.

3.1.1.2 The service configuration back doors

The JAR file specificationsii suggest that the META-INF/services directory be used to report the presence of components to be integrated. A UTF-8 file, generally bearing the name of an interface, includes a line of text with the proposed class for implementation purposes. Up until JDK5, this technique was not used by APIs in the JDK. Each project that wanted to use this convention had to write specific code. JDK6 offers a new API. Generally speaking, the program requires the resource(s) corresponding to a key. The file is read and an instance of the class indicated is then built. For example, the commons-logging framework from Apache uses this convention to initialize the LogFactory. The discovery algorithm includes several steps:

A search is made for the environment variable org.apache.commons.logging.LogFactory

If none, a search is made for a resource named META-INF/services/org.apache.commons.logging.LogFactory

If none, the commons-logging.properties is read to find the key org.apache.commons.logging.LogFactory

If none, a default value is used: org.apache.commons.logging.impl.LogFactoryImpl

The second step is the most attractive for the hacker. By distributing an archive with this file, it is possible to execute code. The code should continue the process with steps 2-4 to ensure that its presence is invisible. Other standard frameworks use the same approach, including:

META-INF/services/javax.xml.parsers.SAXParserFactory META-INF/services/javax.xml.parsers.DocumentBuilderFactory META-INF/services/org.apache.axis.EngineConfigurationFactory etc.

As a result, it is easy to publish these files in order to inject behaviour. There are countless entryways of this type: http://www.google.com/codesearch?q=META-INF+providers Positioning several equivalent techniques increases the likelihood that the back door will be executed. To protect against the injection of an XML analyzer, the JVM must be launched with parameters added that prevent dynamic implementation selection. -Djavax.xml.parsers.SAXParserFactory=\ com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl -Djavax.xml.parsers.DocumentBuilderFactory=\ com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl etc.

We have officially identified this vulnerability and proposed a solutioniii.


3.1.1.3 The Aspect configuration back doors

The third back door technique consists of using innovative aspect-oriented programming (AOP) technology. With this technique, code is woven into the project code's syntax criteria. AOP frameworks look for the presence of a /META-INF/aop.xml file in each archive. This file is used to run a Java code automatically. The code can be executed if just one archive contains the file.

3.1.2 Back doors using a ResourceBundle


Java uses ResourceBundles to manage messages in several languages. The algorithm looks for a .properties file based on various language criteria and then offers a set of keys/values. ResourceBundle.getBundle("Messages").get("hello") The algorithm looks for a file by adding a suffix comprised of the language and its country extension. For example, for France the suffix is _FR_fr, and for Belgium the suffix is _FR_be. If it does not find a file, the algorithm deletes suffix components one by one until it locates a file for the language. If no file is found, it searches for a version with no suffix.
Figure 1. Reading the properties

Messages_fr_FR.properties Messages_fr.properties Messages.properties

Although this is not widely known, the algorithm is actually more complex. It also searches for classes with the same name before looking for .properties files.

Figure 2. Reading properties with classes

Messages_fr_FR.class Messages_fr_FR.properties Messages_fr.class Messages_fr.properties Messages.class Messages.properties

As a result, code can be executed by simply adding a class when loading a resource. Numerous frameworks use ResourceBundles. A Google codesearch query reveals the extent of the possibilities: http://www.google.com/codesearch?q=ResourceBundle.getBundle+lang%3Ajava Merely by adding a class of the same name as a resource file, the back door can be activated without the application's knowledge. During a harmless process, such as loading a key/value file, the back door is created in the system. When the back door is carefully chosen, the likelihood is strong that the initialization code for a back door will be executed. Every project now uses Open Source or open components. If a ResourceBundle is used in privileged code, the simulation class may then obtain permissions. We have officially identified this vulnerability and proposed a solutioniv.

3.1.3 The annotation-based back doors


An increasing number of frameworks use annotations to identify classes and instances to be initialized. That is one aim of annotation: to reduce the amount of configuration. By capitalizing on the annotations used by the various frameworks, it is possible to add a class that will be invoked automatically. For example, the Spring framework builds instances of classes that are annotated as @Component or @Repository. The restriction is that a class must be declared in a directory that is used by the application when it is launched.

<context:component-scan base-package="org.monprojet"/> The disadvantage of this back door is that you must know the name of the branch of the project that will be searched for the various components. Unless you modify the file or capture the analysis by the XML parser, it is impossible to develop a generic back door that uses this function. By contrast, a project developer will have no difficulty coming up with an appropriate attack code. With the Servlet 3.0 specifications, each class containing the character string "Ljavax/servlet/annotation/WebServlet;" will be instantiated by the application server. This is the technique used to identify classes with a @WebServlet annotation.

3.2

Injection-based techniques

The back door code has to be injected in the application workflow. The ideal solution is to be able to analyse each HTTP query in order to locate a specific key that opens the door. There are various techniques for injecting code in an HTTP query management process. The diagram below shows the standard workflow for a Web-based Java EE component, and identifies the various possible insertion points.
Figure 3. Insertion points

Filtre web.xml Valve AOP

AutoProxy

Apache

Valve

Filtre JavaEE

Servlet

Framework

MVC

Several strategies can be used for this purpose. Each is effective to a greater or lesser degree depending on the circumstances of its use: Modify the web.xml file in the Tomcat cache; Dynamically add a Tomcat valve;

Inject code with the AOP; Inject code in the frameworks; Inject a Servlet 3.0; Inject code during the compilation process.

3.2.1 Injection by adding a filter


The Tomcat server decompresses the archived components (WAR, EAR) in a work directory. This directory is refreshed if the application component has a more recent date. In order to be activated, the back door must find the web.xml file in the Tomcat cache, inject a Java EE filter and wait for a restart of the application server. Note that with the new Servlet 3.0 specifications, filters or servlets can be added dynamically.
ServletContext.addFilter(...)

In addition, web fragments provide an even easier method for adding filters or servlets by declaring a META-INF/web-fragment.xml file. <web-fragment> <filter> etc. </filter> </web-fragment>

3.2.2 Injection by adding a valve


Tomcat also offers valves. These are specific filters that can be added dynamically via a JMX request. JMX is a technology for looking up and manipulating server parameters. To add a valve, you need to build an instance that inherits ValveBase before installing it on the server via a JMX request.

3.2.3 Injection via XML


We saw earlier how it is possible to bypass the invocation of the SAX or DOM parser. In this way, an XML file in the application can be enhanced or modified as it is being processed by the parser. Since numerous frameworks use this format, it is possible to inject new parameters on the fly, prior to analysis by the framework. The same approach can be used during analysis of a DOM when configuring logs, for example. The initialization can be bypassed in order to suppress alarms with complete discretion.

3.2.4 Injection by generating an Autoproxy


Java offers a special API that can be used to generate a class dynamically in accordance with a specific interface. An instance of this class captures all invocations and can then modify the processing. The CGLIB library offers a similar function, dynamically generating a class inherited from another class for which all public methods can be redefined. This second approach can be used to provide the same service without the need for an interface.

These forms of technology are used to generate autoproxies designed to add security rules, transaction management, load balancing, RMI- or CORBA-based remote communication, etc.
Injecting singletons

The Java 2 permission suppressAccessChecks can be used to modify private attributes. If it is available, singletons can be easily altered. Imagine an interface-based singleton. The singleton is accessible using the static method TheSingleton.getSingleton(). It is also available via the private attribute TheSingleton._singleton. It is easy to generate an autoproxy to replace the singleton, modify the private attribute directly and capture every invocation of the singleton's methods. Two techniques exist for protecting yourself from these attacks: declaring the _singleton attribute as final or using Java 2 security. You must have the suppressAccessChecks permission in order to be able to modify a private attribute. This highlights the fact that using the singleton poses a risk for projects. The Google Singleton Detector utility can identify risksv in projects.
Injecting Spring components

The Spring framework initiates application singletons using the inversion of control concept. The initialization of Spring components involves the creation of a group of interrelated singletons. The Spring framework offers various sub-frameworks, including an MVC (Model-View-Controller) layer that can be used to manage Web requests. One of three injection approaches consists of declaring a <bean/> that implements the BeanPostProcessor interface. It then becomes possible to act on beans that implement the HandlerMapping interface in order to modify the behaviour of the getHandler(HttpServletRequest request) method. If we want a generic attack that does not rely on a project-specific package name, the analysis of the XML file must be modified on the fly so that the declaration of a new <bean/> can be injected dynamically. At the time of writing, this attack did not require any particular permission in order to be effective. It cannot be blocked. We offer a solution and a patch to JDK6 for correcting this problem.

3.2.5 Injection using an aspect declaration


Aspect-oriented programming provides a natural means of injecting code into the application. We have shown how this technique allows a back door in the application to execute code unbeknownst to the project. It can also be used to inject processing during HTTP queries. Any workflows leading to JSP files or queries can be diverted. As a result, all of the application server servlets and JSPs will fall under the control of the back door. No technology exists for blocking this attack.

3.2.6 Servlet 3.0 injection


The most recent servlet specifications naturally allow for filter injection. The classloader for a Web application looks at every class in order to find any potential annotations. When a @WebFilter annotation is present, it is added automatically as if it were present in the web.xml file. To prevent this automatic discovery of filters, the parameter metadata-complete must be added to the web.xml file.

3.2.7 Injections during the compilation process


JSR269 lets you add processors when compiling a Java code. Beginning with Version 6 of JVM, when an annotation is present, a Java code assumes control during compilation in order to generate other classes or resource files. In order for this to work, there must be an archive in CLASSPATH when the compilation is performed. This archive must include the service javax.annotation.processing.Processor. In this way it is possible to modify the final code for the application, even with an archive that is only present for unit tests. A class can be added or modified. Consequently, steps can be taken with a compiled class to modify its behaviour, either by injecting code directly into the class during compilation or by simply replacing the .class file. During a Maven or Ant compilation, for example, the processor is invoked in order to compile the project classes and unit test classes. The processor can then take steps to alter the target directory before the project archive is created. This attack can be used with any Java application, and offers a means of injecting a back door into a chip card. To prevent this, the parameter -proc:none must be added during the compilation process.

3.3

Detecting the opening of the door

When the back door code is executed with each HTTP query by means of a Tomcat valve, Java EE filter, AOP injection, autoproxy or Spring interceptor, it is possible to parse every field found in the forms. When a key is present in any field on a form, the back door blocks the process. We offer a demonstration code for these attacks. It involves placing a simple archive in the WEBINF/lib directory. Then the word Macaron in leetspeakvi ("M4c4r0n") is used in any field of the application in order to run it.

3.4

Discreet communication

Once the flow is blocked, discretion is needed in order to communicate with the back door. It must not be possible for network firewalls or application firewalls (WAFs) to detect the code. WAFs detect:

URLs used, via a whitelist; The list of fields for each URL and the format restrictions (digits/letters, length, etc.); The speed of queries (more than 120 queries per minute or more than 360 queries in five minutes); The maximum size of the response (512 KB); The presence of specific keywords in the pages of responses (blacklist). The back door needs to get around all of these verifications. Consequently, the filter uses a standard URL for the application, the one used to insert the key. The opening request complies with the restrictions if the field that is selected for using the key accepts characters and digits.

Communication is conducted by filling in a form with a special value that complies with the field restrictions (in terms of character type and field length). The back door's agents then use that URL alone, always submitting the same form with the same values except for a single field used for transport purposes. This latter field must not violate the field restrictions. The diagram in Figure 4 shows how communication is routed.
Figure 4. Communication with the back door

1
3
Tomcat Application

2 4

Macaron

When a form is submitted, the processing is diverted to the back door. A specific page is sent. This page communicates with the back door code using AJAX requests in order to inject the results of the processing into the page in XML format. Monitoring of network frames during communication with the back door reveals that one form is submitted on a regular basis in which only one field changes. If the request is a POST request, it is unlikely to be recorded in the logs. The AJAX transmission flow is slowed in terms of network traffic so as not to raise suspicion.

3.5

Agents
An agent that stores the most recent requests on the server; A JMX agent for manipulating the application server; A JNDI agent for consulting the configuration directory; An SQL agent for manipulating the database;

The back door offers various agents:

A Java/javascript agent for dynamically compiling and running code on the server; and a Shell agent for fun (Figure 5).
Figure 5. Shell

Demonstration

A demonstration code is available that illustrates this study. It involves a Java archive to be placed in the WEB-INF/lib directory of a Web component. Various techniques are used to reveal effective vulnerabilities in the execution environment. The demonstrations are all founded on the same approach: downloading a WAR component onto the network, adding the back door archive to the WEB-INF/lib directory and installing the component on the application server. Here are some examples you can use: http://tomcat.apache.org/tomcat-5.5-doc/appdev/sample/sample.war http://homepage.ntlworld.com/richard_c_atkinson/jfreechart/jfreechart-sample.war http://www.springsource.org/download After downloading, use a ZIP archive program or a console.

$ wget http://tomcat.apache.org/tomcat-5.5-\ doc/appdev/sample/sample.war $ mkdir -p WEB-INF/lib $ mv macaron-backdoor*.jar WEB-INF/lib $ jar -uf sample.war WEB-INF $ cp sample.war $CATALINA_HOME/webapps To prevent any mishaps with the code, it does not run unless certain conditions are met. The macaron-backdoor environment variable must be declared before the application server is launched.

export JAVA_OPTS="$JAVA_OPTS -Dmacaron-backdoor=i-takeresponsibility-for-my-actions" Then launch Tomcat. $ $CATALINA_HOME/bin/catalina.sh run Wait thirty seconds until the back door is in place; then, using a browser, view the site. In a form field, enter the password "M4c4r0n" or add a ?param=M4c4r0n page to the URL.

Propagation

As projects become increasingly dependent on components that are themselves dependent on other components, it is often difficult to add all the archives with the proper versions to ensure that the project runs. The Apache Software Foundation's Maven projectvii offers a way of managing this, by allowing each component to compile its dependency list. An algorithm can then scan the dependency graph to select the archives that are required for a project. A global repository includes every version of the Open Source components. In order to place archives in the global repository, users must demonstrate that they are the manager of a domain name, by publishing their own name on a principal page of the site, and then inform the Maven administrator of where to find the archives to be published. Only components of that domain name can be published. The number of contributors is important. The archives that are retrieved are not electronically signed. By hacking the account of a single contributor, it is possible to add a dependency to one of the components. This can be done in a version manager such as CVS Manager or SVN Manager, or directly in the source from which the Maven administrator retrieves the component. The new dependency will make it possible to add the back door archive in each project that uses the infected component. As we have shown, the mere presence of an archive makes the installation of a back door possible. Each external component used by a project must be given very close attention. Recently, repositories have fallen victim to hackers. All Red Hat and Debian clients have been affected, and a similar problem has now occurred with Mavenviii. This is indicative of the genuine threat that is posed. To reduce risk, the components present in the Maven repository should all be digitally signed by their authors, as should the dependency description files. When that is the case, a hacker will not only have to hack into an account, but will also have to steal and break the author's private key in order to alter the component. Efforts are currently underway in this areaix. The Ivy technologyx relies on the Maven or other repositories. Since it does not verify signatures, it is vulnerable as well.

Conclusion

We have shown that, by using various back door techniques, injecting code or exploiting permissions, an invisible back door can be added to a Java EE project. We have identified the

strategies of attack. We offer three utilities that can be used to audit and strengthen the code and extract the few permissions to be granted. http://macaron.googlecode.com Ideally, we need to advance the Java culture so that projects use a seal on all their packages and work routinely with Java 2 security during the development phase. This is also the approach taken by Google for its Google App Engine hosting service. Archive signatures and human audits offer additional means of protecting repositories. Java offers signature solutions, but they are not widely used. Greater use should be made of these solutions for enhanced security. You will find a more detailed description of these attacks in the report presented at the SSTIC conference on information security. Philippe Prados Consultant Architect, Atos Origin macaron@philippe.prados.name

i http://suif.stanford.edu/~livshits/papers/pdf/thesis.pdf ii http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html iii CVE-2009-0911 iv CVE-2009-0911 v http://code.google.com/p/google-singleton-detector/ vi http://fr.wikipedia.org/wiki/Leet_speak vii http://maven.apache.org/ viii http://www.nabble.com/Unintended-usage-of-core-plugin-stubs-td19633933.html ix http://docs.codehaus.org/display/MAVEN/Repository+Security x http://ant.apache.org/ivy/

Вам также может понравиться