During a black-box penetration test we encountered a Java web application which presented us with a login screen. Even though we managed to bypass the authentication mechanism, there was not much we could do. The attack surface was still pretty small, there were only a few things we could tamper with.
1. Identifying the entry point
In the login page I noticed a hidden POST parameter that was being sent for every login request:
<input type="hidden" name="com.ibm.faces.PARAM" value="rO0..." />
The famous Base64 rO0 (ac ed in HEX) confirmed us that we were dealing with a Base64 encoded Java serialized object. The Java object was actually an unencrypted JSF ViewState. Since deserialization vulnerabilities are notorious for their trickiness, I started messing with it.
JSONP injection is a lesser known but quite widespread and dangerous vulnerability and it surfaced in the last years due to the high rate of adoption of JSON, web APIs and the urging need for cross-domain communications.
What is JSONP?
Assuming everybody knows what JSON is, let’s talk a little about JSONP. JSONP comes from JSON with Padding and it was created in order to bypass common restrictions such as Same-origin Policy which is enforced for XMLHttpRequest (AJAX requests).
Let’s take an example. Our online banking application, http://verysecurebank.ro, has implemented an API call that returns the current user’s transactions.
An HTTP request to the http://verysecurebank.ro/getAccountTransactions endpoint presents us with the transactions, JSON formatted:
If our reports application, accessible at http://reports.verysecurebank.ro wants to get the transaction details, an AJAX call to the page won’t be possible, due to Same-origin Policy being in effect (different host).
Note: even if it might be obvious, it’s worth mentioning that when including a script cross-domain, it will run in the context of the including application, not in the source’s context.
Adding a callback to the API response, wrapped around the JSON formatted data, allows us to load the API response between script tags and get its content by defining our own callback function to handle it.