Sitemap

$175 Prototype Pollution Vulnerability – Public program

1day
5 min readOct 2, 2024

INTRODUCTION

Hey everyone, I’m excited to be back with another write-up! I’m a 19-year-old BCA student with a passion for bug hunting and cybersecurity. In this post, I’ll walk you through how I uncovered a prototype pollution vulnerability, leading to a $175 bounty. Let’s dive in!

THE DISCOVERY

I’ve been hunting bugs for like 2 years, I usually target VDPs because they are easy to be hacked and I can learn more from it. From the last 6–7 months I was onto Bug bounty programs because I was a little bit confident on my skill after working on VDPs.

This is a Public program on Bugcrowd but I cannot disclose the name of the target, I’ll call it redacted.com. redacted.com is a web3 blockchain game platform where you can play-and-earn a crypto (I cannot reveal its name). You can use the crypto to purchase in-game currency called CRYSTALS. You can use the crystals to purchase different characters, Mystery boxes and more.

After hours of clicking I found a Redeem code functionality.

So first I tried entering random codes and it showed me the code does not exist. It reflected the code we enter in the response.

When I entered a redeem code and submit, I got the following request captured in Burpsuite :

Failed redeem code request with a random code

The backend server is using node-js as it was specified in the program description.

I enjoy working with JSON input and output areas because they are often vulnerable to various injection attacks.

Now on to the attack…

PROTOTYPE POLLUTION

Prototype pollution is a type of vulnerability that occurs in JavaScript when an attacker is able to manipulate or modify the prototype of built-in objects like Object, Array, etc. JavaScript uses prototypes to share properties and methods among objects, and by altering a prototype, the attacker can potentially inject malicious properties into every object that inherits from that prototype.

Suppose there’s an isAdmin flag used to control access to administrative features. If the prototype of an object can be polluted, an attacker might be able to inject an isAdmin: true property, giving themselves unauthorized access.

app.post('/auth', (req, res) => {
let user = {};
Object.assign(user, req.body); // Merging user-controlled data without sanitization
if (user.isAdmin) {
return res.send('Welcome Admin!');
} else {
return res.send('Invalid');
}
});

This backend code shows a vulnerable endpoint called “auth” which takes, a JSON input. If we enter any JSON input it will be Merged to the user object without any validation. So the following payload will exploit it:

{"__proto__": {"isAdmin": true}}

This JSON input will change the isAdmin prototype of the user object to true, allowing unauthorized access.

This was a quick intro into prototype pollution, Now let’s get into the target scenario.

EXPLOITATION

So here, When we enter a code and submit, It is sent to the server in the JSON format like:

{"code":"testcode123"}

In the backend, the check might look like this (JUST MY ASSUMPTION):

app.post('/redeem', (req, res) => {
let redemptionRequest = {};
Object.assign(redemptionRequest, req.body); // Merging request body into redemptionRequest object

let redeemableItem = database.find(item => item.code === redemptionRequest.code);

if (redeemableItem) {
if (!redeemableItem.redeemed) {
// Mark the item as redeemed
redeemableItem.redeemed = true;
userAccount.addItem(redeemableItem.item, redeemableItem.item_count);

// Respond with success
return res.json({
id: redeemableItem.id,
created_at: redeemableItem.created_at,
updated_at: new Date().toISOString(),
code: redeemableItem.code,
item: redeemableItem.item,
item_count: redeemableItem.item_count
});
} else {
return res.status(400).send('Code already redeemed');
}
} else {
return res.status(400).send('Invalid code');
}
});

The pollution of the prototype may caused the backend to incorrectly match the redeemable code or skip some validation logic.

When I send the payload {"code":{"__proto__":{"foo":"bar"}}}, the code field in redemptionRequest may caused unexpected behavior due to the altered prototype. The server might bypass certain checks because the polluted prototype chain might interfere with redemptionRequest.code during the comparison (item.code === redemptionRequest.code), leading to the redemption of a valid item that wasn't intended for this specific code.

  • THIS IS JUST MY ASSUMPTION OF THE BACKEND LOGIC, I’M STILL NOT 100% SURE HOW THIS WOULD’VE HAPPENED.

Now when I sent that request, I got a valid response as follows:

Successfully redeemed a code using prototype pollution

This added 1500 CRYSTALS to my wallet without actually redeeming a valid code.

1500 CRYSTALS in my wallet

This attack was only possible once per account, because if we try to inject it again, It will say “Code [Object object]” has already been redeemed”.

So I created another account for learning what all rewards I can claim using this vulnerability, and it turns out that I was able to claim a free pass to a paid game.

REPORTING

I quickly reported this vulnerability on the Bugcrowd and it was considered as a P4 vulnerability as the attacker cannot control what reward can be redeemed.

Reported on : 13-Sep-2024

Triaged on : 24-Sep-2024

Bounty rewarded on : 24-Sep-2024

CONCLUSION

I was actually very scared to approach this target as this was a public program on Bugcrowd and it was a Web3 based target. But I didn’t gave up on my intuition and proceeded to hack it.

Thanks for reading my writeup, Please clap & support my writings, More coming soon….

--

--

1day
1day

Responses (6)