Thursday, January 31, 2013

Rails is [Fr]agile. Vulnerabilities Will Keep Coming.

This post is just a thought, with some minor vulnerabilities(all of them are reported). Everyone knows these "January events":
1) find_by_* can be tricked to use user input's :select as injection
2) XML can be tricked to use YAML
3) YAML can be tricked to initialize arbitrary objects
4) AGAIN! JSON can be tricked to use YAML(see point 3..)

Is it over? No, I guess.
This is just a short demo, how FAR this [Fr]agileness can lead to:
There is "redirect_to" method and it accepts:

    # * <tt>Hash</tt> - The URL will be generated by calling url_for with the +options+.

    # * <tt>Record</tt> - The URL will be generated by calling url_for with the +options+, which will reference a named URL for that record.
    # * <tt>String</tt> starting with <tt>protocol://</tt> (like <tt>http://</tt>) or a protocol relative reference (like <tt>//</tt>) - Is passed straight through as the target for redirection.
    # * <tt>String</tt> not containing a protocol - The current protocol and host is prepended to the string.
    # * <tt>Proc</tt> - A block that will be executed in the controller's context. Should return any option accepted by +redirect_to+.
    # * <tt>:back</tt> - Back to the page that issued the request. Useful for forms that are triggered from multiple places.

Agile, huh?
Let's assume there is open redirect(it's bad but it happens): 'redirect_to params[:next]'
Here is generated response for /path?next[status]=200&next[protocol]=javascript:alert(document.domain)

<html><body>You are being <a href="javascript:alert(document.domain)//HOST/">redirected</a>.</body></html>

Status 200 - no redirect happened. URL has XSS. Now you just need to make user to click it. You can use clickjacking, but he can also decide to click by himself. And you can also set custom :alert, :notice - flash messages.

Another one - famous arrays with nils, which was patched in JSON/XML parsers too and it broke some apps. If you pass [nil] to find_by_ methods you can also find records where this field IS NULL(It wasn't set, intentionally). This is a good vulnerability for all kinds of APIs, spree example:
(I'm sorry about this PR and I behaved irresponsibly. Following bugs were disclosed privately.)

Conclusion: keep an eye on your 'params'. Don't put it in 'agile' methods. It hurts.
Another conclusion: should we (Rails) start using less magic and more predictable behavior? I'm not sure.

P.S. Most likely this is the last technical post in the blog. I am starting a yet another security agency(core service is the Ruby/Rails audit), doing pen-test and code review for some cool startups and it's awesome when you can hack/help people and get paid for it. 
Want to make your Ruby application super secure? Drop a line: 
Following security posts will be published on another website, some of old posts will be probably rewritten, with nifty design etc. I got a lot of delicious stuff in my drafts ;)

Friday, January 18, 2013

XSS Hunter: Using XSS Auditor For Great Good

discussion: Hacker News, reddit
What is XSS Auditor?
It's a built in chrome(and IE) tool, switched on by default(you can control it with X-XSS-Protection header, either 0;, 1; or 1;block), which inspects all request params and response body trying to find if any of param present as malicious script inside of body. If it detects anything odd - by default it just removes it from HTML. It can lead to weird things..
First of all we will use it for some evil.
I am telling nothing new, but a trick from my previous post - slicing scripts and events you don't like in some page
You can remove any event "on*", any javascript:... link and any <script> tag. Best targets: confirms(to make clickjacking easier) and framebuster scripts, sending them in request params(?removal=<script>remove_me();</script>). Without them life of hacker gets easier.

Don't touch my framebuster!
I created a neat trick to disallow such things to happen. Just put some random code in your code(<script src="framebuster.js?<%=rand(1,9999)%>"></script>) - nobody knows how code looks in response so it's impossible to 'cut' it off.

XSS Auditor is a pain in ass for scriptkiddies.
This is out of question. They just hate it. So let's use it even for greater good!
I wrote a demo script which detects if XSS Auditor removed any inject and if it did - we fire up document.onxssprotection event(which will notify the administrator of website for example).

Don't touch my auditor of XSS Auditor!
And we don't want our XSS auditor removed either - so when you use it be sure to write src="auditor.js?RANDOM"

I like it more than any WAF - "native" environment detects XSSes better than server side middlewares(take into account performance too).

This code is rather demo and may content bugs, I did not test it in all browsers and IE. Feel free to contribute.

Thursday, January 10, 2013

Rails 'params' #2

I discovered [1, nil] attack, but while i was checking unsafe query generation and DoS with symbols people on twitter found RCE for YAML through instancing some class that will eventually eval attribute from user input! Sweet!
IMHO this article is best on topic, and explains the whole chain of exploitation.
I told you, didn't i?

Thursday, January 3, 2013

Rails Security Digest. 'params' Case

Old tricks, new workarounds. In this post I gave mitigation advice and some explanation of WTH IS GOING ON.

The issue can be mitigated by explicitly converting the parameter to an expected value.  For example, change this:
to this:

You need to send keys as symbols! It's not that easy. While you can use symbols in HashWithIndifferentAccess, those symbols params[:id][:symbol] is not the case - only 'symbol' key will be used by find_by_* method.

2. Maybe put poisoned payload in your session cookie?
Tenderlove explains:
>However, this exploit does not require session secrets. The person who wrote the blog post wrote about essentially two vulnerabilities: session forging and SQL injection.
You will need to know session_secret, which is hard to steal. Forget about it.

3. Maybe craft poisoned payload in params? Normal application/x-www-form-urlencoded won't work, because keys are strings. JSON decodes to strings either. params is always HWIA. Injection is never going to happen through params[:id]