Headline
CVE-2022-39295: Improper Neutralization of Alternate XSS Syntax in KnowageLabs / Knowage-Server
Knowage is an open source suite for modern business analytics alternative over big data systems. KnowageLabs / Knowage-Server starting with the 6.x branch and prior to versions 7.4.22, 8.0.9, and 8.1.0 is vulnerable to cross-site scripting because the XSSRequestWrapper::stripXSS
method can be bypassed. Versions 7.4.22, 8.0.9, and 8.1.0 contain patches for this issue. There are no known workarounds.
The XSSRequestWrapper::stripXSS method can be bypassed.
public static String stripXSS(String value) {
logger.debug(“IN”);
String initialValue = value;
if (value != null) {
// NOTE: It’s highly recommended to use the ESAPI library and uncomment the following line to
// avoid encoded attacks.
// value = ESAPI.encoder().canonicalize(value);
// Avoid null characters
value = value.replaceAll("", “”);
// Avoid anything between script tags
Pattern scriptPattern = Pattern.compile("<script>(.*?)</script>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll(“”);
scriptPattern = Pattern.compile("<script>(.*?)</script>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll(“”);
// Avoid anything in a src=’…’ type of expression
// Pattern.compile("src[\r\n]*=[\r\n]*\\\’(.*?)\\\’", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
// value = scriptPattern.matcher(value).replaceAll(“”);
//
// scriptPattern = Pattern.compile(“src[\r\n]*=[\r\n]*\\\”(.*?)\\\"", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
// value = scriptPattern.matcher(value).replaceAll(“”);
value = checkImgTags(value);
value = checkIframeTags(value);
value = checkAnchorTags(value);
value = checkVideoTags(value);
value = checkCSS(value);
// Remove any lonesome </script> tag
scriptPattern = Pattern.compile("</script>", Pattern.CASE_INSENSITIVE);
value = scriptPattern.matcher(value).replaceAll(“”);
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(“”);
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(“”);
// Avoid onClick= expressions
scriptPattern = Pattern.compile("onClick(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll(“”);
// Avoid anything between form tags
Pattern formPattern = Pattern.compile("<form(.*?)</form>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = formPattern.matcher(value).replaceAll(“”);
// Avoid anything between a tags
// Pattern aPattern = Pattern.compile("<a(.*?)</a>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
// value = aPattern.matcher(value).replaceAll(“”);
// aPattern = Pattern.compile("<a(.*?/)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
// value = aPattern.matcher(value).replaceAll(“”);
Pattern aPattern = Pattern.compile("<a(.*?)</a>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = aPattern.matcher(value).replaceAll(“”);
// Avoid anything between button tags
Pattern buttonPattern = Pattern.compile("<button(.*?)</button>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = buttonPattern.matcher(value).replaceAll(“”);
buttonPattern = Pattern.compile("<button(.*?/)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = buttonPattern.matcher(value).replaceAll(“”);
buttonPattern = Pattern.compile("<button(.*?)</button>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = buttonPattern.matcher(value).replaceAll(“”);
// Example value ="<object data=\"javascript:alert(‘XSS’)\"></object>"
// Avoid anything between script tags
Pattern objectPattern = Pattern.compile("<object(.*?)</object>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = objectPattern.matcher(value).replaceAll(“”);
objectPattern = Pattern.compile("<object(.*?)</object>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = objectPattern.matcher(value).replaceAll(“”);
// Remove any lonesome </object> tag
objectPattern = Pattern.compile("</object>", Pattern.CASE_INSENSITIVE);
value = objectPattern.matcher(value).replaceAll(“”);
objectPattern = Pattern.compile("</object>", Pattern.CASE_INSENSITIVE);
value = objectPattern.matcher(value).replaceAll(“”);
// Remove any lonesome <object …> tag
objectPattern = Pattern.compile("<object(.*?/)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = objectPattern.matcher(value).replaceAll(“”);
objectPattern = Pattern.compile("<object(.*?/)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = objectPattern.matcher(value).replaceAll(“”);
if (!value.equalsIgnoreCase(initialValue)) {
logger.warn(“Message: detected a web attack through injection”);
}
}
logger.debug(“OUT”);
return value;
}
Fundamentally, attempting to filter for XSS payloads uniformly, as this logic attempts to do is, a fundamentally flawed protection strategy. The way that user-input strings need to be used (for example HTML escaped, or URL encoded) is context dependent and varies heavily depending upon where they are being rendered/used. This issue needs to be fixed closer to where the content is being rendered, instead of attempting to prevent XXS in the manner this method attempts.
Is there a way for users to fix or remediate the vulnerability without upgrading?