WEB安全

浅谈JSP安全开发之XSS

字号+ 作者:0nise 来源:i春秋社区 2016-11-25 09:36 我要评论( )

作者: 0nise 首发: i春秋社区 注明:转载请务必注明 i春秋社区(bbs.ichunqiu.com) 前言 大家好,好男人就是我,我就是好男人,我就是 -0nise。在各大漏洞举报......

作者:0nise
首发:i春秋社区
注明:转载请务必注明i春秋社区(bbs.ichunqiu.com)

前言
     大家好,好男人就是我,我就是好男人,我就是-0nise。在各大漏洞举报平台,我们时常会看到XSS漏洞。那么问题来了,为何会出现这种漏洞?出现这种漏洞应该怎么修复?
目录
     1.XSS?XSS?XSS是什么鬼?
     2.XSS的危害有多大?
     3.如何避免XSS漏洞的出现

正文
1.XSS?XSS?XSS是什么鬼
     XSS又叫跨站脚本攻击(Cross Site Scripting),我不会告诉他原本是叫CSS的,但是为了不和我们所用的层叠样式表(Cascading Style Sheets)CSS搞混。CSS(跨站脚本攻击),CSS(层叠样式表)傻傻分不清。所以就叫XSS咯。
2.XSS的危害是什么?
实验一:
0x00构造代码
[Java] 纯文本查看 复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<%@ 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>My JSP 'index.jsp' starting page</title>
        <meta http-equiv="pragma" content="no-cache">
        <meta http-equiv="cache-control" content="no-cache">
        <meta http-equiv="expires" content="0">  
        <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
        <meta http-equiv="description" content="This is my page">
  </head>
  <body>
    <div style="margin: 0 auto">
    <%
//设置编码
            request.setCharacterEncoding("UTF-8");
//接收用户传入值
            String tmp = request.getParameter("opr");
            //减速传入值是否为空
            if(tmp == null){
                    out.print("111");
            }else{
                    //转码
                    String opr = new String(tmp.getBytes("ISO-8859-1"),"utf-8");
                    out.print(opr);
            }
    %>
            我是内容
    </div>
  </body>
</html>

0x01环境布局

0x02漏洞演练
我们访问:http://localhost:8080/XSS/index.jsp?opr=i%E6%98%A5%E7%A7%8B

然后访问:http://localhost:8080/XSS/index.jsp?opr=0nise

最后我们发现了一个“伟大的规律”:
   opr参数等于什么页面就打印什么。(好像是废话)
我们接着来加载一个图片看看
访问:
http://localhost:8080/XSS/index.jsp?opr=%3Cimg%20src=%221.png%22%3E%3C/img%3E

既然图片都可以加载,那么我们JS文件是不是也阔以加载呢?
访问:http://localhost:8080/XSS/index.jsp?opr=%3Cscript%3Ealert(/i%E6%98%A5%E7%A7%8B%E7%A4%BE%E5%8C%BA%E6%AC%A2%E8%BF%8E%E5%A4%A7%E5%AE%B6/)%3C/script%3E

Js?Js?那么是不是可以来改变跳转后地址?
访问:
http://localhost:8080/XSS/index.jsp?opr=%3Cscript%3Elocation.href=%27http://bbs.ichunqiu.com%27%3C/script%3E

既然xss都可以加载js,那么,我们是不是通过js来打开本地的某些东西?

提前放了一个MD5.exe文件
访问:http://localhost:8080/XSS/index.jsp?opr=<script> var objShell = new ActiveXObject("wscript.shell");objShell.Run("G:/work/XSS/WebRoot/Md5.exe");</script>

既然连本地文件都可以打开那么远程文件木马?来个电脑恶搞?这个自己慢慢象限。我可没说啊。。。。。
文件都可以打开,那么写一些文件呢?
访问:
http://localhost:8080/XSS/index.jsp?opr=%3Cscript%3Evar%20fso,tf;fso%20=%20new%20ActiveXObject(%22Scripting.FileSystemObject%22);tf%20=%20fso.CreateTextFile(%22d:\\test.txt%22,true);tf.WriteLine(%22i%E6%98%A5%E7%A7%8B%E7%A4%BE%E5%8C%BA%E6%AC%A2%E8%BF%8E%E6%82%A8%22);tf.Close();alert(%22%E6%96%87%E4%BB%B6%E5%86%99%E5%85%A5%E6%88%90%E5%8A%9F%EF%BC%81%22);%3C/script%3E


通过以上实验我们可以看出opr参数赋值操作。如果opr参数没有值的话,就无法执行执行,被攻击者必须访问攻击者提前设计好的才能攻击。这种XSS攻击方式叫做:存储型XSS
如果你想看到更给力的实验,请接着往下看。

实验二:
前言:
大部分网站都会和数据打交道那么,XSS漏洞出现这些网站是什么样子的?
0x00构造代码
数据库部分

BaseDao.java
[Java] 纯文本查看 复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class BaseDAO {
        //打开连接
        public Connection getConn(){
                Connection conn = null;
                try {
                        Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
                        conn = DriverManager.getConnection("jdbc:sqlserver://localhost:1433;databaseName=SQLTMP","sa","sa");
                } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                } catch (SQLException e) {
                        e.printStackTrace();
                }
 
                return conn;
        }
         
        //关闭链接的方法
        public void closeAll(Connection conn,Statement stat,ResultSet rs){
                try {
                        if(rs != null)
                                rs.close();
                        if(stat != null)
                                stat.close();
                        if(conn != null)
                                conn.close();
                         
                } catch (SQLException e) {
                        e.printStackTrace();
                }
        }
        //重载关闭方法
        public void closeAll(Connection conn,PreparedStatement pstat,ResultSet rs){
                try {
                        if(rs != null)
                                rs.close();
                        if(pstat != null)
                                pstat.close();
                        if(conn != null)
                                conn.close();
                         
                } catch (SQLException e) {
                        e.printStackTrace();
                }
        }
        //继续重载
        public void closeAll(Connection conn,PreparedStatement pstat){
                try {
                        if(pstat != null)
                                pstat.close();
                        if(conn != null)
                                conn.close();
                } catch (SQLException e) {
                        e.printStackTrace();
                }
        }
        //增删改的公用方法
        public int upDate(String sql,Object[] pram){
                 
                PreparedStatement pstat = null;
                Connection conn = null;
                int a = 0;
                 
                try {
                        conn = getConn();
                        pstat =conn.prepareStatement(sql);
                        //遍历参数集合,将集合中的参数对应添加到sql语句中
                        for (int i = 1; i <= pram.length; i++) {
                                pstat.setObject(i, pram[i-1]);
                        }
                        //调用方法
                        a = pstat.executeUpdate();
                         
                } catch (SQLException e) {
                        e.printStackTrace();
                }finally{
                        closeAll(conn, pstat);
                }
                return a;
        }
}
      
CommentDao.java
[Java] 纯文本查看 复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import java.sql.*;
import java.util.*;
import entity.*;
public class CommentDao extends BaseDAO {
        /**
         * 获取所有留言
         * */
        public List<comm> GetComment(){
                //SQL语句
                String sql = "SELECT CID,CName,CContext FROM Comments";
                List<comm> list = new ArrayList<comm>();
                //数据库连接对象
                Connection conn = null;
                //SQL执行对象
                PreparedStatement pstmt = null;
                //数据库执行返回值
                ResultSet rs = null;
                try {
                        //创建数据库链接
                        conn = this.getConn();
                        //创建SQL执行对象
                        pstmt = conn.prepareStatement(sql);
                        //执行SQL语句     返回值
                        rs = pstmt.executeQuery();
                        //读取
                        while (rs.next()) {
                                comm comment = new comm();
                                comment.setCID(rs.getInt("CID"));
                                comment.setCName(rs.getString("CName"));
                                comment.setCContext(rs.getString("CContext"));
                                list.add(comment);
                        }
                } catch (Exception e) {
                        e.printStackTrace();
                }finally{
                        //关闭
                        this.closeAll(conn, pstmt, rs);
                }
                return list;
        }
        public int AddComment(comm comment){
                String sql = "INSERT INTO Comments VALUES(?,?)";
                //受影响行数
                int result = 0;       
                //数据库连接对象
                Connection conn = null;
                //SQL执行对象
                PreparedStatement pstmt = null;
                try {
                        //创建数据库链接
                        conn = this.getConn();
                        //创建SQL执行对象
                        pstmt = conn.prepareStatement(sql);
                        //设置参数
                        pstmt.setString(1, comment.getCName());
                        pstmt.setString(2, comment.getCContext());
                        //执行SQL语句
                        result =  pstmt.executeUpdate();
                } catch (Exception e) {
                        e.printStackTrace();
                }finally{
                        this.closeAll(conn, pstmt);
                }
                return result;
        }
}

CommentServlvet
[Java] 纯文本查看 复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import entity.*;
public class CommentServlvet extends HttpServlet {
        /**
         * doGet()
         */
        public void doGet(HttpServletRequest request, HttpServletResponse response)
                        throws ServletException, IOException {
                request.setCharacterEncoding("UTF-8");
                response.setContentType("text/html;charset=UTF-8");
                PrintWriter out = response.getWriter();
                String opr = request.getParameter("opr");
                CommentDao commentDao = new CommentDao();
                //检索参数是否为空
                if(opr == null || opr.equals("all")){
                        request.setAttribute("all", commentDao.GetComment());
                        //转发
                        request.getRequestDispatcher("comment.jsp").forward(request, response);
                }else if (opr.equals("add")){
                        comm comment = new comm();
                        comment.setCName(request.getParameter("UName"));
                        comment.setCContext(request.getParameter("context"));
                        if(commentDao.AddComment(comment) > 0){
                                out.print("<script>alert('留言成功');location.href='CommentServlvet?opr=all';</script>");
                        }else{
                                out.print("<script>alert('留言失败');location.href='CommentServlvet?opr=all';</script>");
                        }
                }else{
                        request.setAttribute("all", commentDao.GetComment());
                        //转发
                        request.getRequestDispatcher("comment.jsp").forward(request, response);
                }
                out.flush();
                out.close();
        }
 
        /**
         * doPost()
         */
        public void doPost(HttpServletRequest request, HttpServletResponse response)
                        throws ServletException, IOException {
                doGet(request, response);
        }
}

Comment.jsp
[Java] 纯文本查看 复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<%@ page language="java" import="java.util.*,entity.*" 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>My JSP 'comment.jsp' starting page</title>
        <meta http-equiv="pragma" content="no-cache">
        <meta http-equiv="cache-control" content="no-cache">
        <meta http-equiv="expires" content="0">  
        <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
        <meta http-equiv="description" content="This is my page">
  </head>
  <body>
  <%
          request.setCharacterEncoding("UTF-8");
          if(request.getAttribute("all") == null){
                  request.getRequestDispatcher("CommentServlvet?opr=all").forward(request, response);
          }
  %>
  <table>
  <%
          List<entity.comm> list = (List<entity.comm>)request.getAttribute("all");
              for(int i = 0; i < list.size(); i++ ){
  %>
                  <tr>
                  <td><%=list.get(i).getCName() %></td>
                  <td><%=list.get(i).getCContext() %></td>
                  </tr>
                  <%
          }
  %>
   </table>
  <form action="CommentServlvet?opr=add" method="post">
          <textarea rows="5" cols="30" name="context"></textarea>
          昵称:<input type="text" name="UName" />
          <input type="submit" value="提交" />
  </form>
  </body>
</html>

0x01漏洞实验
root@1~#
我们在留言板留言:
[JavaScript] 纯文本查看 复制代码
?
1
<script> var objShell = new ActiveXObject("wscript.shell");objShell.Run("G:/work/XSS/WebRoot/Md5.exe");</script>


然后访问:http://localhost:8080/XSS/comment.jsp

这样只要访问这个页面,软件就自动打开了,来个远程文件?慢慢领悟。
root@2~#
我们在留言板留言:
[JavaScript] 纯文本查看 复制代码
?
1
<script>var fso,tf;fso = new ActiveXObject("Scripting.FileSystemObject");tf = fso.CreateTextFile("d:\\test.txt",true);tf.WriteLine("i春秋社区欢迎您");tf.Close();alert("文件写入成功!");</script>


然后访问: http://localhost:8080/XSS/comment.jsp

文件写入成功。
root@3~#
留言内容:
[JavaScript] 纯文本查看 复制代码
?
1
<script>location.href='http://bbs.ichunqiu.com'</script>

访问页面:http://localhost:8080/XSS/comment.jsp

访问留言页面自动跳转到攻击者特定的网站。难道这就是传说中的劫持吗?
3.XSS防御方案
正所谓哪里有攻击,哪里就有防御。XSS一样,有攻击的方式,也有防御的方案。
EL表达式+JSTL标签库
EL(Expression Language):[size=12.0000pt]为了使JSP写起来更简单。表达式语言的灵感来自于ECMAScript和XPath表达式语语言,他提供了JSP中简化表达式的方法,让jsp代码更简单。

JSTL(JSP Standard Tag Library):开放源代码的JSP标签库。
实验一防御代码:
[Java] 纯文本查看 复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%
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>My JSP 'index.jsp' starting page</title>
        <meta http-equiv="pragma" content="no-cache">
        <meta http-equiv="cache-control" content="no-cache">
        <meta http-equiv="expires" content="0">   
        <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
        <meta http-equiv="description" content="This is my page">
  </head>
  <body>
    <div style="margin: 0 auto">
    <%
            request.setCharacterEncoding("UTF-8");
            String tmp = request.getParameter("opr");
            //减速传入值是否为空
            if(tmp == null){
                    out.print("111");
            }else{
                    //转码
                    String opr = new String(tmp.getBytes("ISO-8859-1"),"utf-8");
                    request.setAttribute("name", opr);
                    %>
                    <c:out value="${requestScope.name }"></c:out>
                    <%
            }
    %>
            我是内容
    </div>
  </body>
</html>


实验二防御代码:

[Java] 纯文本查看 复制代码
?
1
2
3
4
5
6
<%@ page language="java" import="java.util.*,entity.*" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

[Java] 纯文本查看 复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="<%=basePath%>">
    <title>My JSP 'comment.jsp' starting page</title>
        <meta http-equiv="pragma" content="no-cache">
        <meta http-equiv="cache-control" content="no-cache">
        <meta http-equiv="expires" content="0">   
        <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
        <meta http-equiv="description" content="This is my page">
  </head>
  <body>
  <%
          request.setCharacterEncoding("UTF-8");
          if(request.getAttribute("all") == null){
                  request.getRequestDispatcher("CommentServlvet?opr=all").forward(request, response);
          }
  %>
  <table>
<!-- 防御XSS方案 -->
  <c:forEach var="x" items="${requestScope.all }">
  <tr>
          <td>
          <c:out value="${x.getCName() }"></c:out>
          </td>
          <td>
          <c:out value="${x.getCContext() }"></c:out>
          </td>
  </tr>
  </c:forEach>
   </table>
  <form action="CommentServlvet?opr=add" method="post">
          <textarea rows="5" cols="30" name="context"></textarea>
          昵称:<input type="text" name="UName" />
          <input type="submit" value="提交" />
  </form>
  </body>
</html>


结束语
        技术无黑白,专研甚好。

本文来自: 蜗蜗侠's Blog-关注网络安全 http://blog.icxun.cn/Web/257.html

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

相关文章
  • EXIF Viewer XSS漏洞的来龙去脉[转载]

    EXIF Viewer XSS漏洞的来龙去脉[转载]

    2017-06-27 21:26

  • T00LS帖子正文XSS[转载]

    T00LS帖子正文XSS[转载]

    2017-06-27 21:03

  • XSS钓鱼模拟实战【附赠源码】

    XSS钓鱼模拟实战【附赠源码】

    2017-01-12 21:30

  • 新手指南:DVWA-1.9全级别教程(完结篇,附实例)之XSS

    新手指南:DVWA-1.9全级别教程(完结篇,附实例)之XSS

    2016-12-27 09:41

网友点评
暂时未开启评论功能~