JAVA Code Audit-XSS

Posted by dvd420 on Wed, 02 Feb 2022 05:22:01 +0100

Preface

This article documents the XSS vulnerabilities that require attention in java code auditing.

Vulnerability Analysis of 0x01 XSS

XSS Generation

The background does not check or filter the user input, but directly returns the user input to the front. Causes javascript code to execute arbitrarily on the client side.

Code examples

public void Message(HttpServletRequest req, HttpServletResponse resp) {
        // TODO Auto-generated method stub
        String message = req.getParameter("msg");

        try {
            resp.getWriter().print(message);

        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

 }

The msg field obtained here is returned intact, and if it is js code, it will also parse the execution, causing reflective xss vulnerabilities;

Defense against XSS

Depending on the cause of the vulnerability, you can defend against it by filtering the input:

  • Enter escape for storage
  • Filter special characters
  • Special characters such as input limit < ` for the previous paragraph

Specific defenses can be:

  • Global filter, set filter:

    <filter>  
            <filter-name>XssSafe</filter-name>  
            <filter-class>XssFilter</filter-class>  
    </filter>  
    <filter-mapping>  
            <filter-name>XssSafe</filter-name>  
            <url-pattern>/*</url-pattern>  
    </filter-mapping>
    

    It is important to note here that our configuration is /* instead of /, < url-pattern>/</url-pattern> will match a path url like / login, not a pattern of *. A suffix URL such as jsp, and < url-pattern>/*</url-pattern> matches all urls: path-type and suffix-type URLs (including/login,*.jsp,*.js, and *.html).

    Then write the content of the filter, which is written on the Internet and can be used directly as follows:

    //XssFilter implementation:
    
    public class XssFilter implements Filter {
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
        }
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response,
                FilterChain chain) throws IOException, ServletException {
            chain.doFilter(new XssHttpServletRequestWrapper((HttpServletRequest) request), response);
        }
    
    }
    //XssHttpServletRequestWrapper implementation
    
    public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
    
        public XssHttpServletRequestWrapper(HttpServletRequest request) {
            super(request);
        }
    
        @SuppressWarnings("rawtypes")
        public Map<String,String[]> getParameterMap(){
            Map<String,String[]> request_map = super.getParameterMap();
            Iterator iterator = request_map.entrySet().iterator();
            while(iterator.hasNext()){
                Map.Entry me = (Map.Entry)iterator.next();
                String[] values = (String[])me.getValue();
                for(int i = 0 ; i < values.length ; i++){
                    values[i] = xssClean(values[i]);
                }
            }
    
            return request_map;
        }
         public String[] getParameterValues(String paramString)
          {
            String[] arrayOfString1 = super.getParameterValues(paramString);
            if (arrayOfString1 == null)
              return null;
            int i = arrayOfString1.length;
            String[] arrayOfString2 = new String[i];
            for (int j = 0; j < i; j++){
                arrayOfString2[j] = xssClean(arrayOfString1[j]);
            }
            return arrayOfString2;
          }
    
          public String getParameter(String paramString)
          {
            String str = super.getParameter(paramString);
            if (str == null)
              return null;
            return xssClean(str);
          }
    
          public String getHeader(String paramString)
          {
            String str = super.getHeader(paramString);
            if (str == null)
              return null;
            str = str.replaceAll("\r|\n", "");
            return xssClean(str);
          }
    
    
          private String xssClean(String value) {
            //ClassLoaderUtils.getResourceAsStream("classpath:antisamy-slashdot.xml", XssHttpServletRequestWrapper.class)
            if (value != null) {
                // NOTE: It's highly recommended to use the ESAPI library and
                // uncomment the following line to
                // avoid encoded attacks.
                // value = encoder.canonicalize(value);
                value = value.replaceAll("\0", "");
    
                // Avoid anything between script tags
                Pattern scriptPattern = Pattern.compile("<script>(.*?)</script>",
                        Pattern.CASE_INSENSITIVE);
                value = scriptPattern.matcher(value).replaceAll("");
    
                // Avoid anything in a src='...' type of expression
                scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\'(.*?)\\\'",
                        Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
                                | Pattern.DOTALL);
                value = scriptPattern.matcher(value).replaceAll("");
                // Avoid anything in a href='...' type of expression
                scriptPattern = Pattern.compile("href[\r\n]*=[\r\n]*\\\"(.*?)\\\"",
                                    Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
                                            | Pattern.DOTALL);
                value = scriptPattern.matcher(value).replaceAll("");
    
    
                // Remove any lonesome </script> tag
                scriptPattern = Pattern.compile("</script>",
                        Pattern.CASE_INSENSITIVE);
                value = scriptPattern.matcher(value).replaceAll("");
    
                // Remove any lonesome <script ...> tag
                scriptPattern = Pattern.compile("<script(.*?)>",
                        Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
                                | Pattern.DOTALL);
                value = scriptPattern.matcher(value).replaceAll("");
    
                // Avoid eval(...) expressions
                scriptPattern = Pattern.compile("eval\\((.*?)\\)",
                        Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
                                | Pattern.DOTALL);
                value = scriptPattern.matcher(value).replaceAll("");
    
                // Avoid expression(...) expressions
                scriptPattern = Pattern.compile("expression\\((.*?)\\)",
                        Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
                                | Pattern.DOTALL);
                value = scriptPattern.matcher(value).replaceAll("");
    
                // Avoid javascript:... expressions
                scriptPattern = Pattern.compile("javascript:",
                        Pattern.CASE_INSENSITIVE);
                value = scriptPattern.matcher(value).replaceAll("");
    
                // Avoid vbscript:... expressions
                scriptPattern = Pattern.compile("vbscript:",
                        Pattern.CASE_INSENSITIVE);
                value = scriptPattern.matcher(value).replaceAll("");
    
                // Avoid onload= expressions
                scriptPattern = Pattern.compile("onload(.*?)=",
                        Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
                                | Pattern.DOTALL);
                value = scriptPattern.matcher(value).replaceAll("");
            }  
              return value; 
              }
    }
    
  • Using the tool class xssProtect

    Download the corresponding jar package into the lib directory and import: https://code.google.com/archive/p/xssprotect/

    Simple usage:

    protectedAgainstXSS(String html){StringReader reader = new StringReader(html); StringWriter writer = new StringWriter();
      try {
          // Resolve incoming string from "html" variable
          HTMLParser.process( reader, writer, new XSSFilter(), true );
    
          // Returns parsed and processed strings
          return writer.toString();
      } catch (HandlingException e) {
      }
    }
    

    Specific ways of using can be referred to: https://www.iteye.com/blog/liuzidong-1744023

  • Most web attacks can be defended against using the ESAPI

    pom import:

    <dependency>
        <groupId>org.owasp.esapi</groupId>
        <artifactId>esapi</artifactId>
        <version>2.2.1.1</version>
    </dependency>
    

    Entity encoding occurs once before getting input parameters:

     public void Message(HttpServletRequest req, HttpServletResponse resp) {
            // TODO Auto-generated method stub
            String message = req.getParameter("msg");
            String s = ESAPI.encoder().encodeForHTML(message);  //Entity encoding
    
            try {
                resp.getWriter().print(s);
    
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
    
    }
    

0x02 Audit XSS Vulnerability

setAttribute

The setAttribute method is used to save the variable usage in the same request cycle and then take it out using the getAttribute method.

@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");// Set Response Type
        String content = request.getParameter("content");  //Get context pass-through parameter data
        request.setAttribute("content", content);  //content shared to request domain
        request.getRequestDispatcher("/WEB-INF/pages/xss.jsp").forward(request, response);  //Forward to xxs. In JSP page

    }
}

In jsp:

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

</body>
</html>

ModelAndView

ModelAndView can return parameters to the request scope of a specified page or specify the page name to be returned.

@RequestMapping("/test")
public ModelAndView test(){
    ModelAndView mav=new ModelAndView("hello");
    mav.addObject("time", new Date());
    mav.getModel().put("name", "caoyc");
    
    return mav;
}

In jsp:

time:${requestScope.time} <br/>
name:${name }

We can audit by observing if the parameters passed in from ModelAndView are controllable or if there is any filtering.

You can see that no matter which way you use it, you will need to take it out and output at the end, except <%out. Println(msg);%> Is the el expression, that is, in audit xss you can also start with the el expression.

Reference resources

https://xz.aliyun.com/t/6937

https://www.cnblogs.com/nice0e3/p/13655552.html