6

It is well known that Facebook uses javascript responses (JS,not json) which is prefixes with while(1) & for(;;); in order to prevent script tag to steal the json data when old browsers are being overloaded with their Array ctor & Object ctor.

But from a recent try , it seems that this is not the case anymore (for friends list , which i'm sure it was used)

enter image description here

Notice that now , the content-type is :

content-type: application/octet-stream

But why did they do it ? is it now safe ? ( I know that it's for older browsers , but still...).

I know that [..]'s ctor was problematic. But what about {..}'s ctor ?

Question:

Why did facebook remove the infinite-loop ? and how do they now mitigate against json hijacking ?

I mean , what happens now if <script> tag will try to fetch the "getFiriends "list ? ( in a very old browser)

NB

Worth to mention that there are still others responses with infinite loop for {..} !! :

enter image description here

Also in here ( Object , with infinite loop)

enter image description here

Royi Namir
  • 131,490
  • 121
  • 408
  • 714
  • 2
    This was fixed on the browser side in 2011 ... if you are using a browser from back then I guess you got bigger problems than this – Jonas Wilms Mar 17 '19 at 11:42
  • Security aspect , your comment is no answering the situation. becuase its clearly that they still use it in other responses – Royi Namir Mar 17 '19 at 12:34
  • @SeanKinsey Can you please clarify how come FB changed it ? I've noticed that some services now does return infinite loop and some not. care to explain ? :-) – Royi Namir Mar 17 '19 at 14:39
  • you just pinged me :) (you can't ping people outside of a thread) – Jonas Wilms Mar 17 '19 at 14:45

1 Answers1

3

This attack (loading JSON as a <script>) is based on a few assumtions:

1) The JSON is itself valid JS (thats what the for(;;) changes), which also means that it may not start with a { as that is a block statement, which does not contain key-value pairs:

 { "a": 1 } // invalid JS, valid JSON *
 [{ "a": 1 }] // valid JS, valid JSON

2) The browser is very old (< 1% of the total users), as constructing arrays with the literal does not call the Array function in newer browsers (ES5 support is a good estimation for those).

Therefore this attack isn't possible in this case, as the API you mentioned returns an object, therefore (1) is not fullfilled. And even if the API would return an array, only a very small amount of people could theoretically be hijacked:

1) The browser has to be very old, and then the browser itself is probably a bigger risk, and the browser has to even support JavaScript.

2) The client has to visit a malicious site, which is very unlikely due to spam filters / blacklists at various levels.

3) The user has to be logged in at facebook while visiting the malicious website.

Worth to mention that there are still others responses with infinite loop

I guess this is generally a thing of the past. It will take a while until all APIs got refactored / migrated. I assume adding/removing these 5 characters causes a significant overhead if you think at Facebook's scale.


*: If you try to load { a: 1 } you'll find out that it does not throw a SyntaxError! However this is neither valid JSON, nor does it create an object (it's a labelled 1 inside of a blocn statement).

Jonas Wilms
  • 106,571
  • 13
  • 98
  • 120
  • In my second image in the question , you can clearly see that they do **still use** inifinite loop with `{` – Royi Namir Mar 17 '19 at 12:06
  • @royi I don't know how their codebase looks like. Maybe it is more effort to remove than to keep it. – Jonas Wilms Mar 17 '19 at 12:09
  • I disagree about your first assumption. look please in [here](https://stackoverflow.com/a/3147804/859154) as it's states that `{a:1}` was also used – Royi Namir Mar 17 '19 at 12:24
  • @royi Hmm, maybe there was no block statement back then? I'll dig into the ES spec ... – Jonas Wilms Mar 17 '19 at 12:39
  • No way. Don;t search there becuase there was. notice that it wasnt required that the js will be valid. dont forget that contenttype supposed to be json and then `{a:1}` was a valid json. and then they hacked the setter. – Royi Namir Mar 17 '19 at 12:39
  • @royi I'm not sure about that, the only real attacks I could find used APIs that returned arrays. – Jonas Wilms Mar 17 '19 at 12:41
  • @royi It is required that it is valid JS. otherwise it would fail at parse time & wouldn't get exposed. – Jonas Wilms Mar 17 '19 at 12:41
  • @royi no, you are missunderstanding the attack. The trick is to load the JSON as if it was JS, then it gets parsed at JS which you then can hook in. You can't load JSON without using AJAX, which can be blocked through the cross-origin policy – Jonas Wilms Mar 17 '19 at 12:45
  • yes, I stand corrected. its when you try to load json via script tag. yes – Royi Namir Mar 17 '19 at 12:46
  • btw look [here](https://stackoverflow.com/a/21510402/859154) . it also mentions BOTH array ctor and Object setter --------"_Except that when using a script tag to request JSON content, the JSON is executed as Javascript in an attacker's controlled environment. If the attacker can replace the Array or Object constructor or some other method used during object construction, anything in the JSON would pass through the attacker's code, and be disclosed._" – Royi Namir Mar 17 '19 at 12:46
  • @royi It does not specify however that the top level might be an object. If youd write an object hook for `[{ a: 1 }]` it'll also work. Have a look at the second answer, which states that explicitly – Jonas Wilms Mar 17 '19 at 12:49
  • anyway , a script that gets `{a:1}` would perfectly run in browser. and if you overloded ( back then) the object ctor , then you'd get the data. – Royi Namir Mar 17 '19 at 12:51
  • @royi no it does not! `{ a: 1 }` is a SyntaxError! [proof](https://jsbin.com/lecetogase/edit?console) – Jonas Wilms Mar 17 '19 at 12:52
  • @royi I have to admit that `{ a: 1 }` is a bad example. `{ ... }` is a block statement, `a:` is a label, therefore it'll parse it successfully. However, there is no object created here. – Jonas Wilms Mar 17 '19 at 13:04
  • well , this makes me wonder how the object ctor was identified as a problem at first place......... array , I know. but object ......? yes it's a label .... and if no object is created here then where is the pitfall ?? – Royi Namir Mar 17 '19 at 13:09
  • @royi well `[...]` is an array in JSON and in JS. `[{ a: 1 }]` is an array with an object literal inside. – Jonas Wilms Mar 17 '19 at 13:10
  • I know . but we're after {...} here ... which is what you and i trying to figure how it used to work as an attack – Royi Namir Mar 17 '19 at 13:10
  • @royi as I said earlier, the block statement might be a newer invention, and older engines might parse `{ a: 1 }` as an object literal. Haven't had the time to verify that though – Jonas Wilms Mar 17 '19 at 13:11
  • @royi Just found the ES3 spec, it did have the block statement already. As far as I can see, my statements hold true – Jonas Wilms Mar 17 '19 at 13:17
  • So if it did have the block statement already , then where is the object constructor hack gets in ? – Royi Namir Mar 17 '19 at 13:18
  • @T.J.Crowder But - how come `{...}` ever was suspected to be read by json hijack ? it doesn't seem to activate the Object constructor at first place , since it's not being parsed as an object........ But bob [says](https://stackoverflow.com/a/3147804/859154) it did : https://i.imgur.com/7QIOpqB.jpg – Royi Namir Mar 17 '19 at 16:57
  • `{"a": 1}` is not a label. `{a:1}` - is – Royi Namir Mar 17 '19 at 17:00
  • @RoyiNamir - Fair point about `{"a": 1}`! At statement level at global scope, `{"a": 1}` is a syntax error. – T.J. Crowder Mar 17 '19 at 17:01
  • @T.J.Crowder Anyway , I'm trying to understand , why they did remove the infinite loop ( and do still use it on other `{..}` areas , like images in original question).... – Royi Namir Mar 17 '19 at 17:02
  • @RoyiNamir - I suspect bobince was incorrect about that. `{` in statement context has always started a block. (Of course, that doesn't mean there weren't implementations that got it wrong at one point. I don't know that any *did*, just that it's possible, bobince was/is fairly clued in.) – T.J. Crowder Mar 17 '19 at 17:04
  • @t.j. it's a mess. All those answers are either outdated, missleading, wrong, contain dead links and so on... tried to clarify this answer – Jonas Wilms Mar 17 '19 at 17:47