Ow Facebook Part 3: Token Misconfigurations

11:28 AM

Facebook, unlike other websites have a very shitty token usage strategy. First I taught I discovered a CSRF, upon further investigation. I just discovered it’s a shitty design that never got/will be fixed.

Using m.facebook.com, while you share a status, there is an anti-CSRF token called fb_dtsg, actually that token appears in almost always action you do. But here is the fucked up thing about that token, even though the token regenerates for each action. The first token would do fine, actually the token works 72hours for any action infinite times. So what is the point of generating a new token every time?

So I reported the issue and got this 

“…Are you reporting a CSRF attack that requires one of the victim's FB_DTSG tokens as a pre-requisite?”

Yes, I was reporting a CSRF attack that requires a valid anti-CSRF token, when I say it out loud, I feel stupid, but it’s true. If an attacker somehow manages to get a victims token leaked, sniffed, etc, that's a problem. So when you have a used token, that isn’t totally useless, you can craft most type of CSRF attacks. But that was something Facebook rejects to fix, again.

Then I found something interesting, https://m.facebook.com/ajax/dtsg/?__ajax__=true is a very interesting link. It generates tokens for the logged in user, when you visit that link, it just generates you a valid token and prints it out with for how long it is valid for. My first try was click jacking, drag and dropping game to make the victim copy the token and paste it. Then using that token to craft an instant CSRF, but shit, X-FRAME-Options was there, I had to think of something else.

Then I got a very rare, but possible ( I think ) possibility. When you visit, https://m.facebook.com/ajax/dtsg/?__ajax__=false even when you’re not authenticated, it just prints out a random users access token with for how much long it’s valid for. But that next to nothing considering there are over a billion users in Facebook and you can’t possibly know for which user. Guessing actually is 0.000081% only probable. So shit. But now totally shitty because,

Imagine a website as popular like Google, Imagine them being malicious and want to make everyone share some status update. They get around billion hits a day. But how does this help... So imagine while you’re on Google or even watching a long 6 hour long video, your browser in behind is designed to bruteforce the token using something like (pseudo code)

$tok = file_get_contents($token); //somehow get token;
foreach($tok as $sometoken){
                //javascript/ajax for you to request an action

That code is PHP but we can make a JavaScript code to request a token from our php code (where we store random valid tokens), when the PHP returns random valid token for some unknown user, we can use that token to make a request in behalf of the user using JavaScript (their logged in browser) and if the user is stuck in that website for atleast 6 hours (like watching a video) and the website in background brute forcing their token, it is somehow probable the token might get correct and create us a CSRF. Enjoy!


Ow Facebook Part 2: Facebug Logic Flaws

4:47 AM

This series is a bug class of Facebook that got declined for being unexplainable, unexploitable or having 0 probability of exploitation. I decided to share those for fun because it seems I got like 2-3 hours of spare time. Check out my recent post before this for part one.

This bug isn’t going to be fixed anytime soon because of being/having no risk at all other than for fun. Using the first bug, this one, you can create events with years that are fat or nonexistent.
Events are only allowed to be created from 2012-2024, but you can create even for years like 30000, 31337, 1337, very deep in the future or in the past. :)

It’s not a big secret; it’s just a very common logic flaw. The program expects integer values and does not sanitize the given year is from 2012-2024 because in the database, only those years exist to be chosen from. But while tampering data, it is possible to change the value that is being sent to the server to store.

Here are the reproduction steps, first using https://m.facebook.com/events/create/basic
create a normal event, then go to edit, chose the event and start tamper data, then change the year to anything...  (Note: it have to be edited, the edit page contain the flaw. The first one is well sanitized)
Then enjoy sending your friends event invites with years like -25418 or 1337 or 31337… negative values are the fun part. -2012 will become -0012. How awesome is that?

Your homies be like “You have created an event back in -0012? :O” Haha. Awesome.

Same thing happened in Facebook birthday, the limitation is 1996 to change from but anyone who is aware of this bug can change his/her birth date to recent years like 2000 using m.facebook.com. This violates Facebook’s rule and make you a minor and decrease your birth day, which is fun. No risk.

The same logic issues often occur in money related tasks. That’s a very sad thing considering you can steal money. Recently, while pentesting a website that contains a script to transfer money to one account to another I was actually able to steal money (would have stolen), this happened.

Obviously, while transferring money it decreases money you sent from your account and add it to the 
receivers account. It’s like -amount from you and +amount to the other dude.

Now imagine, the script does is “Your total amount - amount = remaining amount” imagine if we tamper the request and give it a negative amount, meaning, the formula becomes,
“Your total amount - ( -amount) = remaining amount”

Which is equivalent to “Your total amount + amount = remaining account” which means you are instead adding infinite money to your account.

Also most websites on their checkout page contain a hidden parameter holding the amount, tampering that to 0.01 is valid considering the script expects if the payment is complete using the payment token, whatever amount you are supposed to pay, you paid 0.01 which still makes the script true and execute the next step. Enjoy!

Conclusion: watch out for parameter tampering. It’s “almost always” forgotten.


Ow Facebook: Taking Over Random Accounts

12:25 PM

Okay, it seems I am obsessed with Facebook, I like it. But not obsessed, just addicted? Anyway, this is a series of declined obvious Facebook Bugs I have reported in the program and are still available to be exploited.

This one is a bug that is still out there for being “unpractical” for the Facebook security team. Well, frankly, it’s just a theory I have in my mind. Never tried it because I don’t have a lot of zombies. Zombies? What am I talking about right? Well you will get it soon, stick with me.

When you reset your password, you will get an option to send it to phone by SMS, in the SMS there is a 6 digit token to confirm you phone and also a link to reset it, when redirect to the link, it just gives you a new password and a confirm new password input boxes. So the idea here is to bruteforce this tokens, here is the statics… over a billion users, at least 3-4 million resetting password in a day. Meaning there are around 4 million possible tokens to be found while brute forcing and use them to pawn random accounts. The link looks likehttps://fb.com/l/240jMqhGzXiy8 the last part is the part that holds the token. 13 character token that resets someone’s password is 240jMqhGzXiy8. But the bruteforce is next to impossible because of being 13 characters long, with a mix of lower case letters (26 possibilities), upper case letters (26 possibilities), and numbers (10 possibilities, including 0). So that's 62 raised to the 13th power. That equals 200028539268669788905472 possible values -- 200 sextillion!

But that is a true sextillion if we are looking for a particular value, with a growing number of users resetting their passwords there are around 4 million possibilities. If we do the math that’s a very low percentage of capturing an actual account. But imagine if you have botnets, the zombies, imagine a person with a great internet speed and around 1 billion zombies that take almost an hour to capture all of the 4 mil accounts and take them over.

Now a cleaver attacker does this, he creates an automated script to incriminate the Facebook user ids and request a password reset to over a billion users Facebook holds, that actually doesn’t do anything other than send every user a token. it will help make the bruteforce less time consuming considering we have a possibility of taking over a billion tokens and a billion accounts. Interesting eh?

So if you have the zombies or a system performance that effective, you can still own a lot of accounts. One 
thing I then realized is to study the nature of the token to make our bruteforce algorithm a little effective and less time consuming, they usually start with 3 numbers then characters to be randomized.

This should be classified as a threat, even though the probability of exploitation is very low. Confirming the safety of the users is only by limiting the rate by try and not just because of probability, which still puts the users in a less probable but yet dangerous situation.


Header Based Login Bypass

1:06 PM

This is an unusual type of attack I discovered while doing a pentest today, this is possibly found in almost every PHP code I have written, and almost 50% of the sites I tested on, it is occurred in a very unpredictable place, the header(“Location: redirect”) header in php, it is occurred because the page redirects the visitor to another page by returning an HTTP status code of 301/302 after requesting a page that needs to be authenticated to get access into, but we can manipulate our browser not to receive Redirection codes using an HTTP Editor or Firefox’s NoRedirect Plugin


                header(“Location: admin.php”);
<!—Administration Center -- >

The script is incorrect bcause the script is not terminated after the “header()” line. An attacker can access the content of the administration page by using an HTTP client that doesn’t follow redirection and can create an authentication bypass vulnerability
The correct code should’ve been

                header(“Location: admin.php”);
<!—Administration Center -- >

And the code I was working on contain the following code,

function redirect($url,$msg_type=false,$msg=false,$type=false){
                                if($msg and $msg_type and $type)
//creates new token
                $isAuth = false;
                      $isAuth = true;
                      redirect('../' . PAGE_LOGIN);
//… other blah blah

And exploitation was simple as shit, I just installed a simple Firefox plugin called “NoRedirect” then add this line to the list “^http://localhost” which will then block any HTTP based redirection, then I just requested the page… http://localhost/project/index.php and since the redirect() won’t work now…. Just got inside. As this isn’t a very popular technique I decide to share it, Happy Hunting!


Facebook HTTP Parameter Renaming (0day) (Unfixable?)

1:57 AM

I have been participating in Facebook bug bounty this week to find interesting bugs other than XSRF and XSS. Something so uncommon. A turn out Facebook is full of them. I will blog about some of these bugs Facebook declines to either payout or fix. One is HPP (HTTP Parameter Pollution); this one is kind of interesting. Facebook is coded with pure PHP and PHP by itself suffers from pollution issues by its nature. Facebook’s WAF is designed to detect and stop HPP, if parameters are duplicate. Now that’s when Parameter Renaming comes. When URL arguments including POST and Cookies are parsed in PHP they use the parse_str function – it accepts strings like:

Note: Blogger coudnt let me write nullbytes so i write them as %0,0 so take it without a comma. 

This function also accepts associative arrays such as:


When we specify only one bracket “[“  and don’t close it, it will get converted into an underscore. This means that the two strings below ($s1 and $2) create identical associative arrays when parsed.
$s1 = “user_id=123”;$s2 = “user[id=123”;
parse_str($s1, $o1); parse_str($s2, $o2);

Now both $o1 & $o2 contain:

string(3) “123” }

You know what that means, we can re-write any parameter names with underscores on them using a square bracket (in this case the redirect_uri parameter);

We can also do a similar trick with null bytes (%0,0). However, in this case anything after the null byte in a parameter name gets removed so both the strings below are parsed into the same array:
$user = 123

Furthermore, Facebook’s WAF was filtering the QUERY_STRING parameter in an attempt to prevent HTTP parameter pollution, now we can turn requests like (in HPP):

account_ id=123&account_ id=456



{Since PHP by its nature pick the last one to execute, the second Parameter (account[id=456 which is equivalent to account_ id=456 for PHP) will be chosen. }

Or into:


and that’s what happened in this case, the redirect_uri (or any other redirection parameter Facebook hosts) is being checked not to redirect outside of Facebook, but turns out we can using this technique since only the first parameter is being checked with that name,

So providing names like “redirect[uri=” or “redirect_uribullshit” which is equivalent for PHP to redirect_uri, it is possible to perform HTTP parameter renaming,


That is not an open redirection issue. It however could be a linkshim evade, not sure. I reported this issue to Facebook and I am very happy with their response, they were happy I informed them, the thing is the bug bounty program works if there is at least one exploitation scerio which in this case isn’t; it’s just an interesting bug. But this can be exploited with XSS or even Session Fixation (which I don’t have at the moment) (please feel free to re-submit this bug if you have found exploitation technique that is exploitable, would be happy to know if you inform me how too :-D ) 

Fix: the simplest fix I recommend is for your WAF to recheck the {$parameter} names and block if they contain either [ or %0,0 because without those there seems to be no parameter renaming. To be honest, I taught the null byte trick would be noticed by a WAF but It didn’t. More precisely while submitting parameters, using array based tricks would still might bypass that since the $_GET, $_POST and even the $_COOKIE global vars take arrays and concatenates them.
Ways to exploit this and re-write HttpOnly Cookies if/with XSS, 

//using [ to replace _
document.cookie = ‘session[id=EVIL;expires=Tue, 18 Apr 2024 13:32:42GMT’;
// or extending it with
document.cookie = ‘session_id%0,0ignoremebabe=EVIL;expires=Tue, 18 Apr 2024 13:32:42GMT’;

Let’s say the session_id cookie var is set for the current session, however, session[id is valid for 10 years. As soon as session_id destroyed by the browser (when it closes the session regenerates or when the user logs out) we end up with the single session[id in the browser which now becomes the first cookie in the list,

Set-Cookie: session[id=EVIL;
Which also means session_id=evil; for php since browsers respond cookie values both session[id=evil and consider them both to be unique, however php uses one of them to understand who that user is, J.