snakeCTF logo

Boxbin


Description

šŸŽµ You're on Boxbin, you're on Boxbin... šŸŽµ Welcome to Boxbin, the totally-not-suspicious platform for sharing your hatred against any kind of box!

Solution

The challenge requires chaining two vulnerabilities to escalate privileges from a regular user to an administrator, thereby gaining access to a hidden post containing the flag. The solution can be divided into three main steps.

Step 1: Discovery and Broken Access Control

Upon initial analysis, it is determined that the application's backend is powered by a GraphQL API located at /api/graphql. Introspection is enabled on this endpoint, which allows the entire API schema to be queried.

By performing an introspection query, a mutation named adminUserUpgrade(upgradeId: ID!) is discovered. It is noted that this mutation is not used by the client-side application under normal circumstances. Further testing reveals that this mutation lacks any authorisation checks. It can be called by any authenticated user.

An account is created, and a login is performed to acquire a JWT authentication token. With this token, the adminUserUpgrade mutation is called. This action grants the user an "upgraded" status, which makes a previously hidden "Settings" page accessible on the user's profile.

Step 2: Server-Side Object Injection

The newly accessible Settings page is analysed. It is found that the "Save All Settings" functionality uses the updateSettings(settings: String!) mutation. The settings argument accepts a JSON string.

It is determined that the backend logic for this mutation is vulnerable to Server-Side Object Injection. The provided JSON string is parsed and its properties are recursively merged into a shared, global object on the server. No sanitization is performed on the keys.

The authorisation logic for administrative functions is found to be based on a check for isAdmin: true within this shared object. A payload can therefore be crafted to inject this property.

The required payload is:

{"isAdmin": true}

This payload is stringified and sent via the updateSettings mutation. The server merges this into the shared state object. As a result, the current user's session, and all subsequent sessions, are treated as having administrative privileges.

Step 3: Retrieving the Flag

With administrative privileges now active, the "Admin" link becomes visible in the site's header, leading to the /admin dashboard.

On the dashboard, a list of "Hidden Posts" is available. The post titled "The Box To End All Boxes" is selected. The content of this post contains the flag.