Monthly Archives: March 2014

OWASP Top 10 is overrated

OWASP Top 10 doesn’t need an introduction: it’s certainly the most well-known project of the Open Web Application Security Project (OWASP), referenced by every single presentation, paper, brochure and blog post that is at least slightly related to web application security. 

But unfortunately, according to my experiences, most of the time, OWASP Top 10 is the only thing people can think of, when it comes to (web)app security, even though OWASP and other groups provide materials of much higher professional value. This affects not only for novice programmers, but also people in corporate IT-security teams, and even quite a few security vendors and consultant firms.

In the next sections, I will try to shed light on the misunderstandings around the Top 10, the weaknesses of the project, and reasons why I think it doesn’t fit many purposes it is (ab)used for right now.

Good Definitions

To see what the Top 10 is good for, we can simply take a look at how the Top 10 project defines its goals:

"The goal of the Top 10 project is to raise awareness about application security by identifying some of the most critical risks facing organizations."

This is a very accurate description that deserves some more attention. 

Raising awareness is a really important task that needs to be taken care of. However, raising awareness in itself was never meant to help prevent, identify or solve any problem. The HIV problem is not taken care of by simply telling people that they should only have sex in a safe way (whatever that means…). 

Moving forward we read that the Top 10 helps “identifying some of the most critical risks”. Not all the risks. Not all the critical risks.

All in all, with the Top 10, we may have sneak peak into the problems of the web application security, however, we will definitely not see the big picture. The Top 10 can’t be used as a silver bullet, when it comes to web application security, this is what the creators themselves tell you. Unfortunately, as it turns out, people prefer short, simple lists as the solution for their overly complex problems.

Risk Rating

We are most afraid of “critical” vulnerabilities, and the Top 10 project provides a seemingly good way to put up the fight with them. But what vulnerabilities are critical anyway?

“Top 10-only” people are usually unaware of the fact that OWASP also maintains its own Risk Rating Methodology. This methodology helps us assessing the risk of vulnerabilities by measuring different factors of a potential attack, like its impact on our business or the motivation of the attacker. What we have to keep in mind is that these factors are strongly dependent on the wider context of the application.

The Top 10 is created by measuring the usual impact of some common vulnerability classes. But web applications are difficult (both from security and development standpoints) because they are mostly developed “from scratch” (hopefully at least based on some kind of framework…) to meet the custom specifications of the customer. Business processes of big companies are run through series of independent webapps developed by different companies on different platforms at different times.  Apart from the vulnerabilities arising from the interaction of these components (which are obviously not covered in the Top 10) assessing the severity of even the simple-looking issues can be far from obvious, if you take the application context into account.

How severe is an SQL injection issue in an application with similar functionality to that of phpMyAdmin? Have you ever tried exploiting an SQL injection issue with a 10 char input limit? How often would you associate critical impact to an open redirect issue (No. 10 in Top 10 2013)? Are insecure file uploads (which usually result in RCE) even covered by the Top 10?

For the uninitiated reader, the Top 10 could suggest that the severity of security vulnerabilities can be measured merely by some of their technical properties; this contradicts the basic considerations of any serious security concept. The truth is that the Top 10 is about the web applications in general, and not about your web application.

Bad Definitions

 You could assume after the honest and clear self-definition of the project that it will at least provide you with a useful classification for the vulnerabilities you can encounter. But it is not. Some examples:

If we create a big set of injection problems (A1) and say that “injection occur when untrusted data is sent to an interpreter as part of a command or query” why don’t we drop XSS (A3) in the bag also? I can think of the browser as an interpreter and HTML tags or embedded scripts as its commands. 

Isn’t the presence of insecure direct object references (A4) imply the  lack of function level access control (A7)?

Can’t we just think about every single security issue as Security Misconfiguration (A5)?

I suspect that in order to raise awareness about some undoubtedly important issues, the Top 10 team tried to include too many things in this short 10 element list. As a result, the classification became unclear and instead of shedding light on fundamental issues, it left its readers alone to fight the complexity of application security.

A developer friend of mine asked me the other day, if I could point him to some useful resources about web application security. First, I wanted to give him a list including the OWASP Top 10, but then I decided not to, because I didn’t want to proivde him a confusing material at the very first step on his way in security.

Some common misunderstandings

Finally I would like to answer some common questions regarding the above thoughts and the Top 10 in general:

– “You are bashing OWASP”

– I’m not bashing OWASP. I’m only bashing the Top 10 project and those who are lazy enough to see it as a comprehensive solution for their appsec problems. I’m actually an admirer of OWASP, and use their fine materials every single day. I also do respect the work of the Top 10 project members, and I’m open for discussions about how we could make things better.

– “At least the Top 10 gives us a QA baseline to hold on to”

– The Top 10 is never meant to be a baseline for anything (there is even a separate OWASP project for that). A baseline should be something that you can enforce/verify, but the Top 10 doesn’t give you anything to do such things (other OWASP projects can help you, though). You should also consider if such baseline could ever be created, taking the high diversity of web applications into account. 

– “The Top 10 gives you all the references to really useful materials”

This is true, and this is what I find most valuable in the project. But people are lazy and tend to ignore those materials. Why would someone waste the time on learning robust development methodologies and frameworks, when he can solve all his problems by “using bind variables in all prepared statements and stored procedures, avoiding dynamic queries”? And although the Top 10 encourages its readers to “Don’t stop at 10”, they actually do, because  it is always easier to check the items of a list than to think through the problem we are facing. 

OWASP Top 10 can be a good starting point for less tech-savvy people (like journalists), but it shouldn’t be thought of as a piece of professional material. I hope an audience that has already got familiar with the Top 10 will also find the more valuable materials of OWASP which could effectively help creating and maintaining more secure systems.

Update: Here are some links to other OWASP projects which can give you more useful guidance to deal with web application security:

SNMP trap?

During one of our internal network penetration testings, I focused on the network devices. The customer had 3Com/HP switches. Little portscan with NSE revealed that the switches used default SNMP community strings (public and private)! I checked SNMP problems affecting 3Com/HP switches; there was a really interesting issue:

3Com, HP, and H3C Switches SNMP Configuration Lets Remote Users Take Administrative Actions

I tried to check all the OIDs from h3c-user.mib and hh3c-user.mib files with no success.
Having tried everything else, the solution was good old brute force (snmpwalk and a shell script):

b2

The screenshot shows the three default accounts on the device: admin, manager, monitor and their plain text passwords.

With these, I could log into the device:
b1

The SNMP MIB brute force revealed some other interesting information, including configuration files that you could download using the TFTP ;)
What have we learnt today? If a method of attack does not work at first, do not reject it immediately!

Happy hacking!

Sanitizing input with regex considered harmful

Sanitizing input (as in trying to remove a subset of user input so that the remaining parts become “safe”) is hard to get right in itself. However, many developers doom their protection in the first place by choosing the wrong tool to get it done, in this case, regular expressions (regex for short). While they’re powerful for quite a few purposes, as the old saying goes,

Some people, when confronted with a problem, think “I know, I’ll use regular expressions.” Now they have two problems.

During a recent pentest, we found an application that did this by stripping HTML tags from a string by replacing the regular expression <.*?> with an empty string. (Apparently, they haven’t read the best reaction to processing HTML with regexes.) For those wondering about the question mark after the star, it disables the default greedy behavior of the engine, so the expression matches a less-than sign, as few characters as possible of any kind, and a greater-than sign. At first sight, one might think that’s the definition of an HTML tag, and for a minute we also believed it was the case.

In regexes, the dot matches any character. However, the definition of any excludes newlines (ASCII 0x0a, \n) by default in most implementations, while the HTML standard allows for such characters inside tags, which gives us a specific class of tags that are valid in browsers but are not stripped by the above algorithm. Below are some examples of platforms used to implement web applications and their behavior regarding this “challenge”. Some libraries have similar solutions, but only one thing was common in these five languages; by default, the above expression fails the test. For the sake of brevity and readability, examples were produced in interactive shells (REPLs); in case of Java and .NET, Jython and IronPython were used, respectively.

Java

>>> from java.util.regex import Pattern
>>> p = Pattern.compile('<.*?>')
>>> p.matcher('<foobar>').replaceAll('')
u''
>>> p.matcher('<foo\nbar>').replaceAll('')
u'<foo\nbar>'

The official documentation states that dot matches “any character (may or may not match line terminators)”. The link points to a section that says “The regular expression . matches any character except a line terminator unless the DOTALL flag is specified.” [emphasis added] Adding the flag solves the problem, as it can be seen below.

>>> p = Pattern.compile('<.*?>', Pattern.DOTALL)
>>> p.matcher('<foobar>').replaceAll('')
u''
>>> p.matcher('<foo\nbar>').replaceAll('')
u''

Python

>>> import re
>>> re.sub('<.*?>', '', '<foobar>')
''
>>> re.sub('<.*?>', '', '<foo\nbar>')
'<foo\nbar>'

Python follows a similar path, even the flag is called the same: “In the default mode, this matches any character except a newline. If the DOTALL flag has been specified, this matches any character including a newline” [emphasis added].

>>> re.sub('<.*?>', '', '<foobar>', flags=re.DOTALL)
''
>>> re.sub('<.*?>', '', '<foo\nbar>', flags=re.DOTALL)
''

PHP

php > var_dump(preg_replace("/<.*?>/", "", "<foobar>"));
string(0) ""
php > var_dump(preg_replace("/<.*?>/", "", "<foo\nbar>"));
string(9) "<foo
bar>"

Although PHP has an interactive mode (php -a), return values are silently discarded, and var_dump doesn’t escape newlines. However, it clearly illustrates that it behaves just like the others, but PHP doesn’t mention this behavior in the official manual for preg_replace (even though a user comment points it out, it lacks the solution). The PCRE modifiers page has the answer, the s modifier should be used, and it even shows the longer name for it (PCRE_DOTALL), although there’s no way to use it, in contrast with Python’s solution (re.S is equivalent to re.DOTALL).

php > var_dump(preg_replace("/<.*?>/s", "", "<foobar>"));
string(0) ""
php > var_dump(preg_replace("/<.*?>/s", "", "<foo\nbar>"));
string(0) ""

.NET

>>> from System.Text.RegularExpressions import Regex
>>> Regex.Replace('<foobar>', '<.*?>', '')
''
>>> Regex.Replace('<foo\nbar>', '<.*?>', '')
'<foo\nbar>'

Of course, Microsoft surprises noone by having its own solution for the problem. In their documentation on regexes, they also mention that dot “matches any single character except \n”, but you have to figure it out yourself; there’s no link to the Singleline member of RegexOptions.

>>> from System.Text.RegularExpressions import RegexOptions
>>> r = Regex('<.*?>', RegexOptions.Singleline)
>>> r.Replace('<foobar>', '')
''
>>> r.Replace('<foo\nbar>', '')
''

Ruby

irb(main):001:0> "<foobar>".sub!(/<.*?>/, "")
=> ""
irb(main):002:0> "<foo\nbar>".sub!(/<.*?>/, "")
=> nil

Ruby performs as usual, having easy-to-write/hard-to-read shorthands, however, its solution is almost as dumbfounding as the above. Like PHP, it expects modifiers as lowercase characters after the trailing slash (/), but it interprets s as a signal to interpret the regex as SJIS encoding (I never knew it even existed), and wants you to use m (called MULTILINE by the official documentation, adding to the confusion), which is used for other purposes in other regular expression engines.

irb(main):005:0> "<foobar>".sub!(/<.*?>/m, "")
=> ""
irb(main):004:0> "<foo\nbar>".sub!(/<.*?>/m, "")
=> ""

Javascript

> "<foobar>".replace(/<.*?>/, "")
''
> "<foo\nbar>".replace(/<.*?>/, "")
'<foo\nbar>'
> "<foo\nbar>".replace(/<.*?>/m, "")
'<foo\nbar>'

JavaScript has three modifiers (igm), none of them useful for making dot match literally any character. The only solution is to do it explicitly, the best one of these seems to be matching the union of whitespace and non-whitespace characters.

> "<foo\nbar>".replace(/<[\s\S]*?>/, "")
''
> "<foobar>".replace(/<[\s\S]*?>/, "")
''

Conclusion

The above solutions address a single problem only (stripping HTML tags having line breaks), processing untrusted input is much more than this. If you build a web application that must display such content, use a proper library for this purpose, preferably a templating language that performs escaping by default. For other purposes, use a DOM and don’t forget to test for corner cases, including both valid and broken HTML.