[Server] Did you update OpenSSL?

Two weeks ago, the Debian package of OpenSSL has been found to generate weak keys (CVE). Here's the news from Heise online:

Security expert Luciano Bello has now discovered a critical vulnerability in the OpenSSL package which makes the random number sequences, and therefore keys generated, predictable. The problem only affects Debian and distributions derived from it, such as Ubuntu and Knoppix. […]

OpenSSL provides connection security for many important network services, such as the Apache web server, the SSH login service, the OpenVPN service, the Bind name server, S/MIME e-mail encryption and the trustworthiness of digital signatures. This could enable attackers to listen in on and manipulate SSL connections, obtain unauthorised access to SSH servers or poison DNS server caches.

As it is a serious security vulnerability, it is strongly advised to update your keys, especially for the SSH login service. Although the security advice is two weeks old already, there are still thousands of servers vulnerable. Heise Security found 5% of nearly 2,000 servers tested to use weak keys.

Real world CSRF: Update your Radiant now

Radiant is a no-fluff, open source content management system designed for small teams, written in Ruby on Rails.

I have found several security problems in Radiant, informed the vendor, who fortunately removed the (critical) vulnerabilities quickly. As an update is available, I’m now publishing information about the vulnerabilites.

CSRF in a real world application
About Cross Site Reference Forgery attacks I’ve written in a previous post. Here is an example of what you can do with it in a real world application: An attacker could add his own administrator users, change the current’s administrator’s user name and password, or create malicious pages in the content management system. Vulnerable is Radiant version 0.6.6 and most likely previous versions. Not vulnerable is version 0.6.7.

In this proof-of-context page, you have to enter the URL of your Radiant setup and click the link. If you you’re still logged in to that site, i.e. your cookie didn’t expire, a new administrator “cracker” with the password “cracker” will be added. Of course the attacker won’t ask you about the URL, and there are many ways to obfuscate the attack.
Changing the password
To change the password of an account, the user doesn’t have to enter the old password. As Radiant version 0.6.7 is not vulnerable to CSRF, the admin’s password may not be changed by CSRF. However, if an attacker manages to use the application in the admin’s name, he will be able to hijack the entire application by changing the admin’s password and possibly the user name. The attacker may use the application if he managed to brute-force the admin’s login credentials or if he got hold of the admin’s cookie (by listening to network traffic, for example).
Although this is an attack with (hopefully) difficult preconditions, I prefer to take care of second level attacks, too. As a precondition, require to enter the old password when changing the password, and use good passwords.
Unsalted passwords
The user’s passwords in the database are encrypted, but not salted. So if someone gets hold of a user entry in the database, he can brute-force the users password in the matter of minutes using rainbow tables. From version 0.6.7, passwords are salted.

 

Holes in the textile
At least the Textile filter is vulnerable to injection, try to inject this:

!http://www.google.com/intl/en_ALL/images/logo.gif(Bunny” onclick=”alert(‘XSS’))!

You can find more details in this post about Textile security. This is how an attacker could introduce malicious content. Of course this would require that the attacker has access to the application. But, as mentioned before, I prefer to make sure less/nothing will happen, if someone got past the first barrier.

The countermeasure against this, is to use Rails’ sanitize() method with the Textile output.

[WebAppSec] Automatic security and HackerSafe

Several people asked me about automatic assessment tools to check the security of an application stack. My opinion is that they may be a great support, but they cannot replace some manual work (oh, well, maybe). Rails test are a great way to make sure your application is safe, but you have to write them on your own. Security is not a plug-n-play product, but rather a process.

Automatic security
One automatic security scan is provided by McAfee. The HackerSafe certification is a service that detects vulnerabilities on web sites using automatic tools. If all tests pass, the site owner gets an HackerSafe logo, that he can put on his site. Over 80,000 sites, according to McAfee, use the HackerSafe logo to increase customer trust. According to the description, the service uses port scans, a vulnerability scan on the network layer, but also an automatic audit of the web application layer. On this layer, it looks for SQL Injection and Cross-Site Scripting (XSS) vulnerabilities. It is, however, not clear whether the service scans for other important attack methods, such as CSRF.

 
XSS and HackerSafe 
But, apparently, protection from XSS and other vulnerabilities is not a prerequisite for the HackerSafe logo. Russ McRee discovered several XSS holes in HackerSafe certified sites which allows the attacker to grab customer credentials or redirect the user to a malicious web site. He also made a video to demonstrate various XSS holes in five certified sites. Someone also found an SQL Injection vulnerability in a HackerSafe certified site. And I've seen at least one HackerSafe site which is vulnerable to CSRF. Although, maybe McAfee does not scan for CSRF, it is definitely an important attack method.
 
McAfee reacts 
A spokesperson for McAfee told British media that the company does not find XSS holes to be as critical as SQL Injection or other vulnerabilities. According to her, an XSS hole would not lead to revocation of the HackerSafe certification, although the company informs the customer about it. She added that XSS holes cannot be exploited to break into a server. No they cannot, but an attacker may steal the user's login credentials or credit card number, install malware on the client's computer or snitch his authentication cookie.
 
HackerSafe – just an image? 
After all, the HackerSafe certificate means that the site is protected against known attacks. It does, however, not mean that the site is not vulnerable to important attacks on the web application layer, which accounts for "an estimated 70% of all security breaches", according to the McAfee web site. And it does not mean that the site has no logic flaws, which gives an attacker (or another user) access to information he is not allowed to see. This can only be done by a manual security audit.

CSRF – An underestimated attack method

Cross Site Reference Forgery works by including malicious code or a link in a page that accesses a web application that the user is believed to have authenticated. If the session for that web application has not timed out, an attacker may execute unauthorized commands.

Most Rails applications use cookie-based sessions. Either they store the session id in the cookie and have a server-side session hash, or the entire session hash stays on the client-side. In either case the browser will automatically send along the cookie on every request to a domain, if he can find a cookie for that domain. The controversial point is, that it will also send the cookie, if the request comes from a site of a different domain. Let’s start with an example:

 

  • Bob browses a message board and views a post from an attacker where there is a crafted HTML image element. The element references a command in Bob’s banking application, rather than an image file (note that .src is meant to be src).

  • <img .src=”http://www.bank.com/transfer?account=bob&amount=1000&destination=attacker”>

  • Bob’s session at www.bank.com is still alive, because he didn’t log out a few minutes ago.

  • By viewing the post, the browser finds an image tag, which it tries to load from www.bank.com. As explained before, it will also send along the cookie with the valid session id.

  • The web application at www.bank.com verifies the user information in the corresponding session hash and transfers the money to the attackers account. It then returns a result page which is an unexpected result for the browser, so it will not display the image.

  • Bob doesn’t notice the attack, only a few days later he finds out about the strange transfer.

It is important to notice that the actual crafted image or link doesn’t necessarily has to be situated in the web application’s domain, it can be anywhere – in a forum, blog post or email.

 

See the figure at shiflett.org to see how CSRF works.

 

CSRF appears very rarely in CVE (Common Vulnerabilities and Exposures), less than 0.1% in 2006, but it really is a ‘sleeping giant’ [Grossman]. This is in stark contrast to the results in my (and others) security contract work – CSRF is an important security issue.

 

 

CSRF Countermeasures

First of all, GET and POST have to be used according to the W3C. Secondly, a security token in non-GET requests will protect your application from CSRF.

The HTTP protocol basically provides two main types of requests – GET and POST (and more, but they are not supported by most browsers). The World Wide Web Consortium (W3C) provides a checklist for choosing HTTP GET or POST:

 

Use GET if:

  • The interaction is more like a question (i.e., it is a safe operation such as a query, read operation, or lookup).

Use POST if:

  • The interaction is more like an order, or

  • The interaction changes the state of the resource in a way that the user would perceive (e.g., a subscription to a service), or

  • The user be held accountable for the results of the interaction.

 

The verify method in a controller can make sure that specific actions may not be used over GET. Here is an example to verify that the transfer action will be used over POST, otherwise it redirects to the list action.

 

verify :method => :post, :only => [ :transfer ], :redirect_to => { :action => :list }

 

With this precaution, the attack from above will not work, because the browser sends a GET request for images, which will not be accepted by the web application.

But this was only the first step, because POST requests can be send automatically, too. Here is an example for a link which displays harmless.com as destination in the browser’s status bar. In fact it dynamically creates a new form that sends a POST request (.href is meant to be href).

 

<a .href=”http://www.harmless.com/” onclick=”var f = document.createElement(‘form’); f.style.display = ‘none’; this.parentNode.appendChild
(f); f.method = ‘POST’; f.action = ‘http://www.example.com/account/destroy’; f.submit();return false;”>To the harmless survey</a>

 

Or the attacker places the code into the onmouseover event handler of an image (again, .src is meant to be src):

 

<img .src=”http://www.harmless.com/img” width=”400″ height=”400″ onmouseover=”…” />

 

There are many other possibilities, including Ajax to attack the victim in the background. The solution to this, is to include a security token in non-GET requests, which will be checked on the server-side. In Rails 2 this is a one-liner in the application controller:

 

protect_from_forgery :secret => “123456789012345678901234567890”

 

This will automatically include a security token, calculated of the current session and the server-side secret, in all forms and Ajax requests generated by Rails. You won’t need the secret, if you use CookieStorage as session storage. It will raise an ActionController::InvalidAuthenticityToken error, if the security doesn’t match what was expected.

 

Note that cross-site scripting (XSS) vulnerabilities bypass all CSRF protections. XSS gives the attacker access to all elements on a page, so he can read the CSRF security token from a form or directly submit the form.  This is how the Samy MySpace worm did it.

ImageMagick security advisory

A security advisory has been released for libpng, the "official PNG reference library". Libpng is used by ImageMagick, "a software suite to create, edit, and compose bitmap images". Some Rails applications use it to convert, resize or to create thumbnails. The original security advisory was issued by oCERT:

Applications using libpng that install unknown chunk handlers, or copy unknown chunks, may be vulnerable to a security issue which may result in incorrect output, information leaks, crashes, or arbitrary code execution. The issue involves libpng incorrectly handling zero length chunks which results in uninitialized memory affecting the control flow of the application.

The security advisory from libpng reads:

We believe this is a rare circumstance. It occurs in "pngtest" that is a part of the libpng distribution, in pngcrush, and in recent versions of ImageMagick (6.2.5 through 6.4.0-4). We are not aware of any other vulnerable applications. 

And here is the CVE:

libpng 1.0.6 through 1.0.32, 1.2.0 through 1.2.26, and 1.4.0beta01 through 1.4.0beta19 allows context-dependent attackers to cause a denial of service (crash) and possibly execute arbitrary code via a PNG file with zero length "unknown" chunks, which trigger an access of uninitialized memory.
 
Although the impacts are not clear, it is advisable to update ImageMagick, the current version is 6.4.0-7.

[WebAppSec] The idea of negative CAPTCHAs

Spam and automatic submitters really are a problem. One idea to defend this are CAPTCHAs. CAPTCHAs are noisy images and the user (usually) has to recognize the text in the image and enter it in a field. Although some weak algorithms are already broken, this is a good way to keep junk content away. But as automatic recognition gets better, the CAPTCHAs get more sophisticated, and thus harder to read for humans. CAPTCHAs are annoying.
 
Negative CAPTCHAs
The idea of negative CAPTCHAs is not to ask a user to proof that he's human, but reveal that a spam/login robot is a robot (bot). Most bots are really dumb, they crawl the web and enter their junk in every form's field they can find. Negative CAPTCHAs take advantage of that and include a "honeypot" field in the form which will be hidden from the human user by CSS or JavaScript. Ned Batchelder has several ideas how to do that in his original post.
 
On the server side, you will check the value of the field: If it contains any text, it must be a bot. Then, you can either ignore the post or return a positive result, but not saving the post to the database. This way the bot will be satisfied and moves on. You can do this with annoying users, as well.
 
Next step 
This is the basic idea of negative CAPTCHAs, you can make them more sophisticated with Ned's help.

[WebAppSec] Sign-in seals against phishing

There's a new sign-in seal on the Yahoo! login page, which is intended to make phishing attacks more unlikely.

A sign-in seal is a secret message or photo that Yahoo! will display on this computer only. Look for it every time you sign in to make sure you're on a genuine Yahoo! site. If the message, photo, or colors are different, you may have landed on a phishing site.

There might be other techniques to fight phishing, but it is certainly smart to raise awareness. And the technology behind it is clever too. Of course a normal browser cookie would go away from time to time when you (or the browser) clear your cookie cache. So Yahoo! uses so-called Flash SharedObjects which are sort of Flash cookies. They're available cross-browser, and they won't go away normally, because not many people are aware of how to clear these objects.

Intranet and Admin Security

These days the intranet is coming back. I heard it a couple of times: Our intranet is safe, there’s an authentication system and it can be accessed  by hosts from our local IP range only, but no, there are no further security measures. If someone manages to get in, he will be able to do and see a lot. And, yes, the bad guy can get in under certain circumstances.

Last year, for example, we have seen the first tailor-made Trojan which stole information from an intranet, the “Monster for employers” web site of Monster.com. These Trojans are very rare so far and the risk is quite low, but it’s certainly a possibility and an example of how the security of the client host is important, too.

 

XSS in your intranet
While special malware might be less likely for small intranets, XSS and CSRF are not. If your intranet application re-displays unsanitized user input from the extranet (user names, comments, spam reports, order addresses to name just a few uncommon places where I’ve seen malicious user input), the application will be vulnerable to XSS.
Already one single place in the intranet where the input has not been sanitized makes the entire application vulnerable. Vulnerable to what? Well, cookie stealing (YES, it’s a priviledged intranet cookie), content alteration to lure victims to a fake intranet where he might enter confidential information and so on. So I hope you have found a way to eliminate XSS everywhere in your app.

 

CSRF in your intranet
Yup, CSRF (Cross Site Request Forgery) is real, as well. It takes place in combination with XSS or the old-fashioned way: Send an HTML e-mail with CSRF to the victim or lure him to an infected web page. What is CSRF? Take a look at two examples which trigger a GET and POST action (.src is src):

<img .src=”http://intranet/project/1/delete” />

Generate this in Rails and you have a link to a POST action:

link_to(“To the survey”, “http://www.your-online-expense-tracker.com/account/delete”, :method => :post)

Now if the user views the page (for the image) or clicks the link, and he is logged in to the application (i.e. the cookie is set in the browser), the project or account will be deleted. Of course, the attacker has to know the URL structure, but most Rails URLs are quite straightforward or they’re publicly accessible like in the expense tracker application.
The attacker may even do 1,000 lucky guesses. The countermeasure in Rails is to include a token in each POST request that will be verified on the server. See the first post about this, but the csrf_killer plugin has been merged into Rails.

 

Administration
Now, you do have an administration interface for your application? How about its security? Did you take it more serious than the actual applications’ security? You should, because in most cases a security breach is more harmful here.

The common admin interface is like this: It’s located at www….com/admin, may be accessed only if the admin flag is set in the User model, re-displays user input and allows the admin to delete/add/edit a lot. Here are some thoughts about this:

  • As an admin interface is kind of an intranet, the same vulnerabilities as described above may be there. The attacker could steal an admin cookie (via XSS) or use CSRF to delete some users: www….com/admin/user/delete/2

 

  • It is always very important to think about the worst case: What if someone really got hold of my cookie or user credentials. You could introduce roles for the admin interface to limit the possibilities of the attacker.
    And how about special login credentials (other than the ones used for the public part of the app) for the admin controller and another password for very serious actions?

 

  • Does the admin really have to access the interface from everywhere in the world? Think about limiting the login to a bunch of source IP addresses.
  • Put the admin interface to a special sub-domain such as admin.application.com. This makes stealing an admin cookie from the usual domain impossible.
    This is because of the same origin policy in your browser: An injected (XSS) script on www.application.com may not read the cookie for admin.application.com and vice-versa. Of course this precaution will be useless if the attacker got hold of the cookie from www.application.com and may simply copy the cookie string to make one for the admin.application.com host. Use two session tables (if you use the :active_record_store session store) or a seperate admin application for that.

The Tainted Edition

There has been a discussion about whether to untaint or not. A string becomes tainted in Ruby when it comes from an external source, for example. The standard Ruby method untaint marks it as untainted. Plugins such as SafeErb do not allow the programmer to output tainted strings (in Erb) in order to protect the application from XSS. This works fine in my experience (even in Rails 2) and won't need you to untaint manually too often.
 
There is a good comment in the mentioned discussion (and the author has written an interesting article about safe strings):
 
"What most tainting-based solutions seem to miss is that 'safeness' or 'taintedness' is not a property of a string but a relationship between the string and the contexts in which it is used."
 
Indeed, SafeErb escapes and untaints the strings according to one context only – HTML (SGML) – and that is the purpose of the plugin. But there are a lot of other contexts you will use strings in:
 
SQL
Thanks to clever helper methods, this is hardly a problem in most Rails applications. However, you have to follow the rules and remember the problem whenever you use tainted strings in plain SQL or uncommon places. Use sanitize_sql() to escape in this context.
 
SGML (HTML, XML, RSS…)
Escape strings using html_escape() or h() against XSS.
 
CSS
Beware of CSS Injection if you render style sheets using tainted strings. This was a hole the Samy worm exploited.
 
Update: Textile
Textile (by means of RedCloth) should be used only together with a white-list sanitizer like Rails' sanitize(). In addition to my previous post, it is possible to inject scripts in image titles like this: !bunny.gif(Bunny" onclick="alert(1))!
 
Will become:<p><img .src="bunny.gif" title="Bunny" onclick="alert(1)" alt="Bunny" onclick="alert(1)" /></p>
 
JavaScript
Do escape strings in a JS context as well if you render code using tainted strings.
 
JSON
There has been a problem with the to_json method earlier. Solved in Rails 1.2.5.
 
Rails
Do you use the params hash in Rails methods that accept hashes? How about redirect_to(params) or similar? Imagine what will happen when the hash contains a :host key! This is logic injection and can't be sanitized.
 
Log files
Someone could fill up your server's disk or manipulate your log files using log file injection. Remember to sanitize, filter (see filter_parameter_logging()) and truncate here.
 
Second level
Beware of command line injection.
 
All these different contexts raise the question when to sanitize a string, before or after storing it (if it is stored). Of course for some contexts (SQL, shell), it certainly has to be sanitized before being stored/processed. But what about the most important context in web applications, SGML? Will I save a sanitized string or the raw input? I prefer to sanitize (or escape actually) strings according to a context when using it in that context, because in a large application you will never know in which contexts you will use the input data in the future.
For performance reasons I store one untouched and one escaped (and even textiled and white-listed) version of the input. The raw version will be used if the user wants to edit the data, and the untainted version will be displayed.
 
There have come up quite a lot of plugins recently trying to automatically escape the user input data.

What I don't like about these solutions is that it might be seen as plug-n-play security to install and forget, because it does it all automatically. In my opinion security is a process and you have to reconcile for each and every string what it represents and how to escape it in this context. Of course an automatic escaper can be a great help, but only if you remember to sanitize it differently in an other context.