Pages

Showing posts with label security. Show all posts
Showing posts with label security. Show all posts

Tuesday, May 26, 2015

Java XML Processing Vulnerabilities

Last week I was fixing issues for my pet project Scribble. I use Sonar for capturing issues in my code. Since April this year, the Findbugs plugin for Sonar includes rules for finding security bugs. Two of the bugs found were related to XML processing using Java's XML APIs for Xpath and DOM parsing. The security issue themselves were not new, both of them were discovered some years ago. But to me they were new as I was not aware of them at all. For my pet project they are not that critical as it is just a framework for writing tests and no one using that framework is kept from writing vulnerable code themselves. But for me it was a good case for studying the issues to avoid them when it really matters.

 

Xpath Injection

Xpath injection adheres to the same principle as SQL injection were parameter values that are used in an Xpath expression contain characters that are semantically bound to the Xpath syntax to break out from the path defined by the expression.

The Attack

Given, you have an XML document containing sensitive data

<technical-users>
  <user id=”reader”>
  <privateKey>ABC</privateKey>
  </user>
  <user id=”writer”>
  <privateKey>123</privateKey>
  </user> 
</technical-users>
and an Xpath expression with a parameter that is filled in at runtime:
//technical-users/user[@id='”+userId+”']/privateKey
Lets assume, the attacker has authenticated successfully as reader and now tries to query for the private key, manipulating it's own user id to that value:

reader']/../user[@id='writer

The injected value leaves the reader-user subpaths, traverses one level up and down into the writer-users subpath and thereby delivering the privateKey of that user. A variation of this attack is if the authentication data of a webapp is stored in xml, i.e. an XML database. With a forged userId the system can be tricked to authenticate without a proper password

The Defense

The only effective defense is to sanitize the user input! Typically, a regex-pattern could help with allowing only input of a certain pattern, i.e. allowing only alphanumeric characters and within a specific length range (5 to 15 characters):
if(!userId.matches([a-zA-Z0-9]{5,15}) { 
  throw new Exception(“Invalid Input“); 
}
If reserved characters should be allowed, you may escape them:
String escapedUserId = userId.replaceAll(“'“, “\\'“);
Although that may be prone to further injection to circumvent the escaping, so it should be thoroughly tested if self-implemented. Both pattern matching and escaping could be encapsulated in a javax.xml.xpath.XpathVariableResolver that is registered at the Xpath instance. The following example shows a sanitizing variable resolver that accepts a set of regular expressions to check the parameters that should be resolved
public class SanitizingVariableResolver implements XPathVariableResolver {
   //create a map to contain the variable values
  private Map<QName, String> variables = new HashMap<>();
  //keep a list of all valid patterns
  private final List<Pattern> validationPatterns;

  //constructor accepting regular expression patterns
  public SanitizingVariableResolver(String... regexPatterns){
    this.validationPatterns = new ArrayList<>();
    for(String regexPattern : regexPatterns) {
      this.validationPatterns.add(Pattern.compile(regexPattern));
    }
  }
  //method to add variable value on which the sanity check is applied
  public void addVariable(String name, String value) {
    for(Pattern pattern : validationPatterns){
      if(pattern.matcher(value).matches()){
        variables.put(new QName(name), value);
        return;
      }
    }
    //don't accept invalid values
    throw new IllegalArgumentException("The value '" + value + "' is not 
      allowed for a variable" );
  }
  @Override
  public Object resolveVariable(QName variableName) {
    return this.variables.get(variableName);
  }
}
Next, you'll have to apply this resolver to your Xpath instance and use an Xpath expression with a variable placeholder:
//create new xpath instance
final XPath xp = XPathFactory.newInstance().newXPath();

//instantiate the resolver with an alpahnumeric pattern
final SanitizingVariableResolver resolver = 
  new SanitizingVariableResolver("[a-zA-Z0-9]{4,15}");

//add the user id value
resolver.addVariable("userId", userId);

//assign the resolver to the xpath instance
xp.setXPathVariableResolver(resolver);

//apply the xpath expression with variable
xp.evaluate("//technical-users/user[@id=$userId]/privateKey",source);

An alternative to sanitizing the input yourself, you may use alternative libraries such as Xquery that provides an abstraction layer on top of the Xpath API that provides means to sanitize parameter input.

References

 

XML External Entity (XXE)

XML document have to be well-formed and may be validated. For validation, there are two options for declaring a structure against which the document is validated: Doctype Definition (DTD) or XML Schema. A DTD may be embedded in the document itself. For XML the concepts of entities exist to describe characters or values that are parsed and replaced by the XML processor. A common example is the &-entity for describing an ampersand character ('&') because the '&' is a reserved character in Xml. Within a DTD custom entities can be declared. Values for those entities could be characters but also the content external resources indicated by an URI.

The Attack

In an XXE atttack, the attacker sends a perpared XML file containing a malicious entity. The entity points to an external resource containing a secret, i.e. /etc/passwd. Depending on what the service actually does, the attacker may easily read the secret from the parsed document.
A prepared XML document may be

<?xml version="1.0"?>
<!DOCTYPE document [
    <!-- placeholder for the attacked file url -->
    <!ENTITY xxe SYSTEM "/etc/passwd" >
]>
<document>
    <!-- the external entity is replaced with the injected value -->>
    <property>&xxe;</property>
</document>
When being processed by DocumentBuilder, the &xxe; is resolved to the content of /etc/passwd and accessible as text content of the element. The attack is also valid for processing XML with the SAX parser.
 

The Defense

There are several options to fix this vulnerability. Probably the easiest one is to use XML-Schemas only for XML validation and disable the Doctype Declaration feature by setting the DocumentBuilderFactory Feature http://apache.org/xml/features/disallow-doctype-decl to true:
DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
f.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);


This feature however is only supported by Xerces2. If you're on Xerces 1 or you can not disable Doctype declaration, you could disable the features

Xerces 1
http://xerces.apache.org/xerces-j/features.html#external-general-entities
http://xerces.apache.org/xerces-j/features.html#external-parameter-entities
Xerces 2
http://xerces.apache.org/xerces2-j/features.html#external-general-entities
http://xerces.apache.org/xerces2-j/features.html#external-parameter-entities
Sax in general
http://xml.org/sax/features/external-general-entities
http://xml.org/sax/features/external-parameter-entities

and set on the DocumentBuilderFactory the flags
dbf.setXIncludeAware(false);
dbf.setExpandEntityReferences(false);
 
Oracle proposes two alternative approaches. The first is to perform the parse operation in a privileged context with a no-permission ProtectionDomain where the java security policy is effective, preventing access to restricted system files. The second is to use an EntityResolver and allow only entities that match a certain pattern.
Further attacks against DTD, Schema and Entities and how to defend against are discussed in XML "Schema, DTD, and Entity Attacks"(pdf).

References


All examples, including JUnit tests that can be used as template to tests your own code can be found on https://github.com/gmuecke/whoopdicity/tree/master/examples

Thursday, November 26, 2009

"Plane attack prevented by disarming Swiss Cheese Bomber"

It's a ridiculous story that happend to me yesterday. I intended to visit my mother who lives near Hamburg for the 1st advent, I bought a gift for her, as I live now in Switzerland, what is more obvious than bringing some Swiss presents so I bought a complete Swiss Fondue Set, including forks, heater, a big cheese-pot and some dishes and - of course - 1.5kg of Swiss Fondue Cheese (and also some flour for making fresh bread). All our suitcases where full (mine and that of my girlfriend) so we decided to carry the present in our hand luggage. Of course we had to pass security and we where already quite late at the airport. But at the security x-ray scanner we had two findings. One was the flour in my bag pack (scary, huh?) and the other was - you might already guess - the 1.5kg Swiss fondue cheese. Ok, you might think, it was found, considered harmless and that's all about it. But no way! The security officer told me, that this chunk of cheese is considered as liquid (!) and we where not allowed to take it on board. I thought they were kidding, but they weren't, they argued, that it contains wine - which is alcohol - and inflammable. Yes, of course, how could I forget, most of all fire accidents happen due to exploding wine bottles. They said, if I would have some time I could check it in as normal luggae (how normal is it to check in a separate chunk of cheese?). But anyway, we could not take it with us and had to leave it. My girlfriend wished them a nice fondue party and they told us they had to destroy it anyway. The fresh, new, sealed and unused chunk of cheese.
I mean, how stupid is this liquid policy? What's more obvious than carry some cheese when carrying a complete fondue set? Everyone saw it - even the security officers saw it, they looked pretty helpless explaining to us, why a chunk of cheese is a threat. Around 8mio swiss people knew that such a chunk of cheese causes if ever then most likely a bilious attack - but not a plane attack. This has nothing to do with common sense. This has even nothing to do with security or terror prevention. How could liquids in general and a chunk of cheese in special help hijacking a plane? I mean, if it's really a bomb, then the plane just explodes and that's it, you could not fly an exploding plane into a skyscraper, and it's way more easier to get a bomb into a train and blow an entire main station out of this world then getting a chunk of cheese on board of a plane. This is pure stupid, made by people that are not affected. This reminds me of former times, when the soviet central government dictated, what famers had to plant - regardless if farmers complained that the plants are not growing in that region (as I've read in the Occupation museum in Riga).
Stop stupidity and start thinking again!

Well, in the end, we arrived safe and sound in Hamburg thanks to the security authorities who disarmed the dangerous swiss-cheese bomber (me). Happy X-mas!

(and the weird end of the story is the fact, that I could easily take 80g of burning paste which was included in the heater-set onboard without noticing and which is much more inflammable than a chunk of cheese...)

Friday, November 20, 2009

Where is the cloud on a sunny day? or Who controls the weathermaker?

Google announced they Releasing the Chromium OS open source project. They focussed on speed, security and easy handling. The entire concept is, that application do not run on the local machine at all but on the cloud, all the data are on the cloud. So much for the theory. Actually I like the idea of access to all my data everywhere and independent from the device with which I access them, but when it comes to the reality I think we are yet pretty far away from "Everything-in-the-cloud". In my oppinion there are two major obstacles to overcome:
  1. Seamless and Pervasive access to the Internet. Considering the technical and financial side, this is not yet reality for most of the people. The prices are yet still to high for mobile services - especially when it comes to travelling abroad - unlike the US, Europe consists of lots of more or less small countries where you pay roaming fees - which are quite high when it comes to 24h-web-access. As example (from ordinary mobile telephony): I paid 8€ for a-15mins phone call abroad, and I was called! Looking at the technical side, UMTS has become widely available, though there are situation where you simply have no signal - in mountain regions or in the deep cellars of a customer's computing center. There you still rely on plain old network cables. When it comes to seamless, it's still a pain to switch different network providers or media. Switching from UMTS to WLAN to Cable is still a pain, having to reconnect to different services because of a new IP, lost sessions (MS RDP is my favorite...). And how do you access your data or applications when there are blue skies? When you rely on the accessibility of the Internet you could end up lost in the wilderness - and this is not an artifical problem, when I was in the Sequoia National Park this summer, we had no phone or internet access there but had to find a gas station. We were lucky in the end but consider you navigation system runs on Google! But I think, the technology will evolve and this obstacle evaporate over time. But the other obstacle require more than this.
  2. Privacy data protection and data security. When I would put all my data and applications that have been running on my local machine into the cloud I would expand my trust domain from my client device to the cloud (or the internet or provider). And this requires a lot of trust! I have control over my local machine, I can pull the plug and preventing access to it. Of course it is in my responsibility to protect and secure my system, but thats ok. But when it comes to the cloud, I have to trust the cloud provider. And when I look at the recent sensitive data infringements that happen in Spain where probably over 100k credit card data sets have been lost I don't want to think about what would happen if the rest of my data would be stolen from the cloud provider! At the moment we trust on the pure goodwill of a company like Google. Sure, their services are yet for free but what's the worth of my private data I put into their hands? I don't even have a formal contract between them! And even if there would be contract and I would pay for using the cloud - how could I be sure to trust the provider? Providers fail, like power, water or internet providers may fail from time to time, those things happen - but it's not just the lost of internet access, light or fresh water for a moment - it may be the loss of your privacy for a longer period than just a moment! A solution for this would be kind of a certification the cloud providers could get from a governmental agency like those for data privacy protection, something similar to those of a Certification Authority. There have to be regulations for systems that deal with private data such as for banks. Before there isn't such thing I can rely on I won't put my private stuff into the cloud (although I have to admit, that I already use gmail - but to be honest that's already more than I feel comfortable with).