WIZER CTF #28: Object Creator
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!
Goal
In this challenge, we're identifying a Prototype Pollution vulnerability!
Description of code
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`.
What’s wrong with that approach?
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.
What would a successful Prototype Pollution attack look like in this case?
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 :)
So what?
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.
Main Takeaways:
- Never *EVER* trust objects coming directly from the user input:
When using JavaScript, which is exposed to the Prototype Pollution vulnerability, you should avoid using objects coming directly from the user input. An important form of user input sanitization when receiving an object from a user input, should be selectively copying only the relevant values into a fresh new object before using it on the system. This way, if anyone tries to alter an object prototype, the alteration won't be effective, since the object which is actually being used, selectively includes only valid key values. - Consider using deep cloning:
If you need to clone objects, consider using a deep cloning method that does not involve the prototype chain, such as using a library like lodash with _.cloneDeep() or a similar utility. - Avoid Object.assign() for Merging User Input:
Avoid using Object.assign() to merge user input with an object that is used in the application logic. This can lead to Prototype Pollution. If you must use Object.assign(), make sure that the object you are merging into is a new object that is not used elsewhere in the application.
Wanna join us on our next challenge? Sign up for our mailing list at wizer-ctf.com.
CODE WIZER!
Past Challenges
- From Owasp 10 To Advanced Techniques
- Deep-Dive 1 new topic monthly
-
Fun CTF Challenges to apply learning
Itzik Spitzen
Itzik is Wizer's CTO who brings his entrepreneurial spirit and C-level software strategy and technology innovations to the front. His experience in engineering leadership and process improving, technology strategy, product strategy and vision brings fresh insights and innovation to the Wizer platform. He is spear-heading a new initiative with Wizer CTFs challenging developers to learn the offensive in order to code more securely.