Java审计之XSS篇
2020-09-21 14:47:13 Author: xz.aliyun.com(查看原文) 阅读量:404 收藏

0x00 前言

继续 学习一波Java审计的XSS漏洞的产生过程和代码。

0x01 Java 中XSS漏洞代码分析

xss原理

xss产生过程:

后台未对用户输入进行检查或过滤,直接把用户输入返回至前端。导致javascript代码在客户端任意执行。

XSS代码分析

在php里面会使用echo对用户输入的参数进行直接输出,导致了xss漏洞的产生。而在Java里面会将接收到的未经过滤的参数共享到request域中,在jsp的页面里面使用EL表达式进行输出。

这里编写一个serlvet来做一个演示

xssservlet代码:

@WebServlet("/demo")
public class xssServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doGet(request,response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        response.setContentType("text/html");// 设置响应类型
        String content = request.getParameter("content");  //获取content传参数据
        request.setAttribute("content", content);  //content共享到request域
        request.getRequestDispatcher("/WEB-INF/pages/xss.jsp").forward(request, response);  //转发到xxs.jsp页面中

    }
}

xss.jsp代码:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
    ${requestScope.content}
</head>
<body>

</body>
</html>

启动tomcat,访问url:

http://localhost:8080/untitled3_war_exploded/demo?content=1

传参一个1过去成功输入了,那么再来传一个xss的payload试试。

http://localhost:8080/untitled3_war_exploded/demo?content=<script>alert("xss")</script>

成功的弹出了一个框

在审计中需要关注的是参数是否可控,如果可控传入的参数是否会被过滤后共享到request域中,如果在可控和不被过滤的情况下,就很有可能存在xss漏洞。

防御xss策略

我们需要防御xss漏洞的攻击,就需要添加一个方法,在传入前先调用该方法进行一次过滤,但是这样的方式比较繁琐,这时候就可以使用ESAPI来帮我们过滤。

ESAPI介绍:

企业安全API(ESAPI)项目是OWASP项目,可为每个Web平台创建简单的强大安全控件。安全控件并不容易构建。您可以在OWASP网站上了解无聊的开发人员的数百个陷阱。通过为开发人员提供一组强大的控件,我们旨在消除创建安全Web应用程序的某些复杂性。这可以在整个SDLC中节省大量成本。

据说可以应付大部分的web攻击漏洞。

在pom.xml导入ESAPI坐标

<!-- https://mvnrepository.com/artifact/org.owasp.esapi/esapi -->
<dependency>
    <groupId>org.owasp.esapi</groupId>
    <artifactId>esapi</artifactId>
    <version>2.2.1.1</version>
</dependency>

servlet代码:

@WebServlet("/demo")
class xssServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doGet(request,response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, ServletException, IOException {

        response.setContentType("text/html");// 设置响应类型

        String content = request.getParameter("content");  //获取content传参数据
        String s = ESAPI.encoder().encodeForJavaScript(content);  //进行实体编码
        request.setAttribute("content", s);  //content共享到request域
        request.getRequestDispatcher("/WEB-INF/pages/xss.jsp").forward(request, response);  //转发到xxs.jsp页面中

    }
}

参考该博客

https://blog.csdn.net/CHS007chs/article/details/86645450

0x02 搭建测试环境

测试环境

IDEA  :2020.1.2 X64 

MYSQL :5.7.26

TomCat:8.0

JDK   :1.8

搭建环境

下载源码

http://down.admin5.com/jsp/132874.html

idea中导入项目,添加pom.xml文件为maven文件。如果Spring注解报错说明Spring的环境还没拉去下来,刷新一下pom.xml文件就好了。

这里配置是82端口,目录就默认就行。

配置tomcat也设置为82端口

这里要注意路径需要根路径,否则加载有一些css资源的时候路径会因为路径问题加载不少。

这样就配置完成了,但是还是会发现有一些get,set的方法会爆红。

项目的说明文档里面给出了解决方法,只需要安装一下lombok插件重启一下就解决了,这里是因为一些代码中并没有实际编写get和set的方法,使用的是插件去提供的。

这些完成后,就可以讲提供好的sql文件导入进去。进行启动

这些都是自己专门踩过的坑,一段操作猛如虎后,启动完成。但是会有一些报错,sql文件在导入的时候,有些执行错误了,几张表没创建成功,在进行操作该表的时候未找到该表,就报错了。

0x03 setAttribute中的xss

这次还是拿上次搭建的环境来做一个演示。

那么结合前面的内容,知道了xss的产生过程是使用request.setAttribute方法将请求到的数据未经过滤存储到request域中,然后在jsp页面里使用el表达式进行输出。

在审计的时候我们可以直接来全局搜索 快捷键 Ctrl+Shift+F

这里就来找一下存储型xss,反射的xss意义并不大。

点击选择一个文件来看看他的代码,这里直接就给共享到request域中了,但是这里只是我们的一个查询方法,我们需要找到他输入值的地方, 看到下面的addComment方法正好对应上了一个输出xss ,一个插入xss的地方。

查看该方法 commentService.addComment(comment); 调用addComment方法将值传入,不出意外的话传入的comment参数就是接收过来的一个实体类。我们来Ctrl+左键点击 Comment类进行跳转到该类去。

主要关注变量为 String类型的变量,因为Java是强类型的语言。

等会对这几个变量的地方进行插入xss代码。

回到刚才的控制器代码

点击ctrl+左键点击addComment 追溯到CommentService 的接口

同样的方式再追溯到CommentService的实现类

使用的是commentDao调用addComment 传入参数进行添加数据。继续追溯上去

在这里我们就看到了dao接口中的addcomment方法,dao接口中并没有myabtis的注解,说明是xml配置文件配置的。

后面的直接开启全局搜索,搜索addComment指定xml文件。

点击进去看到,我们的提交的内容会被插入数据库里面,也就是说这是个存储型xss

逻辑这里其实已经很清晰了。

具体的还得看实操,查看Controller获取路径。

漏洞位置:

http://127.0.0.1:82/web/comment/ajax/addcomment

结合刚刚查看的Comment实体类,我们已经找到哪些地方可以去插xss了。

<script>alert("1")</script>

访问一下漏洞地址

这里还需要登录后才能访问,那就登录一下吧!

系统错误,我。。。。。肯定又是上次那张表的问题,那几张表没建立好。

没事具体来审计其他的点。

根据上面内容来总结一下,我们首先是全局搜索了request.setAttribute 这个共享到request域的方法,查看他的传值类型,再跟踪到他的实体类里面,查看实体类中哪些地方是String类型的变量。只有String类型的。查询完这样以后,就需要查看哪些方法调用了哪些方法将我们的xss Payload添加进去,后面就可以追溯到dao层查看一下有没有添加进数据库里面。在查询和插入内容的方法里面需要留意一下有没有过滤。

0x04 ModelAndVIew详解

当视图解释器解析是ModelAndVIew,其中model本生就是一个Map的实现类的子类。视图解析器将model中的每个元素都通过request.setAttribute(name, value);添加request请求域中。这样就可以在JSP页面中通过EL表达式来获取对应的值。其实就是进行了一个简单的封装,方便于我们使用。

方法1:

定义格式:

public ModelAndView addObject(String attributeName, Object attributeValue)

实例:

1 ModelAndView mav=new ModelAndView("hello");
2 mav.addObject("time", new Date());

将一个对象共享到域中

方法2:

mav.getModel().put("name", "xiaoming");

0x05 ModelAndView的xss

使用ModelAndView需要new一个对象,那么我们可以直接来全局搜索new ModelAndView来查找该关键字。

点击一个存在该关键字的类,进行跳转到该类。

这里实例化了一个对象叫model,跟踪看一下model都调用了哪些方法,如果调用addObject共享到域中,看他有没有调用过滤方法,没有的话,我们就可以来跟踪一下需要共享的值。哪些地方可以插入 xss的Paylaod。

定位一下typeList变量是怎么来的

这里就可以看到调用了webSiteImagesTypeServicewebSiteImagesTypeService.queryAllTypeList()方法进行返回的,存储到了一个list集合,WebSiteImagesType类型的。

再来定位到WebSiteImagesType实体类里面,看看都有哪些属性,查看有没有String类型的变量。

typeName的地方是String类型的,可以去插入xss的Payload。

返回Controller查看调用的方法typeList值得获取调用得方法。

ctrl+左键点击WebSiteImagesTypeSerivce跳转到该接口。

选中接口,CTRL+H 查看该接口实现类。

点击实现类,进行跟踪

这里就查看到了 service层得queryAllTypeList会调用webSiteImagesTypeDaoqueryAllTypeList()查询进行返回且没有过滤,继续跟踪dao到。

看到并没有使用注解来配置,那么就肯定是使用了xml的文件来进行配置了。

全局搜索一下dao的名称,并且指定类型为xml的文件,在开发中一般xml的映射文件会和dao接口的名字前面一样,然后加个mapper。

点击跳转进去

到这里后,就已经看到内容会从数据库的EDU_WEBSITE_IMAGES_TYPE表里面去取值,并且返回。

下一步需要做的就是查看数据会从哪里去写入。

返回到Controller,看到下面还有个更新的方法,是可以对数据进行插入的。

调用了WebSiteImagesTypeService方法跳转到实现类里面查看,有没有调用到过滤的方法。

这里并没有调用到过滤的方法,而是直接调用webSiteImagesTypeDao.updateType直接传入值了,其实从Controller的更新方法追溯上去一点多此一举了,因为我们在跟踪查询方法的service接口的时候,其实就已经看到增删改查的方法了,这里只是为了逻辑更清晰一些。

跟踪到updatetype方法后, 查询映射文件,其实文件还是刚刚在定位查询方法时候的那个文件里面

这里得知该语句会从WebSiteImagesType取typeName和typeId的值,进行更新语句的填入。如果我们在对应的位置插入xss后,payload 会存储在WebSiteImagesTypetypeName然后再被带入到dao层去写入到数据库里面去。写入完成,访问页面服务器执行了查询方法的话就会返回xss的值,这时候输入输出都没有做过滤直接输出了,就导致了xss的产生。

下面来把环境启动,然后进行测试一下。

查看漏洞地址

http://127.0.0.1:82/admin/imagetype/getlist

点击修改名称进行修改。

xss执行了,但是闭合的时候没成功闭合,插崩了。后面的几个按钮都给覆盖了。

去数据库将数据删除一下。

重新打开一下。

构造xss Payload,具体怎么构造这里就不做赘述了。

</td><script>alert("1")</script>

0x07 参考文章

https://xz.aliyun.com/t/7945#toc-9
https://xz.aliyun.com/t/2646

0x06 结尾

在审计代码的时候会发现一些比较有意思的事情,比如刚刚查看的service接口中的增删改查方法,如果接口中一任意个方法没做过滤,其他的方法也不会去做一个过滤。刚刚审计的只是一个update的方法插入xss,但是如果是增加的方法呢?,当然也是可以的。但是这里的代码添加的方法不是直接去做一个设置,而是添加条新的并且是空的数据,后面需要修改成想要的数据。这样的话漏洞的位置还是在修改方法上面,而不是添加的方法。


文章来源: http://xz.aliyun.com/t/8294
如有侵权请联系:admin#unsafe.sh