XSS(Cross Site Scripting)是利用 WEB 应用程序将用户输入的恶意脚本植入到 WEB 页面中并执行。 目前主流的 XSS 漏洞包含反射性、DOM 型和存储型。

XSS 常见触发位置

XSS 漏洞产生后必然会有相关的输入/输出,因此只需要找到这些输入/输出点,即可进行跟踪发现漏洞。

输入在 Java 中通常使用 requests.getParameter(param) 或 ${param} 获取用户的输入信息。输出主要表现为前端的渲染,可以通过定位前端中一些常见的标识符来找到它们,然后根据后端逻辑判断漏洞是否存在。

JSP 表达式

<%= 变量 %> 是 <% out.println(变量); %> 的简写形式,用于将已声明的变量或表达式输出到页面上。

<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
<head>
<title>JSP - XSS</title>
</head>
<body>
<% String message =request.getParameter("msg"); %>
<%= message %>
</body>
</html>

EL 表达式

EL(Expression Language,表达式语言)提供了在 JSP 中简化表达式的方法,如 <%= request.getParameter("username"); %> 等价于 ${param.username}

  • jsp

<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
<head>
    <title>JSP - XSS</title>
</head>
<body>
${param.msg}
</body>
</html>
  • Servlet

package example.xss.testxss;

import java.io.*;
import javax.servlet.ServletException;
import javax.servlet.http.*;
import javax.servlet.annotation.*;

@WebServlet(name = "xssServlet", value = "/xss-servlet")
publicclassXssServletextendsHttpServlet{
publicvoiddoGet(HttpServletRequest request, HttpServletResponse response)throws IOException, ServletException {
        String content = request.getParameter("error");
        request.setAttribute("msg", content);
        request.getRequestDispatcher("index.jsp").forward(request, response);
    }
}
  • jsp

<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<title>JSP - XSS</title>
</head>
<body>
${requestScope.msg}
</body>
</html>

Model 类的使用

Model 类是一个接口类,通过 attribue() 添加数据,存储的数据域范围是 requestScope。

  1. 创建 maven 项目。

图片

  1. 添加依赖。

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>6.0.6</version>
    </dependency>
    <dependency>
        <groupId>jakarta.servlet</groupId>
        <artifactId>jakarta.servlet-api</artifactId>
        <version>6.1.0</version>
    </dependency>
</dependencies>
  1. 删除原有老的 web.xml 然后新建新的 web.xml。

图片

  1. 在 resources 下创建 springmvc.xml 并编写以下示例内容。

<?xml version="1.0" encoding="UTF-8"?>
<beansxmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/mvc
       http://www.springframework.org/schema/mvc/spring-mvc.xsd">

<!-- 扫描控制器所在的包 -->
<context:component-scanbase-package="org.example" />
<!-- 配置视图解析器 -->
<beanclass="org.springframework.web.servlet.view.InternalResourceViewResolver">
<propertyname="prefix"value="/admin/" />
<propertyname="suffix"value=".jsp" />
</bean>
<!-- 配置注解驱动 -->
<mvc:annotation-driven />
</beans>
  1. 在 main 目录下创建 Java 目录,随后在 Java 目录下创建包 org.example。

  2. 在 webapp 目录下创建 admin 目录。

  3. 创建 org.example.controller.XssController,编写以下示例内容。

package org.example.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
publicclassXssController{
@RequestMapping("/xss")
public String xss(@RequestParam String error, Model model){
        model.addAttribute("xss", error);
return"main";
    }
}
  1. 在 admin 目录下创建 main.jsp,编写以下示例内容。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
${requestScope.xss}
</body>
</html>
  1. 配置工件。

图片

  1. 修改 index.jsp 内容。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>testXSS</title>
</head>
<body>
<a href="${pageContext.request.contextPath}/xss?error=<script>alert(1)</script>">XSS</a>
</body>
</html>
  1. 配置 tomcat,启动项目。

图片

ModelMap 类的使用

ModelMap 类可以根据模型属性的具体类型自动生成模型属性的名称。

  • 修改 XssController 代码。

package org.example.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
publicclassXssController{
@RequestMapping("/xss")
public String xss(@RequestParam String error, ModelMap model){
        model.addAttribute("xss", error);
return"main";
    }
}

ModelAndView 类的使用

ModelAndView 类用来存储处理完成后的结果数据,以及显示该数据的视图。前端 JSP 页面可以使用 ${参数} 的方法来获取值。

  • 修改 XssController 代码。

package org.example.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

@Controller
publicclassXssController{
@RequestMapping("/xss")
public ModelAndView xss(@RequestParam String error){
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("main");
        modelAndView.addObject("error", error);
return modelAndView;
    }
}
  • 修改 main.jsp 内容。

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

在 Java 中可以通过以下关键字快速定位至具有前后端交互功能的代码片段:

  • <%=

  • ${param

  • ${requestScope

  • Model

  • ModelMap

  • ModelAndView

  • response.setContentType("text/html

  • request.getParameter

  • request.setAttribute

  • out.print(

  • out.write(

  • response.getWriter().print()

  • response.getWriter().writer()

Liferay Portal XSS

  • 漏洞名称: Liferay Portal XSS(CVE-2025-4388)

  • 漏洞类型:基于 out.print() 方法的 html 拼接导致的跨站脚本攻击

  • 影响版本:7.4.0 - 7.4.3.131

  • 利用点:动态渲染图标资源(icon.jsp)

开始审计

XSS payload 可以被解析的必要条件是返回类型为 text/html,通过“在文件中查找”中搜索关键内容 response.setContentType("text/html");

图片

一个个点击去后再找输入输出的地方。

Liferay Portal 使用的是 ParamUtil.getString(request, xxx) 从 HttpServletRequest 中获取字符串类型的请求参数。使用 out.write() 和 out.print() 输出到页面。经过一一排查,定位到 osgi/portal/com.liferay.marketplace.app.manager.web.jar!/org/apache/jsp/icon_jsp.java

  • icon_jsp.java 简化版

......
      response.setContentType("text/html");
......

String iconURL = ParamUtil.getString(request, "iconURL");
......
if (_jspx_eval_c_when_1 != javax.servlet.jsp.tagext.Tag.SKIP_BODY) {
do {
                out.write("\n\t\t\t<img alt=\"thumbnail\" class=\"img-fluid\" src=\"");
                out.print( iconURL );
                out.write("\" />\n\t\t");
......

html 语句为:<img alt="thumbnail" class="img-fluid" src="iconURL" />

在以上几行代码的位置均打上断点,进行调试。

  • 配置远程 JVM 调试:

图片

  • 修改 tomcat/bin/catalina.sh 的内容:

JAVA_OPTS="$JAVA_OPTS -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005"

  • 运行 tomcat/bin/startup.sh,等待 5005 端口开放,开启远程 JVM 调试。

图片

  • 访问 http://localhost:8080/o/marketplace-app-manager-web/icon.jsp?iconURL=https://mc.kurogames.com/website-preface/assets/avatar-1-active-b0eab8b5.webp"><script>alert(1)</script><!----

图片

  • 走到下一个断点:

图片

  • 走到下一个断点:

图片

图片

  • 查看网页源代码。 

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐