XSS WITH MATH CALCULATOR
This month Intigriti challenge was very hard and that’s not a news since it was developed by @huli. The website present itself as a math calculator where we can use trigonometric function and get the output however there are no numbers or mathematical operations such as multiplication,division,addition and subtraction
Let’s take a look at the code
<script>
(function(){
name = 'Pure Functional Math Calculator'
let next
Math.random = function () {
if (!this.seeds) {
this.seeds = [0.62536, 0.458483, 0.544523, 0.323421, 0.775465]
next = this.seeds[new Date().getTime() % this.seeds.length]
}
next = next * 1103515245 + 12345
return (next / 65536) % 32767
}
console.assert(Math.random() > 0)
const result = document.querySelector('.result')
const stack = document.querySelector('.stack-block')
let operators = []
document.querySelector('.pad').addEventListener('click', handleClick)
let qs = new URLSearchParams(window.location.search)
if (qs.get('q')) {
const ops = qs.get('q').split(',')
if (ops.length >= 100) {
alert('Max length of array is 99, got:' + ops.length)
return init()
}
for(let op of ops) {
if (!op.startsWith('Math.')) {
alert(`Operator should start with Math.: ${op}`)
return init()
}
if (!/^[a-zA-Z0-9.]+$/.test(op)) {
alert(`Invalid operator: ${op}`)
return init()
}
}
for(let op of ops) {
addOperator(op)
}
calculateResult()
} else {
init()
}
function init() {
addOperator('Math.random')
}
function addOperator(name) {
result.innerText = `${name}(${result.innerText})`
operators.push(name)
let div = document.createElement('div')
div.textContent = `${operators.length}. ${name}`
stack.prepend(div)
}
function calculateResult() {
result.innerText = eval(result.innerText)
}
function handleClick(e) {
let className = e.target.className
let text = e.target.innerText
if (className === 'btn-fn') {
addOperator(`Math.${text}`)
} else if (className === 'btn-ac') {
result.innerText = 'Math.random()';
stack.innerHTML = '<div>1. Math.random</div>'
operators = ['Math.random']
} else if (className === 'btn-share'){
alert('Please copy the URL!')
location.search = '?q=' + operators.join(',')
} else if (className === 'btn-equal') {
calculateResult()
}
}
})()
</script>
Here’s a breakdown of this code that creates a simple calculator-like interface for performing calculations using various mathematical operators from the Math
object. It allows users to build a sequence of mathematical operations and calculate the result.
(function(){ ... })()
: This is an immediately-invoked function expression (IIFE) that encapsulates the entire script. It ensures that the code within it is executed immediately after the script is loaded, providing a private scope for variables.name = 'Pure Functional Math Calculator'
: This line assigns a string value to the global variable name
, which seems to define the name of the calculator.let next
: This declares a variable next
using the let
keyword, which will be used to generate pseudo-random numbers.Math.random = function () { ... }
: This code snippet overrides the Math.random
function to provide custom random numbers. It uses a linear congruential generator (LCG) algorithm to generate pseudo-random numbers based on a sequence of seed values. If no seeds are defined, it initialises them and generates subsequent random numbers using the LCG algorithm.console.assert(Math.random() > 0)
: This line uses console.assert
to ensure that the custom Math.random
function generates numbers greater than 0.const result = document.querySelector('.result')
: This line selects an HTML element with the class name .result
and assigns it to the result
constant. This element will display the result of calculations.const stack = document.querySelector('.stack-block')
: This line selects an HTML element with the class name .stack-block
and assigns it to the stack
constant. This element will display the stack of operators used in the calculations.let operators = []
: This initializes an empty array called operators
that will store the sequence of mathematical operators.document.querySelector('.pad').addEventListener('click', handleClick)
: This line adds a click event listener to an element with the class name .pad
. When clicked, the handleClick
function will be executed.let qs = new URLSearchParams(window.location.search)
: This creates a new URLSearchParams
object to parse the query parameters in the URL.if (qs.get('q')) { ... } else { ... }
: This block checks if there's a query parameter named 'q'
in the URL. If it exists, the code parses the query parameter to extract a sequence of operators and performs various checks on them. If the query parameter doesn't exist, the init
function is called.function init() { ... }
: This function initializes the calculator by adding the initial operator 'Math.random'
.function addOperator(name) { ... }
: This function adds an operator to the sequence of operators, updates the display, and updates the stack of operators.function calculateResult() { ... }
: This function evaluates the sequence of operators that is passed to the url q parameter using the eval
function and updates the result display.