MENU

XSS攻击常识及实战

October 2, 2018 • Read: 5516 • 渗透测试阅读设置

什么是XSS?

XSS全称是Cross Site Scripting(为了和CSS进行区分,就叫XSS)即跨站脚本,当目标网站目标用户浏览器渲染HTML文档的过程中,出现了不被预期的脚本指令并执行时,XSS就发生了

XSS分类

XSS有三类:反射型XSS(非持久型)、存储型XSS(持久型)和DOM XSS

反射型XSS

发出请求时,XSS代码出现在URL中,作为输入提交到服务器端,服务器端解析后响应,XSS代码随响应内容一起传回给浏览器,最后浏览器解析执行XSS代码。这个过程像一次反射,所以称反射型XSS。
一个简单的例子:

<?php
echo $_GET['x'];
?>

如果输入x的值没有经过任何过滤直接输出,假设提交链接为:

http://www.foo.com/xss/reflect.php?x=<script>alert(1)</script>

则alert()函数会在浏览器访问时触发

存储型XSS

存储型XSS和反射型XSS的差别仅在于,提交的代码会存储在服务器端(数据库、内存、文件系统等),下次请求目标页面时不用再提交XSS代码。最典型的例子就是留言板XSS,用户提交一条包含XSS代码的留言存储到数据库,目标用户查看留言板时,那些留言就会从数据库中加载出来并显示,于是出发了XSS攻击

DOM XSS

DOM XSS和反射型XSS、存储型XSS的区别在于DOM XSS代码并不需要服务器参与,出发XSS靠的是浏览器的DOM解析,完全是客户端的事情
www.xss.com/domxss.html 代码如下:

<script>
    eval(localtion.hash.substr(1));
</script>

触发方式为:www.xss.com/domxss.html#alert(1) 这个URL#后的内容是不会发送到服务器端的,仅仅在客户端被接收并执行,常见的输入点有:

document.URL
document.URLUnencoded
document.localtion
document.referrer
window.location
window.name

实验一

1.构造代码
<%@ 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 'xss_test.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>
    <%
        String str = request.getParameter("name");
        out.print(str);
    %>
</body>
</html>
2.漏洞演练

首先访问:http://localhost:8080/jsp/user/xss_test.jsp?name=小明

接着我们试着加载一个js脚本看看,访问:http://localhost:8080/jsp/user/xss_test.jsp?name=<script>alert("XSS")</script>

那么是不是可以改变跳转后的地址?访问:http://localhost:8080/jsp/user/xss_test.jsp?name=<script>location.href='http://www.baidu.com'</script>

既然可以加载JS,那么我们是不是可以通过js来打开本地的某些东西?我提前在D盘根目录下放了一个1.txt文件,访问:http://localhost:8080/jsp/user/xss_test.jsp?name=<script> var objShell = new ActiveXObject("wscript.shell");objShell.Run("D:/1.txt");</script>

上面我都是用的Firefox或者chrome,但是这个只能用IE,因为只有IE才有ActiveXObject这个对象,而且访问之前要去IE的Internet选项里把安全级别调成很低,具体来说就是各种设置全部启用

既然连本地文件都可以打开,那么远程木马,写入文件?自己想象......

实验二

大部分网站都会和数据库打交道,XSS漏洞如果出现在这些网站会怎么样?

1.构造代码

user_insert.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>My JSP 'user_insert.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">
<jsp:include page="../res.jsp" />
</head>
<body class="container">
    <div class="container">
        <h3 class="page-header">输入用户信息</h3>
        <form action="<%=basePath%>user/user_insert_action.jsp" method="get"
            class="form-horizontal">
            <div class="form-group">
                <label class="col-md-3 control-label">userName:</label>
                <div class="col-md-5">
                    <input type="text" class="form-control" name="username">
                </div>
            </div>
            <div class="form-group">
                <label class="col-md-3 control-label">password:</label>
                <div class="col-md-5">
                    <input type="text" class="form-control" name="password">
                </div>
            </div>
            <div class="form-group">
                <label class="col-md-3 control-label">name:</label>
                <div class="col-md-5">
                    <input type="text" class="form-control" name="name">
                </div>
            </div>
            <div class="form-group">
                <label class="col-md-3 control-label">sex:</label>
                <div class="col-md-5">
                    <input type="text" class="form-control" name="sex">
                </div>
            </div>
            <div class="form-group">
                <label class="col-md-3 control-label">classes:</label>
                <div class="col-md-5">
                    <input type="text" class="form-control" name="classes">
                </div>
            </div>
            <div class="form-group">
                <label class="col-md-3 control-label">phone:</label>
                <div class="col-md-5">
                    <input type="text" class="form-control" name="phone">
                </div>
            </div>
            <div class="form-group">
                <label class="col-md-3 control-label">email:</label>
                <div class="col-md-5">
                    <input type="text" class="form-control" name="email">
                </div>
            </div>
            <div class="form-group">
                <label class="col-md-3 control-label">qq:</label>
                <div class="col-md-5">
                    <input type="text" class="form-control" name="qq">
                </div>
            </div>
            <div class="form-group">
                <div class="col-md-offset-3 col-md-5">
                    <button type="submit" class="btn btn-primary">提交</button>
                </div>
            </div>
        </form>
    </div>
</body>
</html>

user_insert_action.jsp

<%@page import="java.sql.*"%>
<%@ 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>user_insert_action.jsp</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>
    <%
        //1.获取请求参数
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String name = request.getParameter("name");
        String sex = request.getParameter("sex");
        String classes = request.getParameter("classes");
        String phone = request.getParameter("phone");
        String email = request.getParameter("email");
        String qq = request.getParameter("qq");
    %>
    <%
        //2.向数据库插入数据
        Connection conn = null;
        PreparedStatement pstmt = null;
        try {
            //2.1 加载驱动类
            Class.forName("com.mysql.jdbc.Driver");
            
            //2.2 创建数据库连接
            String url = "jdbc:mysql://localhost:3306/jsp?useUnicode = true & characterEncoding = UTF-8";
            String userName = "root";
            String pwd = "root";
            conn = DriverManager.getConnection(url, userName, pwd);

            //2.3 创建预处理声明
            String sql = "insert into user" + "(username,password,name,sex,classes,phone,email,qq)"
                    + "values(?,?,?,?,?,?,?,?)";
            pstmt = conn.prepareStatement(sql);
            pstmt.setString(1, username);
            pstmt.setString(2, password);
            pstmt.setString(3, name);
            pstmt.setString(4, sex);
            pstmt.setString(5, classes);
            pstmt.setString(6, phone);
            pstmt.setString(7, email);
            pstmt.setString(8, qq);

            //2.4 向数据库发送sql语句
            int res = pstmt.executeUpdate();
            out.println(res);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            pstmt.close();
            conn.close();
        }
    %>
</body>
</html>

user.jsp

<%@page import="cn.edu.wic.jsp.bean.User"%>
<%@page import="java.sql.DriverManager"%>
<%@page import="java.sql.ResultSet"%>
<%@page import="java.sql.PreparedStatement"%>
<%@page import="java.sql.Connection"%>
<%@ 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>JDBC</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>
    <%
        List<User> users = new ArrayList<User>();
        Connection conn = null;
        PreparedStatement pstmt = null;//发送声明的对象
        ResultSet rs = null;//返货结果集的对象

        try {
            Class.forName("com.mysql.jdbc.Driver");
            String url = "jdbc:mysql://localhost:3306/jsp?useUnicode=true&characterEncoding=UTF-8";
            String username = "root";
            String password = "root";
            conn = DriverManager.getConnection(url, username, password);
            pstmt = conn.prepareStatement("select * from user");
            rs = pstmt.executeQuery();
            while (rs.next()) {
                User user = new User();
                user.setId(rs.getInt("id"));
                user.setUsername(rs.getString("username"));
                user.setPassword(rs.getString("password"));
                user.setName(rs.getString("name"));
            %>
    <%= user.getId() + ","%>
    <%= user.getUsername() + "," %>
    <%= user.getPassword() + "," %>
    <%= user.getName() %>
    <br>
    <%
                
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (pstmt != null) {
                try {
                    pstmt.close();
                } catch (Exception e) {
                }
            }
            if (conn != null) {
                try {
                    conn.close();
                } catch (Exception e) {
                }
            }
        }
    %>
</body>
</html>

用户从user_insert.jsp输入信息提交,然后跳转到user_insert_action.jsp,页面会显示数据库更改的条数信息,然后访问user.jsp查询数据库中的用户信息

2.漏洞实验

首先在user_insert.jsp输入信息

提交后跳转到user_insert_action.jsp,页面显示1,说明用户信息成功插入数据库

最后,访问user.jsp,XSS注入成功

上面实验一进行的实验都可以在这上面利用,比方说写入文件,或者实现页面跳转

信息提交成功

然后访问user.jsp,首先弹框1,没问题,点击确定后,就直接跳转到baidu的网站去了

如果我把弹框的信息删掉,只保留跳转,产生的效果就是只要有用户访问到user.jsp页面,就立马跳转到百度去了,类似DNS劫持

Last Modified: October 7, 2018
Archives Tip
QR Code for this page
Tipping QR Code
Leave a Comment

2 Comments
  1. 风雪 风雪

    还可以利用XSS获取用户Cookie

    1. mathor mathor

      @风雪都行,只要有漏洞