If you're a returning visitor to our CTF Recaps, feel free to dive straight into the insights! For first-time explorers, let us quickly introduce you to the essence of these recaps. Wizer CTFs were introduced to challenge developers, encouraging them to adopt a hacker's mindset and thereby code more securely. This initiative is a pivotal part of our new security awareness training, specially crafted for development teams - Wizer's Secure Code Training for Developers!
After a challenge retires, our Wizer Wizard and CTO, Itzik Spitzen, crafts takeaways that offer valuable insights into the challenge, focusing on the defensive perspective for your script. Curious to test-drive a CTF before delving into the notes? Visit wizer-ctf.com – it's free, and there's something for all skill levels!
In this challenge, we're identifying a Prototype Pollution vulnerability!
The code of the challenge showcases an API endpoint which creates new objects within a certain system. The endpoint expects an array of objects in a JSON format, and creates them one by one in a loop. In the code, there are 3 different types of objects: non-exclusive, approved-exclusive and an implicit type unapproved-exclusive. To create any exclusive object, the API call requires a secret passcode named `EXCLUSIVE_PASSCODE`.
In reviewing the code, we can notice that it is exposed to a Prototype Pollution vulnerability. The process of creating the objects, include a prototype based merge of objects: `object.assign()`. An attacker could use that to change the intended flow of the code.
An attacker could exploit the endpoint by using the `__proto__` property name in order to revise the default value of the property `type`. To achieve that, an object created with `{ "__proto__": { "type": "exclusive" }` for instance will `trick` the system into creating an unapproved-exclusive object. How is that possible? well, since the property `exclusive` of the provided object is undefined => false, the first `if` condition will be false, and the object will be pushed as `exclusive = true` and `approved = false` within the else part. The reason for `exclusive = true` is that the prototype of the object was overridden using the "__proto__" property, and now the default value of the property `exclusive` is set to `true` in the merged object. Now I leave the last part to you to figure out, as a simple exercise: how can we create an approved-exclusive object? Hint: no need for Prototype Pollution here :)
Prototype Pollution or Poisoning is definitely a dangerous vulnerability. In this case, the API endpoint allowed creating an unintended exclusive object and bypassing the intended logic of the procedure, which could result in getting access to sensitive data on the system or performing malicious changes to data. With that being said, depending on the poisoned object role in the logic of the code, it could result in a very wide range of outcomes, starting from getting access to sensitive data, causing denial of service or even gaining full control over a system.
Wanna join us on our next challenge? Sign up for our mailing list at wizer-ctf.com.