As with previous cases, tracking scenarios where publishing of an object occurs but no publish permission is required, in this instance a Facebook page can have the profile picture updated without the need of publish_actions or the new publish_pages.

Seeing that with v2.3 introduction and publish_pages, this restriction should probably be in place. This is actually undocumented https://developers.facebook.com/docs/graph-api/reference/page/picture

This has been patched and now asks for publish_pages

Timeline

Apr 8, 2015 2:58am – Report Sent
Apr 8, 2015 8:23pm – Escalation by Facebook
Apr 15, 2015 3:57am – Patched and Bounty Awarded of $750 by Facebook

The page-id/links endpoint wasn’t properly checked for in the new 2.3 version and allows one to post without the publish_pages permission.

As noted here https://developers.facebook.com/docs/graph-api/reference/v2.3/page/links#Creating the endpoint is undocumented. If this were to be compared to https://developers.facebook.com/docs/graph-api/reference/v2.3/page/feed#publish

“A page access token with publish_pages permission can be used to publish new posts on behalf of that page. Posts will appear in the voice of the page.”

It is seen that the undocumented edge isn’t obeying this restriction.

Timeline

Mar 30, 2015 3:38pm – Report Sent
Apr 1, 2015 1:42am – Escalation by Facebook
Apr 6, 2015 4:57pm – Patched and Bounty Awarded of $750 by Facebook

There seems to be a permission check here missing for the the new videos thumbnail upload call.

Seeing that from F8 talks (specially Simon Cross talk: Get the Most Out of Login: Graph API 2.3) we know now that the docs reflect the current API codebase, then it adds support to the assumption no permission check was placed here at all.

https://developers.facebook.com/docs/graph-api/reference/video/thumbnails/

I initially found this while attending F8 Developer Conference but decided to inquire more about the new video features at the Developer Support booth and the Graph API booth. Both groups seemed to not know much about it at the time (The technical writer stated it was released 24-48 hours before being shown in the What’s New with Facebook Video talk)

This is basically similar to other permission checks like Change the description of a video without publish_actions permission

This is fixed and now returns

{
"error": {
"message": "(#210) This call requires a Page access token.",
"type": "OAuthException",
"code": 210
}
}

While using a user access token.

And

{
"error": {
"message": "(#200) Requires extended permission: publish_pages and manage_pages",
"type": "OAuthException",
"code": 200
}
}

While using a page token. Initially only public_profile was needed.

Timeline

Mar 28, 2015 8:49am – Report Sent
Apr 1, 2015 3:33am – Escalation by Facebook
Apr 10, 2015 8:49am – Patched and Bounty Awarded of $1500 by Facebook

Last year any request to a act_legacyID doesn’t have access to lead to an “Unsupported get request”. so it wasn’t possible to determine whether the act_legacyID you had was a valid ad account or not.

It seems this year a change has been implemented which I expected in white-listed applications (Facebook for iOS, etc) which allows one to determine whether the Ad account ID is a valid or not given a legacy ID format (act_legacyID)

Additionally to me, it seems, the error returned is of a format targeted to internal investigation. I’ve seen these errors only raised in GraphQL.

Finally the error is raised without the need for ads_read/ads_management permissions, which one would expect to gate before reaching errors providing more information than necessary.

This is patched and an error is now returned

{
"error": {
"message": "(#10) You do not have sufficient permissions to perform this action",
"type": "OAuthException",
"code": 10
}
}

Timeline

Mar 13, 2015 3:13pm – Report Sent
Mar 16, 2015 6:49pm – Escalation by Facebook
Mar 17, 2015 11:43pm – Clarification about reproduction instructions
Apr 15, 2015 2:07am – Patched by Facebook
Apr 15, 2015 11:40 am – Bounty Awarded of $750 by Facebook

Within Facebook API posts, the icon field has the access_token of the current application appended to it. This seemed to be a recent change, but not intentional as appending the access_token here doesn’t change the viewing permission of the icon.

Proof of Concept

A call to any /userid/feed or pageid/feed endpoint resulted in a format similar to the following

{
"icon": "https://www.facebook.com/images/icons/post.gif?access_token=ACCESS_TOKEN&fields=icon%2Cpicture&format=json&method=get&pretty=0&suppress_http_code=1",
"picture": "https://fbexternal-a.akamaihd.net/safe_image.php",
"id": "post_id",
"created_time": "..."
}

This also happened with post objects of the type event and video.

  • https://www.facebook.com/images/icons/event.gif
  • https://www.facebook.com/images/icons/video.gif

And the format appended was

access_token=ACCESS_TOKEN&fields=icon,picture&format=json&method=get&pretty=0&suppress_http_code=1

The issue here is that some applications are probably loading the icons to display in a feed on websites. Based on how these icons were stored and shown access_token might have open to public viewing without the application owner/developer knowledge.

Timeline

Mar 5, 2015 2:38pm – Report Sent
Mar 9, 2015 6:58pm – Escalation by Facebook
Mar 17, 2015 11:33pm – Patched and Bounty Awarded of $750 by Facebook

Via a combination of API calls, I am able to bypass this restriction. Specifically, I can post photos to friends’ timelines without the use of a whitelisted application (such as Facebook for iOS) and with a 2.0+ application (so no 1.0 tricks, thus this can work after 1.0 deprecation)

Background

In October 2013, Facebook Developer Team implemented a change to the API

Removing the ability to post to friends’ timelines via API
We have found that posting content via API (stream.publish) on a friend’s wall lead to a high incidence of user dissatisfaction (hiding content, blocking the app). After the migration period, posting content to friends’ timelines via stream.publish will no longer be allowed. Please use the Feed Dialog for posting.

https://developers.facebook.com/docs/apps/migrations/completed-changes

Proof of Concept

HTTP POST

/unpublished-photo-id

target=friend-id
published=1

Response

{
"success": true
}

Where an unpublished is created via a method found in https://developers.facebook.com/docs/graph-api/reference/v2.2/page/photos. The post is created and appears on the target’s wall with a notification.

This has been patched and now returns

{
"error": {
"message": "(#200) This app is not allowed to publish to other users' timelines.",
"type": "OAuthException",
"code": 200
}

Timeline

Mar 1, 2015 2:47pm – Report Sent
Mar 2, 2015 2:45pm – Escalation to Facebook
Mar 4, 2015 2:26pm – Confirmation of fix
Mar 4, 2015 7:42pm – Bounty Awarded of $1250 by Facebook

This is a proof of logic rather than a simple permissions check. It works off a thought pattern such that there are permissions that according to the documentation should depend on each other but are not being enforced in the API.

According to https://developers.facebook.com/docs/graph-api/reference/v2.2/conversation/messages, a conversation-id can be read as long as read_page_mailboxes is supplied. Further along it states that to reply to a message

A page access token for the page is required

It’s safe to assume that one will need read_page_mailboxes to get the conversation-id first and then post using conversation-id/messages.

So to me the above should actually read

A page access token for the page is required (with read_page_mailboxes granted to the user session to see the conversation-id)

While this is how it works, the prerequisite isn’t checked again when posting to conversation-id/messages.

The impact here is that an app that has had read_page_mailboxes revoked from a user session can still post to the conversation-id/messages edge given the app stored the conversation-id ahead of revoke.

This was patched such that the following error is now returned

{
"error": {
"message": "(#279) Requires extended permission: read_page_mailboxes",
"type": "OAuthException",
"code": 279
}
}

Timeline

Feb 26, 2015 7:21pm – Report Sent
Feb 27, 2015 5:42pm – Escalation to Facebook
Mar 13, 2015 3:14pm – Patched and Bounty Awarded of $750 by Facebook

Using the proper combination of permission scope we can bypass allowing a normal app to edit a post it doesn’t own (when it shouldn’t have that ability)

For apps that aren’t Facebook native applications, it isn’t possible to delete an object that the app hasn’t created. This is good as it provides proper control over what an application can do in case of rogue behaviour.

There isn’t however an indication as to an application editing an object, specifically a status update that it did not create. According to https://developers.facebook.com/docs/graph-api/reference/v2.2/status and https://developers.facebook.com/docs/graph-api/reference/v2.2/post

You can’t update a status/post using the Graph API.

The original response from Facebook

Thank you for your report.

I was able to edit one of my statuses as per your reproduction steps, and I have passed this on to the appropriate team, however, please be aware this may be a documentation issue, in which case, it likely will not be eligible for a reward since no code changes would be required for the fix.

So far, going good, however a day later.

That appears to be a documentation bug, not a privacy or security risk. I’ll pass this along to the team so they can document the behavior properly. :-)

At this point the report has been closed and I investigate other endpoints. Normally, I believe unless you are 100% sure of the implications of the bug, it’s unnecessary to contest the decision of the security team. About a month later I was reading the new documentation for Facebook API and noticed there was a change at https://developers.facebook.com/docs/graph-api/reference/v2.3/status#updating from

You can’t update a status/post using the Graph API.

to

An app can update a status if it published it.

So now I’m able to revisit the closed old report to re-validate the bug.

This is now fixed and returns

{
"error": {
"message": "(#200) App cannot edit non-app posts",
"type": "OAuthException",
"code": 200
}
}

Timeline

Feb 25, 2015 2:20pm – Report Sent
Feb 26, 2015 5:09pm – Escalation and notice of possible non-security issue by Facebook
Feb 27, 2015 2:22am – Closed as a documentation bug, not a privacy or security risk
Apr 2, 2015 2:30pm – Bug re-opened with details from new documentation
Apr 2, 2015 6:52pm – Confirmation and fix in progress by Facebook
Apr 10, 2015 8:40am – Bounty Awarded of $2000 by Facebook

Using the most basic permissions, public_profile, it is possible to change the description/name

Any editable field (https://developers.facebook.com/docs/graph-api/reference/v2.2/video) of any of the session user’s videos. This is undocumented, though it seems, that a permission requirement should be applied to modify the video object.

Proof of Concept

Execute a HTTP POST call

curl -F 'name=My Potato Video' \
-F 'access_token=ACCESS_TOKEN' \

https://graph.facebook.com/video_id

The result is that video name has been changed from “Hot Video” to “My Potato Video”

This was patched and now asks for the publish_action permission.

Timeline

Feb 25, 2015 6:59am – Report Sent
Feb 25, 2015 6:24pm – Escalation by Facebook
Mar 20, 2015 10:47am – Patched and Bounty Awarded of $3000 by Facebook

There seems to be more information being displayed than necessary in errors from GraphQL leading to presentation of a full path of a directory or a file via the BLAME_files and BLAME_dirs feature.

Description

While the files and directories to blame will be of great use to any Facebook employee working on GraphQL (e.g. Jing Chen) I don’t see the need for an ordinary user to be able to see this information.

Normally in other areas I’ve looked at this information isn’t disclosed, and just the error message (less the BLAME_) is shown.

So before I end up on CluelessSec…

I’ve sat on this for a few months trying to see how I can escalate this or combine it with another bug and so far I’ve just been able to guess and use pre-existing information such as http://sintheticlabs.com/blog/a-look-inside-facebooks-source-code.html. Nevertheless as more information is released from GraphQL such as the spec Jing Chen mentioned in her React.JS talk, the easier it will be for me in the future to reach something more substantial by gathering more files names and directory structures until I can make better educated guesses to internal features.

Proof of Concept

Execute a mutation on a GraphQL call, this was also mentioned briefly at the 23min mark in the React.JS talk http://youtu.be/9sc8Pyc51uU?t=23m19s.

The call is changed in such a manner that will bring about an error. Once the error is raised, one can inspect the description to see which files or directories were assigned blame.

These all had starting paths as www/flib/ Some were already known in http://sintheticlabs.com/blog/a-look-inside-facebooks-source-code.html others were not.

I appreciate Facebook offering a Bounty for this and @JosipFranjkovic for pushing me to submit this.

Timeline

Feb 9, 2015 5:05pm – Report Sent
Feb 10, 2015 11:07am – Escalation to Facebook
Mar 3, 2015 10:12am – Confirmation of fix
Mar 3, 2015 11:39am – Bounty Awarded of $750 by Facebook