0x01

前段时间,在对某站群系统进行代码审计时,发现某处DWR-AJAX接口存在文件上传漏洞

代码层:

public String upload(InputStream is, String fileName) {
    String fileUploadPath = getFileUploadPath();
    String file = String.valueOf(fileUploadPath) + "/" + IDCreator.getRandom() + "/" + fileName;
    String fileExtName = FilenameUtils.getExtension(fileName);
    File f = new File(file);
    Properties pro = new Properties();
    try {
      long size = is.available();
      FileUtils.copyInputStreamToFile(is, f);
      pro.put("extName", fileExtName);
      pro.put("originName", fileName);
      pro.put("url", file);
      pro.put("size", Long.valueOf(size));
    } catch (IOException e) {
      e.printStackTrace();
      log.error("+ e);
      return WebTools.getCallBackJSON(0, ");
    } 
    return WebTools.getCallBackJSON(1, JSON.toJSONString(pro));
  }

可以清楚的看到这里是一处文件上传漏洞,在进行存储的过程中,未进行任何文件类型效验操作。

由于是dwr框架,可以通过dwr.xml 查看映射关系

注:

在没有源码的情况下,可以访问dwr框架的DEBUG页面

默认路径:

http://localhost/dwr/index.html

有点类似于.NET平台下的ASMX接口文件,且里面提供了测试方法。

0x02

DWR框架所创建的ajax请求与常见的POST请求有所不同

DWR框架请求格式:

page 为来访页面

scriptSessionId 一般为自动生成或对应Cookie中的DWRSESSIONID

c0-scriptName  调用脚本名 对应 dwr.xml 中的 javascript

如: scriptName = javascript = ExtAjax

其中param为调用自定义的类

methodName 为类中的方法名


c0-param0为参数,如方法接收3个参数,那么就是0到2

如:c0-param0 ,c0-param1,c0-param2 按顺序传递

0x03

由于目标系统是文件上传,需要输入流InputStream,那么格式应该还会有所不同,所以这里我按照网上的相关方法,在本地搭建了一个环境

参考文章:https://my.oschina.net/u/1474779/blog/610668

所需jar包: (要实现文件上传必须引入commons-fileupload包)

commons-logging-1.1.1.jar

dwr.jar

commons-fileupload-1.3.1.jar

commons-io-2.4.jar

Upload.Java

package com.ajax;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.directwebremoting.WebContext;
import org.directwebremoting.WebContextFactory;


public class Upload {

    public String upload(InputStream is, String fileName) throws IOException{
        //dwr通过WebContext取得HttpServletRequest
        WebContext wc = WebContextFactory.get();
        HttpServletRequest req = wc.getHttpServletRequest();

        String realpath = req.getSession().getServletContext().getRealPath("upload");
        String fn = FilenameUtils.getName(fileName);
        String filepath = realpath + "/" + fn;
        FileUtils.copyInputStreamToFile(is, new File(filepath));//将输入流直接copy成文件

        return filepath;
    }

}

在web.xml中配置dwr

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <servlet>
        <servlet-name>dwr-invoker</servlet-name>
        <servlet-class>
            org.directwebremoting.servlet.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>
</web-app>

在dwr.xml 配置映射关系 com.ajax.Upload 为功能处理类所在的位置

<dwr>
    <allow>
        <create creator="new" javascript="Upload">
            <param name="class" value="com.ajax.Upload" />
        </create>
    </allow>
</dwr>

创建jsp页面

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="<%=basePath%>">
    <title>dwr上传文件</title>
  </head>
  <script type='text/javascript' src='dwr/engine.js'></script>
  <script type='text/javascript' src='dwr/util.js'></script>
  <script type="text/javascript" src="dwr/interface/Upload.js"></script>

  <script type="text/javascript">
    function upload(){
        var file = dwr.util.getValue("myfile");
        Upload.upload(file,file.value,function(data){
            alert(data);
        });
    }
  </script>
  <body> 

   <input type="file" id="myfile"/>
   <input type="button" value="上传" onclick="upload();"/>

  </body>
</html>

这里需要注意:

dwr/interface/Upload.js

是dwr.xml中的映射关系,只要配置了映射关系,就会自动生成。无需创建

如果启动过程中,Tomcat出现报错,请讲当前目录PUT到ROOT目录

0x04

成功访问:

这里使用写好的JSP文件尝试上传文件。

用Burp开启抓包功能。

看起来没什么区别,就是转成了multipart/form-data。

那么要对目标系统上进行上传,只需更改scriptName和methodName即可

成功Getshell

0x05 黑盒下的探测手段

在对某高校系统进行测试时,通过主页的HTMl源代码中发现了其系统使用DWR框架

尝试访问/dwr/index.html 获取接口目录

返回500,要么是dwr.xml配置错误,或者是做了防护手段,如果说配置错误的话,接口可能都用不了。这里还是选择了测一下。

由于/dwr/index.html无法访问,那么只能手动收集接口信息。

在各个HTML ,JSP页面上查找路径为

/dwr/interface/*.js

的js文件。此文件只有配置dwr.xml的映射才会生成,所以一般要调用ajax接口,就必须引入此js文件。

如下:

前面为scriptName,后面为methodName。p0,p1,p2 代表需要3个参数

将其各个接口进行了整合。然后提取methodName。尝试进行SQL注入。

这里需要注意:

如果返回结果提示

java.lang.Throwable

造成这个错误的原因有很多:

1.参数类型不对 2. 缺少必要参数 3. 接口自身问题

个人建议使用string: 数字

如下:

这里我构造请求方法,对每个接口都进行测试。

请求地址为:

http://localhost/dwr/call/plaincall/{{ scriptName }}.{{ methodName }}.dwr

正文:

callCount=1
page={{ 任意JSP地址均可 }}
httpSessionId= {{ 可留空 }}
scriptSessionId={{Cookie中的 DWRSESSION}}
c0-scriptName={{ scriptName }}
c0-methodName={{ methodName }}
c0-id=0
c0-param0=string(类型): 值 {{ 参数 1}}
batchId=0

最终在某个接口下面发现SQL注入:

单数单引号(错误)

双数双引号(正常)

由于服务器没有WAF,尝试使用SQLMAP.

注意需要 --level 3 不然跑不出来的

点击收藏 | 1 关注 | 1
  • 动动手指,沙发就是你的了!
登录 后跟帖