Everything you need to know about Prototype Pollution

Table of Contents

  1. Intro
  2. What you need to verify a Prototype Pollution.
  3. What is susceptible to Prototype Pollution manipulation?
  4. Property definition by path/location
  5. Simple Example Prototype Pollution payloads
  6. Polluting the DOM

Intro

Prototype Pollution is a vulnerability that allows attackers to exploit the rules of the JavaScript programming language, by injecting properties into existing JavaScript language construct prototypes, such as Objects to compromise applications in various ways.

JavaScript allows all Object attributes to be altered. This includes their magical attributes such as __proto__, constructor and prototype.

An attacker is able to manipulate these attributes to overwrite, or pollute a JavaScript application object prototype of the base object, by injecting other values.

Properties on the Object.prototype are then inherited by all the JavaScript objects through the prototype chain, resulting in either:

  • Denial of Service – by triggering JavaScript exceptions
  • Remote Code Execution – by tampering with the application source code to force the code path that the attacker injects
  • XSS – see examples below

Why is Prototype Pollution an issue?

In Javascript, prototypes define an object’s structure and properties, so that the application knows how to deal with the data. When new objects are created, they carry over the properties and methods of the prototype “object”. If you modify the prototype in one place, it will affect how the objects work throughout an entire application.

What you need to verify a Prototype Pollution

If you have a Firefox or Chrome browser installed, you should be good to go! In this blog, I will be using Firefox.

Simply open the Firefox Developer Tools from the menu by selecting Tools -> Web Developer -> Toggle Tools or use the keyboard shortcut  Ctrl + Shift + I or F12 on Windows and Linux, or Cmd + Opt + I on macOS.

What is susceptible to Prototype Pollution manipulation?

The impact and severity of Prototype Pollution depends on the application. Property definition by path/location is a key example.

Property definition by path/location

There are numerous JavaScript libraries which are vulnerable to Prototype Pollution due to document.location. Finding out which are vulnerable is easy. GitHub user BlackFan maintains a list of libraries that are vulnerable to Prototype Pollution due to document.location. You can find this list here. An example of a high severity prototype pollution security vulnerability was discovered in the lodash library (versions less than 4.17.15).

Let’s dissect the JavaScript objects to better understand what is happening. 

First, we will create an object and access its attributes.

For example, if we create object Book as:
var book = {bookName: "Book name", authorName: "Author of book"};

We can access the name and the author using two different notations, the dot notation (e.g.: book.name), and the square bracket notation (e.g.: book[“name”]).

book.bookName  //output: “Book name”
book["bookName"]//output: “Book name”
var name = "bookName";
Book[name]//output: “Book name”


book.authorName//output: “Author of book”
book["authorName"]//output: “Author of book”
var author = "authorName";
book[author]//output: “Author of book”

The object Object has a few properties for its prototype. We are interested in constructor and__proto__.

You can see all available properties of the Object by typing Object.prototype. in the console of a web browser by opening developer tools.

Now that you know how to access these attributes and list them, how can you use this to add something and pollute the Object?

Let’s create an object book and try to access some non-existent values?
var book = {bookName: "Book name", authorName: "Author of book"};
book.constructor.protoSomeRandomName // this will not work, since there is no attribute protoSomeRandomName

but what if we do this
Object.__proto__["protoSomeRandomName"]="protoSomeRandomValue"
book.constructor.protoSomeRandomName // this will work and return value protoSomeRandomValue (is it magic? not really)

We proved this indeed polluted all the objects created from the object Object with the new attribute, and all of these new objects have inherited this attribute from the prototype.

Simple Example Prototype Pollution payloads

Object.__proto__["protoSomeRandomName"]="protoSomeRandomValue"
Object.__proto__.protoSomeRandomName="protoSomeRandomValue"
Object.constructor.prototype.protoSomeRandomName="protoSomeRandomValue"
Object.constructor["prototype"]["protoSomeRandomName"]="protoSomeRandomValue"

Polluting the DOM

Examples for vulnerable document.location parsers

Credits go to: s1r1us

https://msrkp.github.io/pp/1.html?__proto__[protoSomeRandomName]=protoSomeRandomValue

https://msrkp.github.io/pp/2.html?__proto__[protoSomeRandomName]=protoSomeRandomValue

https://msrkp.github.io/pp/3.html?__proto__[protoSomeRandomName]=protoSomeRandomValue

XSS examples

XSS example #1 https://msrkp.github.io
XSS example #2 https://msrkp.github.io

How to popup an alert by altering __proto__?

var book = {bookName: "Book name", authorName: "Author of book"};
console.log(book.toString())
//output: “[object Object]”

book.__proto__.toString = ()=>{alert("polluted")}
console.log(book.toString())
// alert box pops up: “polluted”

Remediating this vulnerability:

This vulnerability can be fixed by:

  1. Freezing the prototype
    1. Object.freeze(Object.prototype);
    2. Object.freeze(Object);
  1. Schema validation of JSON input
  2. Avoid using unsafe recursive merge functions
  3. Using Map instead of Object
  4. Use Prototypeless Object

var obj = Object.create(null);
obj.__proto__ //output undefined
obj.constructor //output undefined

Bright enables developers and security teams to automatically detect Prototype Pollution vulnerabilities, seamlessly integrated across your pipelines, with no-false positives and built with a Dev first approach.

Request a demo now or give it a try today with a FREE account!

What is Business Constraint Bypass

Table of Contents

  1. Intro
  2. Importance.
  3. Attack
  4. Remediation
  5. Bright and Business Constraint Bypass

While security professionals pay significant attention to technical vulnerabilities such as SQL Injection, CSRF and Cross-Site Scripting, modern applications are just as susceptible to business logic flaws.  Business logic flaws defy easy categorization and the skill of discovering them can be more art than science.

In this post, we will discuss business constraint bypass vulnerabilities (a unique case of business logic vulnerability) and give AppSec people & pen testers a few tips on how to test for this type of vulnerability.

Intro

Business Constraint Bypass can seem simple and harmless at first but can lead to a series of serious problems.  Impacts can vary from getting data the user should not have access to, to application-based DoS attacks. 

Importance

Why is this specific attack important, and how can it impact your business?

Let’s take for example a website that will provide information on the best software for Application Security Testing. The free version of the application returns only the top three results, and if you want to see the whole list, you have to pay. Or maybe you want to see the top ten visited websites from a certain category. With the free version you can make only three requests, and if you need more than those three requests, you have to pay.

Business constraint bypass attacks exist because of applications like these. It will try to bypass the constraint and get as much data as possible for free.

Even if data is not accessed unlawfully, this attack might cause a small application based DoS attack, or if the attacker is able to distribute the request, a full-blown DDoS.

Attack

Recon

What I like to do first is to find a parameter that might be modifiable to return more data than necessary. This is done usually while going through the application and looking at all of its possibilities. If I see a page that only shows something like 10 results of a certain data and the only way to get more is to click  “Next page” I flag that as a possible candidate for constraint bypass attack.

Once I have my candidate I check what requests take place while that page is being loaded. What usually happens in modern applications is that an API request is called for n values of that data.

The next step is trying to cURL that API call and if that works, we’re all set to start attacking.

Exploitation

Let’s say we have this API call that we want to attack /api/v1/get_books/10/site/all_books. This call gets 10 books on page “All books”.

What we want to attack is the integer value of 10 and we want more books. How do we do that? I usually follow these steps when generating this attack:

First, you would execute the API call to see if you can get the JSON/YAML of the items you want (in our case its books). This can be done easily by executing the request in the browser itself in a new tab or if you’re feeling like a hacker you can use cURL.

Once we confirm that we can return the data we want we can continue to the next step, increasing the number of items.

This is really simple, we just change the number 10 in the call with a 100, and if it returns 100 items (books) we’ve succeeded in an attack.

The next step is trying to see if we can get a 1000 or even more items.

What if we have a call that’s almost the same as the previous one but it has one more parameter in it. Like this: 

/api/v1/get_books/10/site/all_books?hash=abcd-12fa-be34-c45d. What does this change for us? This specific hash probably refers to some type of session that the application is using so you wouldn’t abuse the same API call and it’s valid for a short timeframe.

What I usually do in this case is prepare an API call that I want to call but not execute it (so something like this /api/v1/get_books/100/site/all_books?hash= and then record a regular API request but take the hash from it and plug it into our own call with a modified number of items.

This will usually do the trick in scenarios like these.

Another thing I’ve seen is duplicated parameters, so an API call ends up looking something like this:

/api/v1/?books=10&page=all_books&hash=some-weird-short-hash&books=10&page=all_books&hash=some-weird-short-hash

As you can see every parameter is being duplicated and if they obfuscate the names to something weird or shorten them you might end up seeing something like the following: /api/v1/?b=10&p=all_books&h=weird-hash&b=10&p=all_books&h=weird-has

There are a couple of ways to proceed in such cases. , First, we need to analyze the situation to figure out which parameter we’re actually attacking.

  • If we execute this and get 10 items, it’s pretty obvious we’re attacking the parameter b.
  • If there are multiple different parameters with different names but the same values we would need to manually check all of them to see which ones are actually the ones that are required by us.
  • Once we know which parameters we’re attacking (in our case b) we can proceed to modify it.

One way to modify is to change both values and see if it gets you the number of items you want, so the API call might end up looking something like this: /api/v1/?b=2448&p=all_books&h=weird-hash&b=2448&p=all_books&h=weird-hash

And if this works, great, we have a way of getting more items, if it doesn’t work it means there is some weird check in the background.

Another way to do this is to remove the duplicated parameters and see if the API call still works, this can get a bit complicated since you might need to remove some specific double parameters but leave others, so you would need to play around with the call itself.

Additional tips

If you want to get the maximum number of items allowed it’s probably best to use something like a modified binary search (O(log n)). Since we don’t know the max value we can return we can do something like this:

  • If a regular call is for 10 items, and we know that we can get a hundred, for example, we need to increase it a lot more. Go for something a bit more absurd like 10.000 items
  • If 10.000 items work you would increase this even further but it will be a bit harder to both verify the amount of data and your browser might act a bit weird with a large JSON so be careful about those things.
  • Let’s say 10.000 doesn’t work but we know that 100 does. The next step is as a binary search goes to check the half point of those two.
  • We make a request for 5.000 items. And depending on if this works or not we have two possible paths.
    • First is if it works, we take another half-point between 5.000 and 10.000, which is 7.500 items. And repeat the previous step.
    • Second is if it doesn’t work, we take a half-point between 5.000 and a 100, and that would be 2.500 items. And repeat the previous step.
  • We do this until we get to the number of items we want and we know work

If you can’t get the API request to work, and it looks something like this /api/v1/books/10/page/all_books. The issue could be in the additional parameter that we’re not actually using, page.

What we can do is try removing it and see if that works, our API call ends up with something like /api/v1/books/10.

This can be applied to any parameter that isn’t the one we’re attacking, try removing it and see how the API responds. This is a lot of trial and error until you get it to work but it can make your life a lot easier.

Remediation

Always check the amount of data being requested via an API call. Just because the API is made to be invisible to the user, doesn’t mean it’s actually invisible to everyone.

If you need the API to be dynamic, make sure to either limit it by user or use-case, including the session in the request itself.

Never trust that an API call that’s available from the internet won’t be used or abused by anyone other than your application.

Bright and Business Constraint Bypass

Business Logic Attacks represent a major issue in modern applications.

While a vulnerability like Business Constraint Bypass is easy to find, most automated AST tools are not able to detect it.

Bright is the only DAST solution capable of detecting Business Logic Constraint vulnerabilities in applications and APIs. Simply initiate a scan (using GUI or CLI) and among other vulnerabilities, Bright will also test for business constraint bypass. The resulting report comes completely false-positive free, with remediation guidelines for you and your team. Integrate Bright with Jira, Slack, or any other issue tracking tool and assign any finding as a ticket to your colleagues.

To see these and many other features of Bright in action, request a demo – https://brightsec.com/request-a-demo

The Ultimate Beginners Guide to XSS Vulnerability

Table of Contents

  1. Intro
  2. Importance of XSS vulnerabilities.
  3. Some known XSS attacks in the wild
  4. Types of XSS
  5. Attacks
  6. Prevention
  7. DOM XSS
  8. Summary

Intro

Cross-site scripting (XSS) is an old but always relevant and dangerous type of attack that plagues almost all web applications, be it older or modern ones. It relies on developers using javascript to enhance the experience of end-users of their application, but when the javascript isn’t properly handled it leads to many possible issues, and one of them is XSS.

Importance of XSS vulnerabilities

The risk of XSS is that the malicious code is usually injected directly into the vulnerable application and not a redirect site that the user might watch out for. So if you often go to example.com and someone sends you a link of one of their articles that goes something like example.com/this-article-is-good?id=%3Cscript%3Ealert%281%29%3C%2Fscript%3E you’ll probably click it because it’s something you’re really used to. What you’re not aware of is that there was some code injected in the site without your or the site’s approval and that code might steal your session, take some screenshots, activate a keylogger, etc…

An even more dangerous type of XSS vulnerability is the persistent one where you don’t even have to click on a link to execute the code, you just browse to some page on a site you trust and an attackers comment containing malicious code that was saved in the database is displayed on the site and suddenly you and everyone who visits that page is triggering something they really don’t want to trigger.

Some known XSS attacks in the wild

One of the most famous examples of XSS is the “Samy“. Samy is one of the fastest spreading malwares in internet history. It abused unsanitized profile posts to inject harmful javascript code that was saved to the database and then activated whenever a user viewed that post, thus spreading the worm to themselves and so on.

Yahoo account hijack via email phishing and XSS, attackers made a page with malicious javascript that would steal cookies of visitors. The attack was executed by sending an email with a link to the popular news page article, but the link linked back to the attacker’s site which contained malicious code.

Types of XSS

The three most common types of XSS are:

– Reflected
– Persistent
DOM-based XSS

You can read more about these types and how and why they work here.

Attacks

Let’s start with the basics

XSS is a really easy attack to start testing and seeing if you can execute malicious code. To get started, find some possible injection points in your targets and start with some simple basic payloads and see how the page reacts and then try to break it.

Finding possible injection points

The easiest way to find possible injection points is to see if reflection happens somewhere. A good example for this is usually the search bar where once you search for something you get the string you searched back at the top of the page. 

In the image above you can clearly see reflection happening and this is a prime spot to start testing for XSS.

Another good place to start injecting is a form in which text will be displayed to a large number of people. A good example of this is comments on a page, a review, post, or basically anything that will be seen by someone other than you.

Inspecting the elements and analyzing the reflection

Once you found a reflection point it’s a good idea to analyze it a bit and see how things are getting reflected, what do they pass through to get reflected back to you and how you can get over some of the common hurdles that developers put in to stop XSS attacks.

A good first step is to inject a bunch of random characters to see if some are blacklisted. this includes characters like < > / ; ! # $ and combinations of them to see if they are all reflected properly. Another good way to see for common blacklisting is doing some basic injections and seeing how they are reflected.

After playing around with the input field itself it’s good to check the frontend code to see if it’s sanitized somewhere. Then, check the javascript files that the input field goes through to see that.

Basic injections

Doing basic injections is a great way to see how the field is reflecting the input and what it’s doing with it behind the scenes.

First start with injecting the most basic alert: . What is reflected back to you, just the alert part, maybe you got a popup (if you did you found the goldmine, go ahead and break the whole site because there are probably a bunch more vectors possible), maybe it just filtered out special characters, maybe nothing got reflected, or in the worst case everything got reflected nicely back to you.

Depending on what got reflected back to you you can start crafting your payload.

Here are some examples on different simple injections and bypasses and how to work through them:

1. Basic injection works in the URL parameter id (broken_site/xss/1?id=)

2. Basic injection doesn’t work but we get some reflection (http://100.26.239.14:3000/vuln/xss/2?id=)

In this example we see that there is reflection but the script tags are filtered out, let’s play a bit with them to see how we can get them displayed.

Let’s see if capitalization breaks out of the blacklisting. Next payload is broken/site/xss/2?id=.

And it worked, the filtering used was just checking lowercase/uppercase characters and not mixed case.

3. Let’s try on another page, again we start with basic injection to scout it out broken_site/xss/3?id=

Again as in the previous example, let’s mix the case and see how that reacts broken/site/xss/3?id=

Pretty much the same as the previous try, nothing changed, looks like it sanitizes the input to only one case and then checks it.

Let’s try wrapping it to see if it does just one check or multiple checks. Payload is broken_site/xss/3?id=ript>alert(1)ript>

And this worked, the site just checks once if the payload contains the script tags and removes them, once it removes them we get another set of script tags that we wrapped around the removed ones and we get the successful alert prompt.

4. Page 4, again basic injection to see what’s going on broken_site/xss/4?id=

Here we get an interesting reflection, where some tags are still there but there is no script.

Let’s try wrapping it up to see what’s happening with the payload broken_site/xss/4?id=ript>alert(1)ript>

It looks like the page uses some sort of regex to filters the script out, let’s try something other than script.

Injecting a basic a tag and seeing how the site reacts to that. Payload is broken_site/xss/4?id=Click me!. What we do here is basically create a link that says click me, and when we hover the mouse over it, the alert box should execute.

We have the link on the site, let’s try hovering over it to see if we get the alert box.

And that worked because the whole focus of filtering was the script tag, the developers forgot about a tag and left that for the injections.

5. Another page, again we try the basic injection to see what’s going on with the site broken_site/xss/5?id=

Nothing gets reflected, let’s try wrapping it and seeing how it behaves then. Payload is broken_site/xss/5?id=ript>alert(1)ript>

We get some reflection, but it doesn’t really help us out.

Let’s try with the a tag and see how it behaves, we’re still not sure what’s being filtered here.

Payload is broken_site/xss/5?id=Click me!

We get the link but when we try to hover over it, it doesn’t actually execute anything. So it isn’t the script tag that is being filtered out but the alert is the culprit here. Let’s try converting it from ascii code to characters using some basic JS. Open up your developer tools by pressing F12 in your favorite browser and go to the Console tab. Type the following String.fromCharCode(97) and press Enter. You should get the character a displayed in your console. Now let’s craft up our alert box with this. Function is String.fromCharCode(97, 108, 101, 114, 116, 40, 49, 41) and let’s put that into eval so it executes. 

Payload is broken_site/xss/5?id=Click me!

And once we hover on it.

It worked.

Another thing that would’ve worked in this case if we injected prompt or confirm instead of alert.

This is the standard way of working through to figure out how to get the prompt to appear, iteratively trying things until something sticks and then modifying the thing that sticks the best to get the prompt. Another good thing to do is to inspect the element and see the code around it to see if you can get something out of that. It’s really useful for detecting DOM-XSS issues.

The site we used to test these injections is Broken Crystals, and you can also contribute to it to make it better.

Going crazy with the payloads

XSS Payloads can and do get really crazy real fast, and the AppSec community created some great payloads that you can just copy and paste to see if they work.

Some common bypasses are:

– Encodings

  – URL encoding

to %3Cscript%3Ealert%281%29%3C%2Fscript%3E

  – Base64 encoding

   to PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg==

  – Hexadecimal encoding without semicolon

to %3C%73%63%72%69%70%74%3E%61%6C%65%72%74%28%31%29%3C%2F%73%63%72%69%70%74%3E

  – Decimal HTML character

to

  – Decimal HTML character without semicolon

to <script>alert(1)</script>

  – Octal encoding

javascript:prompt(1) to javascript:'160162157155160164506151'

  – Unicode encoding %EF%BC%9E -> > and %EF%BC%9C -> <

to %EF%BC%9Cscript%EF%BC%9Ealert(1)%EF%BC%9C/script%EF%BC%9E

  - Using jsfuck

- Embedding encoded characters that don't break the script (tab, newline, carriage return)

  - Embedding tab

to alert(1)

  - Embedding newline

to alert(1)

  - Embedding carriage return

to alert(1)

  - Null breaks

  to alert(1);

  Null breaks should be done either through a proxy or by embedding the %00 in the URL query, otherwise they won't work properly.

- Character bypasses:

  - To bypass quotes for string use String.fromCharCode() function

  - To bypass quotes in mousedown event Link

  - To bypass space filter use one of /, 0x0c/^L like:

Click me! to Click me!

Click me! to Click me!

  - To bypass parenthesis for string using `

to

  - To bypass closing tags > use nothing, they don't need to be closed

- Bypassing on...= filter

  - Using null byte

Click me! to Click me!

  - Using vertical tab

Click me! to Click me!

  - Using a /

Click me! to Click me!

- Escaping JS escapes

You're already working in script tags but you need to escape the quotes to inject your own code:

  ";alert(1);//

  or close the script tag and open up your own immediately after:

  

Polyglots

Polyglots are used to save time when testing for XSS. They usually cover a large variety of injection contexts. They aren't the end all be all for XSS but they do speed up the process quite a bit. If the polyglot works, you save a lot of time, if it doesn't you either move on or continue with a lot more specific attack on that input. It all depends on your goal, if it is to test a lot of parameters, polyglots are great, if it is to break a single parameter, you will probably need to dig deep into how that specific part of the application works.

Here is a great polyglot by 0xSobky 

jaVasCript:/*-/*`/*`/*'/*"/**/(/* */oNcliCk=alert() )//%0D%0A%0d%0a//x3csVg/x3e

It covers a large amount of injection contexts and is overall great polyglot to test everything with.

Another great polyglot by s0md3v

-->'"/>. Now anyone that visits our profile gets popup.

DOM XSS Example

In juice-shop in "Search" field type