dwr框架代码审计
简述
在做测试的过程中发现一个老系统提交的请求包比较奇怪,通过检索,发现是早期java web研发人员常用的DWR框架,dwr框架比较古老,可以帮助用户实现Ajax网站,可以让你在浏览器中的Javascript代码调用Web服务器上的Java,就像在Java代码就在浏览器中一样。
DWR 主要包括两部分:
- 在服务器上运行的 Servlet 来处理请求并把结果返回浏览器。
- 运行在浏览器上的 Javascript,可以发送请求,并动态改变页面。
DWR 会根据你的 Java 类动态的生成Javascript代码。这些代码让你感觉整个Ajax调用都是在浏览器上发生的,但事实上是服务器执行了这些代码,DWR负责数据的传递和转换。DWR有些过时了,目前可以直接使用jquery来实现ajax请求。
DWR框架介绍
使用maven或者直接从官网获取jar包,将jar包放入WEB-INF的lib文件夹下。同时,dwr依赖于commons-logging.jar
web.xml配置文件如下:
1 2 3 4 5 6 7 8 9 10 11 12 13
| <servlet> <servlet-name>dwr-invoker</servlet-name> <servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class> <init-param> <param-name>debug</param-name> <param-value>true</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>dwr-invoker</servlet-name> <url-pattern>/dwr/*</url-pattern> </servlet-mapping>
|
dwr配置如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 3.0//EN" "http://getahead.org/dwr/dwr30.dtd">
<dwr> <allow> <create creator="new" javascript="JDate"> <param name="class" value="java.util.Date"/> </create> <create creator="new" javascript="Demo"> <param name="class" value="your.java.Bean"/> </create> </allow> </dwr>
|
dwr.xml 是 dwr 的核心配置文件,主要的标签有:<converter>、<convert>、<create>这三个标签。<create> 标签是 dwr 中重要的标签,用来描述 java(服务器端) 与 javascript (客户端)的交互方式。其基本格式如下:
1 2 3 4 5 6 7 8 9
| <allow> <create creator="..." javascript="..." scope="..."> <param name="..." value="..."/> <auth method="..." role="..."/> <exclude method="..."/> <include method="..."/> </create> ... </allow>
|
其中,creator 和 javascript 是必须属性,其他可以忽略。creator 包含有以下几个值:
- new:Java用“new”关键字创造对象
- none:它不创建对象 (v1.1+)
- scripted:通过BSF使用脚本语言创建对象,例如BeanShell或Groovy
- spring:通过Spring框架访问Bean
- struts:使用Struts的FormBean (v1.1+)
- jsf:使用JSF的Bean (v1.1+)
- pageflow:访问Weblogic或Beehive的PageFlow (v1.1+)
- ejb3:使用EJB3 session bean (v2.0+)
这里初学,实用java new创建对象。
页面配置
页面需要引入3个JS
1 2 3
| <script src="<%=ctxPath%>/dwr/interface/Chat.js" type="text/javascript"></script> <script src="<%=ctxPath%>/dwr/engine.js" type="text/javascript"></script> <script src="<%=ctxPath%>/dwr/util.js" type="text/javascript"></script>
|
其中 engine.js 必须要,如果需要用到dwr提供的一些方便的工具要引用util.js ,然后是dwr自动生成的js文件。名字和 dwr.xml 中 create 标签的 javascript 属性值一样,且必须是 dwr/interface 开头的目录,详细请查阅官方文档,这里不过多说明。
审计
DWR框架对于审计人员比较友好,通过分析web.xml和dwr配置文件,我们可以迅速定位到源代码的位置。
首先分析web.xml
获取dwr配置文件目录
这里查找scriptName为:CaUsermanAjax,方法名为:getTysfyhbList的具体实现的代码。
本次审计的dwr框架配置文件使用spring模式,使用spring框架访问bean,并且使用dwr-signatures的配置模式,signatures段使DWR能确定集合中存放的数据类型。
signatures段允许我们暗示DWR应该用什么类型去处理。格式对以了解JDK5的泛型的人来说很容易理解。
1 2 3 4 5 6 7 8 9 10
| <signatures> <![CDATA[ import java.util.Map; import com.zfsoft.cacommon.username.ajax.UsermanAjax; CaUsermanAjax.getYrdgxxbList(Map<String,String> condition); CaUsermanAjax.getTysfyhbList(Map<String,String> condition); CaUsermanAjax.getOnlineUserList(Map<String,String> condition); CaUsermanAjax.getZhmmxxbList(Map<String,String> condition); ]]> </signatures>
|
标签是用来声明java方法中List、Set或者Map参数所包含的确切类,以便java代码作出判断。
通过查找com.zfsoft.cacommon.username.ajax.UsermanAjax对象,我们找到getTysfyhbList方法。
通过对比捕获的数据包我们可以了解到数据包的格式
请求地址为:
1
| http://ipaddress/dwr/call/plaincall/{{ scriptName }}.{{ methodName }}.dwr
|
http body:
1 2 3 4 5 6 7 8 9 10 11 12 13
| callCount=1 page={{ 任意JSP地址均可 }} httpSessionId= {{ 可留空 }} scriptSessionId={{Cookie中的 DWRSESSION}} c0-scriptName={{ scriptName }} c0-methodName={{ methodName }} c0-id=0 c0-e1=number:0 设置参数 c0-e2=number:15 c0-e3=string: c0-param0=string(类型): 值 {{ 参数 1}} 也可以写成:c0-param0=Object_Object:{start:reference:c0-e1,...}start是参数名,后面是参数值的来源。 batchId=0
|
回过头,我们分析本次审计的源代码,其中TysfyhbDAO对象中的list方法会返回用户的数据信息,未经过处理,直接返回数据库中存储的用户敏感信息。在请求调用的整个过程中,未发现有相关的权限校验,存在未授权访问的风险。
参考