Description

There are various Facebook products like Ads Manager, Business Manager, Messenger Payments, etc. which requires an user to add some payment method to their Facebook account which can be credit card, debit card, paypal, etc.
eg. If I want to run Facebook Ads then I need to add a credit card or any other relevant payment method so as to use it. Same is with other products.

Facebook assigns a unique 15 digit random number to any card added to user's Facebook account and this id is known as credential id. This credential id is then used by Facebook to query about credit card details.

This credential id was querable via GraphQL and it allowed an attacker to use it(credential id) to get credit card details. But it exposed last 4 digits, address, expiry date, etc.

How one can get credential id?

1] I had reported a bug last year where Ad Analyst was able to escalate privileges and was able to access funding sources of the Ad account. This leaked the credential id of the payment method. Unfortunately this bug went duplicate but I was still able to use it to demonstrate the flaw.

2] Brute Force / Dictionary attacks :
We need to form 15 digit numbers so calculations are as follows...

This covers all the 15 digit numbers. We need ONLY 900000 billion numbers. This seems to be practically possible as it may take few weeks to do so.

But even if we consider it impossible, one can generate numbers in range like generating number from 931000000000000 to 999999999999999. This will be a lot quicker than previous one. Also, if we reduce the range and only brute force last 6-8 digits still we can generate a lot of valid 15 digit numbers.

So, now we assume that we can generate a large amount of valid unique 15 digit number.

*Note : I avoided running the real brute force/dictionary attack as it would get me access to real credential ids of real users which voids Facebook's terms. Instead, to prove my point I provided POC of my test accounts where I was able to show that brute force attack may work to get access to credit card details.

3] Other methods:
Ad account Admin removed from the Ad account having noted these ids can still use it now and get access credit card details.

Similarly, it applies to Business Manager as it has a separate payment management. A user having access to Business Manager but now removed from it can still have credential ids.

Proof Of Concept

1] Get an access_token which can access graphql. This token can be obtained by observing requests/responses of your Android/IOS Facebook app or other Facebook owned apps.

2] Now, get yourself a credential id via any of the methods listed above.

3] Encode the credential id in order to form a string as base64encode(p2p_credential_id).
eg. base64encode(p2p_999999999999999) --> cDJwXzk5OTk5OTk5OTk5OTk5OQ==

NOTE : Please note that credential id is never deleted from Facebook. So, anyone can access the details even if card is removed or account is deactivated.

How one can exploit it?

Try to form a valid credit card :
According to my research, it is possible to validate a credit card number using Luhn algorithm (https://en.wikipedia.org/wiki/Luhn_algorithm). One can generate a large set of credit card details then filter out the credit cards based on last 4 digits and pincode and expiry date. This will return a very small set of valid credit cards. Later, cvv number can be brute force or any alternative attack can be done if we have valid credit cards.
This attack is sophisticated and will require a lot of time but it is not practically impossible.

One can even think of innovative ways to use these stolen credit card details.

Impact

Once attacker knows the credential id then attacker can access credit card details which exposed the following:
1. last 4 digits
2. expiry date
3. address
4. country and other relevant details

Facebook determined that brute force attack may take a long time but considering other methods they patched the bug by placing permission checks on the endpoint. Now, users can only access their own credit cards.

Special Thanks

Thanks to Facebook for patching the vulnerability and all my friends who are supporting me for my work.

How can you learn GraphQL?

Timeline

January 1, 2017 at 11:35pm - Report Sent
January 13, 2017 at 6:22pm - Initial Response by Facebook
January 16, 2017 at 6:59am - Sent more information
January 18, 2017 at 1:55pm - Bug Confirmed by Facebook
January 24, 2017 at 3:44pm - Bug fixed and response by Facebook
January 27, 2017 at 7:40am - Confirmation of fix by me
February 1, 2017 at 4:31pm - Bounty awarded