From c4e00077ca22c40c1079c7e63756b184dacba324 Mon Sep 17 00:00:00 2001 From: lostsnow Date: Tue, 11 Apr 2023 12:31:25 +0800 Subject: [PATCH 01/42] add policy tags/untags parsing from config --- .../models/policy/PolicyBuilder.java | 54 +++- .../models/policy/PolicyException.java | 1 + .../hookpoint/models/policy/PolicyTag.java | 279 ------------------ .../hookpoint/models/taint/tag/TaintTag.java | 35 ++- .../policy/tags/policy-tags-empty.json | 13 + .../policy/tags/policy-tags-invalid.json | 15 + .../tags/policy-tags-multi-has-dup.json | 15 + .../tags/policy-tags-multi-has-invalid.json | 15 + .../policy/tags/policy-tags-valid-multi.json | 15 + .../policy/tags/policy-tags-valid-single.json | 15 + .../models/policy/PolicyBuilderTest.java | 30 ++ .../main/java/io/dongtai/log/ErrorCode.java | 2 +- 12 files changed, 201 insertions(+), 288 deletions(-) delete mode 100644 dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyTag.java create mode 100644 dongtai-core/src/test/fixture/policy/tags/policy-tags-empty.json create mode 100644 dongtai-core/src/test/fixture/policy/tags/policy-tags-invalid.json create mode 100644 dongtai-core/src/test/fixture/policy/tags/policy-tags-multi-has-dup.json create mode 100644 dongtai-core/src/test/fixture/policy/tags/policy-tags-multi-has-invalid.json create mode 100644 dongtai-core/src/test/fixture/policy/tags/policy-tags-valid-multi.json create mode 100644 dongtai-core/src/test/fixture/policy/tags/policy-tags-valid-single.json diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyBuilder.java b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyBuilder.java index c6a9fd26b..b783631c3 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyBuilder.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyBuilder.java @@ -1,6 +1,7 @@ package io.dongtai.iast.core.handler.hookpoint.models.policy; import io.dongtai.iast.common.constants.ApiPath; +import io.dongtai.iast.core.handler.hookpoint.models.taint.tag.TaintTag; import io.dongtai.iast.core.handler.hookpoint.vulscan.VulnType; import io.dongtai.iast.core.utils.HttpClientUtils; import io.dongtai.iast.core.utils.StringUtils; @@ -21,6 +22,8 @@ public class PolicyBuilder { private static final String KEY_SIGNATURE = "signature"; private static final String KEY_INHERIT = "inherit"; private static final String KEY_VUL_TYPE = "vul_type"; + private static final String KEY_TAGS = "tags"; + private static final String KEY_UNTAGS = "untags"; private static final String KEY_COMMAND = "command"; private static final String KEY_IGNORE_INTERNAL = "ignore_internal"; private static final String KEY_IGNORE_BLACKLIST = "ignore_blacklist"; @@ -66,7 +69,7 @@ public static Policy build(JSONArray policyConfig) throws PolicyException { buildPropagator(policy, nodeType, node); buildSink(policy, nodeType, node); } catch (PolicyException e) { - DongTaiLog.warn(ErrorCode.get("POLICY_CONFIG_INVALID"), e.getMessage()); + DongTaiLog.warn(ErrorCode.get("POLICY_CONFIG_INVALID"), e); } } return policy; @@ -231,15 +234,52 @@ private static List parseTags(JSONObject node, PolicyNode policyNode) if (!(policyNode.getMethodMatcher() instanceof SignatureMethodMatcher)) { return empty; } - String signature = ((SignatureMethodMatcher) policyNode.getMethodMatcher()).getSignature().toString(); - // TODO: parse tags/untags from policy - List taintTags = PolicyTag.TAGS.get(signature); - if (taintTags == null || taintTags.size() != 2) { - return empty; + boolean hasInvalid = false; + List tags = new ArrayList(); + List untags = new ArrayList(); + try { + JSONArray ts = node.getJSONArray(KEY_TAGS); + for (Object o : ts) { + String t = (String) o; + if (TaintTag.UNTRUSTED.equals(t)) { + continue; + } + if (TaintTag.get(t) != null) { + tags.add(TaintTag.get(t).getKey()); + } else { + hasInvalid = true; + } + } + } catch (JSONException ignore) { + } + + try { + JSONArray uts = node.getJSONArray(KEY_UNTAGS); + for (Object o : uts) { + String ut = (String) o; + if (TaintTag.UNTRUSTED.equals(ut)) { + continue; + } + TaintTag tt = TaintTag.get(ut); + if (tt != null) { + if (tags.contains(tt.getKey())) { + hasInvalid = true; + } + untags.add(tt.getKey()); + } else { + hasInvalid = true; + } + } + } catch (JSONException ignore) { + } + + if (hasInvalid) { + DongTaiLog.warn(ErrorCode.get("POLICY_CONFIG_INVALID"), + new PolicyException(PolicyException.ERR_POLICY_NODE_TAGS_UNTAGS_INVALID + ": " + node.toString())); } - return taintTags; + return Arrays.asList(tags.toArray(new String[0]), untags.toArray(new String[0])); } private static void parseFlags(JSONObject node, PolicyNode policyNode) { diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyException.java b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyException.java index b04eda330..443e354a5 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyException.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyException.java @@ -12,6 +12,7 @@ public class PolicyException extends Exception { public static final String ERR_POLICY_NODE_SOURCE_INVALID = "policy node source is invalid"; public static final String ERR_POLICY_NODE_TARGET_INVALID = "policy node target is invalid"; public static final String ERR_POLICY_SINK_NODE_VUL_TYPE_INVALID = "policy sink node vul type is invalid"; + public static final String ERR_POLICY_NODE_TAGS_UNTAGS_INVALID = "policy node tags/untags has invalid config"; public PolicyException(String message) { super(message); diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyTag.java b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyTag.java deleted file mode 100644 index e6c0e64d7..000000000 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyTag.java +++ /dev/null @@ -1,279 +0,0 @@ -package io.dongtai.iast.core.handler.hookpoint.models.policy; - -import io.dongtai.iast.core.handler.hookpoint.models.taint.tag.TaintTag; - -import java.util.*; - -/** - * Policy tags - * TODO: parse tags/untags from policy - */ -public class PolicyTag { - public static final Map> TAGS = new HashMap>() {{ - String sign; - - // source javax HttpServletRequest - sign = "javax.servlet.http.HttpServletRequest.getReader()"; - put(sign, Arrays.asList(new String[]{TaintTag.CROSS_SITE.getKey()}, new String[0])); - sign = "javax.servlet.http.HttpServletRequest.getQueryString()"; - put(sign, Arrays.asList(new String[]{TaintTag.CROSS_SITE.getKey(), TaintTag.XSS_ENCODED.getKey()}, new String[0])); - sign = "javax.servlet.http.HttpServletRequest.getParts()"; - put(sign, Arrays.asList(new String[]{TaintTag.CROSS_SITE.getKey()}, new String[0])); - sign = "javax.servlet.http.HttpServletRequest.getPart(java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.CROSS_SITE.getKey()}, new String[0])); - sign = "javax.servlet.http.HttpServletRequest.getParameterValues(java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.CROSS_SITE.getKey()}, new String[0])); - sign = "javax.servlet.http.HttpServletRequest.getParameterNames()"; - put(sign, Arrays.asList(new String[]{TaintTag.CROSS_SITE.getKey()}, new String[0])); - sign = "javax.servlet.http.HttpServletRequest.getParameterMap()"; - put(sign, Arrays.asList(new String[]{TaintTag.CROSS_SITE.getKey()}, new String[0])); - sign = "javax.servlet.http.HttpServletRequest.getParameter(java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.CROSS_SITE.getKey()}, new String[0])); - sign = "javax.servlet.http.HttpServletRequest.getInputStream()"; - put(sign, Arrays.asList(new String[]{TaintTag.CROSS_SITE.getKey()}, new String[0])); - sign = "javax.servlet.http.HttpServletRequest.getHeaders(java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.CROSS_SITE.getKey()}, new String[0])); - // sign = "javax.servlet.http.HttpServletRequest.getHeaderNames()"; - // put(sign, Arrays.asList(new String[0], new String[0])); - sign = "javax.servlet.http.HttpServletRequest.getHeader(java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.CROSS_SITE.getKey()}, new String[0])); - // sign = "javax.servlet.http.HttpServletRequest.getCookies()"; - // put(sign, Arrays.asList(new String[0], new String[0])); - - // source jakarta HttpServletRequest - sign = "jakarta.servlet.http.HttpServletRequest.getParameter(java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.CROSS_SITE.getKey()}, new String[0])); - sign = "jakarta.servlet.http.HttpServletRequest.getQueryString()"; - put(sign, Arrays.asList(new String[]{TaintTag.CROSS_SITE.getKey(), TaintTag.XSS_ENCODED.getKey()}, new String[0])); - sign = "jakarta.servlet.http.HttpServletRequest.getParts()"; - put(sign, Arrays.asList(new String[]{TaintTag.CROSS_SITE.getKey()}, new String[0])); - sign = "jakarta.servlet.http.HttpServletRequest.getPart(java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.CROSS_SITE.getKey()}, new String[0])); - sign = "jakarta.servlet.http.HttpServletRequest.getHeaders(java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.CROSS_SITE.getKey()}, new String[0])); - // sign = "jakarta.servlet.http.HttpServletRequest.getHeaderNames()"; - // put(sign, Arrays.asList(new String[0], new String[0])); - sign = "jakarta.servlet.http.HttpServletRequest.getHeader(java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.CROSS_SITE.getKey()}, new String[0])); - // sign = "jakarta.servlet.http.HttpServletRequest.getCookies()"; - // put(sign, Arrays.asList(new String[0], new String[0])); - - // source javax ServletRequest - sign = "javax.servlet.ServletRequest.getReader()"; - put(sign, Arrays.asList(new String[]{TaintTag.CROSS_SITE.getKey()}, new String[0])); - sign = "javax.servlet.ServletRequest.getParameterValues(java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.CROSS_SITE.getKey()}, new String[0])); - sign = "javax.servlet.ServletRequest.getParameterNames()"; - put(sign, Arrays.asList(new String[]{TaintTag.CROSS_SITE.getKey()}, new String[0])); - sign = "javax.servlet.ServletRequest.getParameterMap()"; - put(sign, Arrays.asList(new String[]{TaintTag.CROSS_SITE.getKey()}, new String[0])); - sign = "javax.servlet.ServletRequest.getParameter(java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.CROSS_SITE.getKey()}, new String[0])); - sign = "javax.servlet.ServletRequest.getInputStream()"; - put(sign, Arrays.asList(new String[]{TaintTag.CROSS_SITE.getKey()}, new String[0])); - - // source jakarta ServletRequest - sign = "jakarta.servlet.ServletRequest.getReader()"; - put(sign, Arrays.asList(new String[]{TaintTag.CROSS_SITE.getKey()}, new String[0])); - sign = "jakarta.servlet.ServletRequest.getParameterValues(java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.CROSS_SITE.getKey()}, new String[0])); - sign = "jakarta.servlet.ServletRequest.getParameterNames()"; - put(sign, Arrays.asList(new String[]{TaintTag.CROSS_SITE.getKey()}, new String[0])); - sign = "jakarta.servlet.ServletRequest.getParameter(java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.CROSS_SITE.getKey()}, new String[0])); - sign = "jakarta.servlet.ServletRequest.getInputStream()"; - put(sign, Arrays.asList(new String[]{TaintTag.CROSS_SITE.getKey()}, new String[0])); - - // source springframework - sign = "org.springframework.web.util.pattern.PathPattern.getPatternString()"; - put(sign, Arrays.asList(new String[]{TaintTag.CROSS_SITE.getKey()}, new String[0])); - sign = "org.springframework.web.method.support.HandlerMethodArgumentResolver.resolveArgument(org.springframework.core.MethodParameter,org.springframework.web.method.support.ModelAndViewContainer,org.springframework.web.context.request.NativeWebRequest,org.springframework.web.bind.support.WebDataBinderFactory)"; - put(sign, Arrays.asList(new String[]{TaintTag.CROSS_SITE.getKey()}, new String[0])); - - // source fileupload - sign = " org.apache.commons.fileupload.FileUploadBase.parseRequest(org.apache.commons.fileupload.RequestContext)".substring(1); - put(sign, Arrays.asList(new String[]{TaintTag.CROSS_SITE.getKey()}, new String[0])); - - // html - sign = "sun.misc.CharacterEncoder.encode(java.io.InputStream,java.io.OutputStream)"; - put(sign, Arrays.asList(new String[]{TaintTag.HTML_ENCODED.getKey()}, new String[]{TaintTag.HTML_DECODED.getKey()})); - sign = "sun.misc.CharacterEncoder.encodeBuffer(java.io.InputStream,java.io.OutputStream)"; - put(sign, Arrays.asList(new String[]{TaintTag.HTML_ENCODED.getKey()}, new String[]{TaintTag.HTML_DECODED.getKey()})); - sign = "sun.misc.CharacterEncoder.decodeBuffer(java.io.InputStream,java.io.OutputStream)"; - put(sign, Arrays.asList(new String[]{TaintTag.HTML_DECODED.getKey()}, new String[]{TaintTag.HTML_ENCODED.getKey()})); - - // html springframework - sign = "org.springframework.web.util.HtmlUtils.htmlEscape(java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.HTML_ENCODED.getKey()}, new String[]{TaintTag.HTML_DECODED.getKey()})); - sign = "org.springframework.web.util.HtmlUtils.htmlEscape(java.lang.String,java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.HTML_ENCODED.getKey()}, new String[]{TaintTag.HTML_DECODED.getKey()})); - sign = "org.springframework.web.util.HtmlUtils.htmlEscapeDecimal(java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.HTML_ENCODED.getKey()}, new String[]{TaintTag.HTML_DECODED.getKey()})); - sign = "org.springframework.web.util.HtmlUtils.htmlEscapeDecimal(java.lang.String,java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.HTML_ENCODED.getKey()}, new String[]{TaintTag.HTML_DECODED.getKey()})); - sign = "org.springframework.web.util.HtmlUtils.htmlEscapeHex(java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.HTML_ENCODED.getKey()}, new String[]{TaintTag.HTML_DECODED.getKey()})); - sign = "org.springframework.web.util.HtmlUtils.htmlEscapeHex(java.lang.String,java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.HTML_ENCODED.getKey()}, new String[]{TaintTag.HTML_DECODED.getKey()})); - sign = "org.springframework.web.util.HtmlUtils.htmlUnescape(java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.HTML_DECODED.getKey()}, new String[]{TaintTag.HTML_ENCODED.getKey()})); - - // html apache - sign = " org.apache.commons.lang.StringEscapeUtils.escapeHtml(java.lang.String)".substring(1); - put(sign, Arrays.asList(new String[]{TaintTag.HTML_ENCODED.getKey()}, new String[]{TaintTag.HTML_DECODED.getKey()})); - sign = " org.apache.commons.lang.StringEscapeUtils.escapeHtml(java.io.Writer,java.lang.String)".substring(1); - put(sign, Arrays.asList(new String[]{TaintTag.HTML_ENCODED.getKey()}, new String[]{TaintTag.HTML_DECODED.getKey()})); - sign = " org.apache.commons.lang3.StringEscapeUtils.escapeHtml3(java.lang.String)".substring(1); - put(sign, Arrays.asList(new String[]{TaintTag.HTML_ENCODED.getKey()}, new String[]{TaintTag.HTML_DECODED.getKey()})); - sign = " org.apache.commons.lang3.StringEscapeUtils.escapeHtml4(java.lang.String)".substring(1); - put(sign, Arrays.asList(new String[]{TaintTag.HTML_ENCODED.getKey()}, new String[]{TaintTag.HTML_DECODED.getKey()})); - sign = " org.apache.commons.lang.StringEscapeUtils.unescapeHtml(java.lang.String)".substring(1); - put(sign, Arrays.asList(new String[]{TaintTag.HTML_DECODED.getKey()}, new String[]{TaintTag.HTML_ENCODED.getKey()})); - sign = " org.apache.commons.lang.StringEscapeUtils.unescapeHtml(java.io.Writer,java.lang.String)".substring(1); - put(sign, Arrays.asList(new String[]{TaintTag.HTML_DECODED.getKey()}, new String[]{TaintTag.HTML_ENCODED.getKey()})); - sign = " org.apache.commons.lang3.StringEscapeUtils.unescapeHtml3(java.lang.String)".substring(1); - put(sign, Arrays.asList(new String[]{TaintTag.HTML_DECODED.getKey()}, new String[]{TaintTag.HTML_ENCODED.getKey()})); - sign = " org.apache.commons.lang3.StringEscapeUtils.unescapeHtml4(java.lang.String)".substring(1); - put(sign, Arrays.asList(new String[]{TaintTag.HTML_DECODED.getKey()}, new String[]{TaintTag.HTML_ENCODED.getKey()})); - - // html unbescape - sign = "org.unbescape.html.HtmlEscapeUtil.escape(java.lang.String,org.unbescape.html.HtmlEscapeType,org.unbescape.html.HtmlEscapeLevel)"; - put(sign, Arrays.asList(new String[]{TaintTag.HTML_ENCODED.getKey()}, new String[]{TaintTag.HTML_DECODED.getKey()})); - sign = "org.unbescape.html.HtmlEscapeUtil.escape(java.io.Reader,java.io.Writer,org.unbescape.html.HtmlEscapeType,org.unbescape.html.HtmlEscapeLevel)"; - put(sign, Arrays.asList(new String[]{TaintTag.HTML_ENCODED.getKey()}, new String[]{TaintTag.HTML_DECODED.getKey()})); - sign = "org.unbescape.html.HtmlEscapeUtil.escape(char[],int,int,java.io.Writer,org.unbescape.html.HtmlEscapeType,org.unbescape.html.HtmlEscapeLevel)"; - put(sign, Arrays.asList(new String[]{TaintTag.HTML_ENCODED.getKey()}, new String[]{TaintTag.HTML_DECODED.getKey()})); - sign = "org.unbescape.html.HtmlEscapeUtil.unescape(java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.HTML_DECODED.getKey()}, new String[]{TaintTag.HTML_ENCODED.getKey()})); - sign = "org.unbescape.html.HtmlEscapeUtil.unescape(java.io.Reader,java.io.Writer)"; - put(sign, Arrays.asList(new String[]{TaintTag.HTML_DECODED.getKey()}, new String[]{TaintTag.HTML_ENCODED.getKey()})); - sign = "org.unbescape.html.HtmlEscapeUtil.unescape(char[],int,int,java.io.Writer)"; - put(sign, Arrays.asList(new String[]{TaintTag.HTML_DECODED.getKey()}, new String[]{TaintTag.HTML_ENCODED.getKey()})); - - // html owasp - sign = "org.owasp.validator.html.scan.AbstractAntiSamyScanner.scan(java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.HTML_ENCODED.getKey()}, new String[]{TaintTag.HTML_DECODED.getKey()})); - sign = "org.owasp.validator.html.CleanResults.getCleanHTML()"; - put(sign, Arrays.asList(new String[]{TaintTag.HTML_ENCODED.getKey()}, new String[]{TaintTag.HTML_DECODED.getKey()})); - sign = "org.owasp.validator.html.CleanResults.getCleanXMLDocumentFragment()"; - put(sign, Arrays.asList(new String[]{TaintTag.HTML_ENCODED.getKey()}, new String[]{TaintTag.HTML_DECODED.getKey()})); - sign = "org.owasp.esapi.Encoder.encodeForHTML(java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.HTML_ENCODED.getKey()}, new String[]{TaintTag.HTML_DECODED.getKey()})); - sign = "org.owasp.esapi.Encoder.encodeForHTMLAttribute(java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.HTML_ENCODED.getKey()}, new String[]{TaintTag.HTML_DECODED.getKey()})); - sign = "org.owasp.html.PolicyFactory.sanitize(java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.HTML_ENCODED.getKey()}, new String[]{TaintTag.HTML_DECODED.getKey()})); - sign = "org.owasp.encoder.Encode.forHtml(java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.HTML_ENCODED.getKey()}, new String[]{TaintTag.HTML_DECODED.getKey()})); - sign = "org.owasp.encoder.Encode.forHtmlAttribute(java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.HTML_ENCODED.getKey()}, new String[]{TaintTag.HTML_DECODED.getKey()})); - sign = "org.owasp.encoder.Encode.forHtmlContent(java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.HTML_ENCODED.getKey()}, new String[]{TaintTag.HTML_DECODED.getKey()})); - sign = "org.owasp.encoder.Encode.forHtmlUnquotedAttribute(java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.HTML_ENCODED.getKey()}, new String[]{TaintTag.HTML_DECODED.getKey()})); - sign = "org.owasp.esapi.Encoder.decodeForHTML(java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.HTML_DECODED.getKey()}, new String[]{TaintTag.HTML_ENCODED.getKey()})); - - // url - sign = "java.net.URLEncoder.encode(java.lang.String,java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.URL_ENCODED.getKey()}, new String[]{TaintTag.URL_DECODED.getKey()})); - sign = "java.net.URLEncoder.encode(java.lang.String,java.nio.charset.Charset)"; - put(sign, Arrays.asList(new String[]{TaintTag.URL_ENCODED.getKey()}, new String[]{TaintTag.URL_DECODED.getKey()})); - sign = "java.net.URLDecoder.decode(java.lang.String,java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.URL_DECODED.getKey()}, new String[]{TaintTag.URL_ENCODED.getKey(), TaintTag.XSS_ENCODED.getKey()})); - sign = "java.net.URLDecoder.decode(java.lang.String,java.nio.charset.Charset)"; - put(sign, Arrays.asList(new String[]{TaintTag.URL_DECODED.getKey()}, new String[]{TaintTag.URL_ENCODED.getKey(), TaintTag.XSS_ENCODED.getKey()})); - - // url javax HttpServletResponse - sign = "javax.servlet.http.HttpServletResponse.encodeUrl(java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.URL_ENCODED.getKey()}, new String[]{TaintTag.URL_DECODED.getKey()})); - sign = "javax.servlet.http.HttpServletResponse.encodeURL(java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.URL_ENCODED.getKey()}, new String[]{TaintTag.URL_DECODED.getKey()})); - sign = "javax.servlet.http.HttpServletResponse.encodeRedirectUrl(java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.URL_ENCODED.getKey()}, new String[]{TaintTag.URL_DECODED.getKey()})); - sign = "javax.servlet.http.HttpServletResponse.encodeRedirectURL(java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.URL_ENCODED.getKey()}, new String[]{TaintTag.URL_DECODED.getKey()})); - - // url springframework - sign = "org.springframework.web.util.UriUtils.encode(java.lang.String,java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.URL_ENCODED.getKey()}, new String[]{TaintTag.URL_DECODED.getKey()})); - sign = "org.springframework.web.util.UriUtils.encodeUri(java.lang.String,java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.URL_ENCODED.getKey()}, new String[]{TaintTag.URL_DECODED.getKey()})); - sign = "org.springframework.web.util.UriUtils.encodeHttpUrl(java.lang.String,java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.URL_ENCODED.getKey()}, new String[]{TaintTag.URL_DECODED.getKey()})); - sign = "org.springframework.web.util.UriUtils.encodeScheme(java.lang.String,java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.URL_ENCODED.getKey()}, new String[]{TaintTag.URL_DECODED.getKey()})); - sign = "org.springframework.web.util.UriUtils.encodeAuthority(java.lang.String,java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.URL_ENCODED.getKey()}, new String[]{TaintTag.URL_DECODED.getKey()})); - sign = "org.springframework.web.util.UriUtils.encodeUserInfo(java.lang.String,java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.URL_ENCODED.getKey()}, new String[]{TaintTag.URL_DECODED.getKey()})); - sign = "org.springframework.web.util.UriUtils.encodeHost(java.lang.String,java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.URL_ENCODED.getKey()}, new String[]{TaintTag.URL_DECODED.getKey()})); - sign = "org.springframework.web.util.UriUtils.encodePort(java.lang.String,java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.URL_ENCODED.getKey()}, new String[]{TaintTag.URL_DECODED.getKey()})); - sign = "org.springframework.web.util.UriUtils.encodePath(java.lang.String,java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.URL_ENCODED.getKey()}, new String[]{TaintTag.URL_DECODED.getKey()})); - sign = "org.springframework.web.util.UriUtils.encodePathSegment(java.lang.String,java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.URL_ENCODED.getKey()}, new String[]{TaintTag.URL_DECODED.getKey()})); - sign = "org.springframework.web.util.UriUtils.encodeQuery(java.lang.String,java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.URL_ENCODED.getKey()}, new String[]{TaintTag.URL_DECODED.getKey()})); - sign = "org.springframework.web.util.UriUtils.encodeQueryParam(java.lang.String,java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.URL_ENCODED.getKey()}, new String[]{TaintTag.URL_DECODED.getKey()})); - sign = "org.springframework.web.util.UriUtils.encodeFragment(java.lang.String,java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.URL_ENCODED.getKey()}, new String[]{TaintTag.URL_DECODED.getKey()})); - sign = "org.springframework.web.util.UriUtils.encode(java.lang.String,java.nio.charset.Charset)"; - put(sign, Arrays.asList(new String[]{TaintTag.URL_ENCODED.getKey()}, new String[]{TaintTag.URL_DECODED.getKey()})); - sign = "org.springframework.web.util.UriUtils.decode(java.lang.String,java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.URL_DECODED.getKey()}, new String[]{TaintTag.URL_ENCODED.getKey()})); - sign = "org.springframework.util.StringUtils.uriDecode(java.lang.String,java.nio.charset.Charset)"; - put(sign, Arrays.asList(new String[]{TaintTag.URL_DECODED.getKey()}, new String[]{TaintTag.URL_ENCODED.getKey()})); - - // url apache - sign = "org.apache.catalina.util.URLEncoder.encode(java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.URL_ENCODED.getKey()}, new String[]{TaintTag.URL_DECODED.getKey()})); - - // url owasp - sign = "org.owasp.esapi.Encoder.encodeForURL(java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.URL_ENCODED.getKey()}, new String[]{TaintTag.URL_DECODED.getKey()})); - sign = "org.owasp.encoder.Encode.forUri(java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.URL_ENCODED.getKey()}, new String[]{TaintTag.URL_DECODED.getKey()})); - sign = "org.owasp.encoder.Encode.forUri(java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.URL_ENCODED.getKey()}, new String[]{TaintTag.URL_DECODED.getKey()})); - sign = "org.owasp.esapi.Encoder.decodeFromURL(java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.URL_DECODED.getKey()}, new String[]{TaintTag.URL_ENCODED.getKey(), TaintTag.XSS_ENCODED.getKey()})); - - // base64 springframework - sign = "org.springframework.webflow.util.Base64.encode(byte[])"; - put(sign, Arrays.asList(new String[]{TaintTag.BASE64_ENCODED.getKey()}, new String[]{TaintTag.BASE64_DECODED.getKey()})); - sign = "org.springframework.webflow.util.Base64.encode(byte[],int,int)"; - put(sign, Arrays.asList(new String[]{TaintTag.BASE64_ENCODED.getKey()}, new String[]{TaintTag.BASE64_DECODED.getKey()})); - sign = "org.springframework.webflow.util.Base64.encodeToString(java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.BASE64_ENCODED.getKey()}, new String[]{TaintTag.BASE64_DECODED.getKey()})); - sign = "org.springframework.webflow.util.Base64.decode(byte[])"; - put(sign, Arrays.asList(new String[]{TaintTag.BASE64_DECODED.getKey()}, new String[]{TaintTag.BASE64_ENCODED.getKey()})); - sign = "org.springframework.webflow.util.Base64.decode(byte[],int,int)"; - put(sign, Arrays.asList(new String[]{TaintTag.BASE64_DECODED.getKey()}, new String[]{TaintTag.BASE64_ENCODED.getKey()})); - sign = "org.springframework.webflow.util.Base64.decodeFromString(java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.BASE64_DECODED.getKey()}, new String[]{TaintTag.BASE64_ENCODED.getKey()})); - - // base64 owasp - sign = "org.owasp.esapi.Encoder.encodeForBase64(byte[],boolean)"; - put(sign, Arrays.asList(new String[]{TaintTag.BASE64_ENCODED.getKey()}, new String[]{TaintTag.BASE64_DECODED.getKey()})); - sign = "org.owasp.esapi.codecs.Base64.encodeBytes(byte[])"; - put(sign, Arrays.asList(new String[]{TaintTag.BASE64_ENCODED.getKey()}, new String[]{TaintTag.BASE64_DECODED.getKey()})); - sign = "org.owasp.esapi.codecs.Base64.encodeBytes(byte[],int)"; - put(sign, Arrays.asList(new String[]{TaintTag.BASE64_ENCODED.getKey()}, new String[]{TaintTag.BASE64_DECODED.getKey()})); - sign = "org.owasp.esapi.codecs.Base64.encodeBytes(byte[],int,int)"; - put(sign, Arrays.asList(new String[]{TaintTag.BASE64_ENCODED.getKey()}, new String[]{TaintTag.BASE64_DECODED.getKey()})); - sign = "org.owasp.esapi.codecs.Base64.encodeBytes(byte[],int,int,int)"; - put(sign, Arrays.asList(new String[]{TaintTag.BASE64_ENCODED.getKey()}, new String[]{TaintTag.BASE64_DECODED.getKey()})); - sign = "org.owasp.esapi.Encoder.decodeFromBase64(java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.BASE64_DECODED.getKey()}, new String[]{TaintTag.BASE64_ENCODED.getKey()})); - sign = "org.owasp.esapi.codecs.Base64.decode(java.lang.String)"; - put(sign, Arrays.asList(new String[]{TaintTag.BASE64_DECODED.getKey()}, new String[]{TaintTag.BASE64_ENCODED.getKey()})); - sign = "org.owasp.esapi.codecs.Base64.decode(java.lang.String,int)"; - put(sign, Arrays.asList(new String[]{TaintTag.BASE64_DECODED.getKey()}, new String[]{TaintTag.BASE64_ENCODED.getKey()})); - sign = "org.owasp.esapi.codecs.Base64.decode(byte[],int,int,int)"; - put(sign, Arrays.asList(new String[]{TaintTag.BASE64_DECODED.getKey()}, new String[]{TaintTag.BASE64_ENCODED.getKey()})); - }}; -} diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/taint/tag/TaintTag.java b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/taint/tag/TaintTag.java index 67ddd5909..52e7b9b13 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/taint/tag/TaintTag.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/taint/tag/TaintTag.java @@ -1,5 +1,8 @@ package io.dongtai.iast.core.handler.hookpoint.models.taint.tag; +import java.util.HashMap; +import java.util.Map; + public enum TaintTag { UNTRUSTED("untrusted"), CROSS_SITE("cross-site"), @@ -10,10 +13,35 @@ public enum TaintTag { URL_DECODED("url-decoded"), BASE64_ENCODED("base64-encoded"), BASE64_DECODED("base64-decoded"), + JS_ENCODED("js-encoded"), + JS_DECODED("js-decoded"), + JSON_ENCODED("json-encoded"), + JSON_DECODED("json-decoded"), + XML_ENCODED("xml-encoded"), + XML_DECODED("xml-decoded"), + CSV_ENCODED("csv-encoded"), + CSV_DECODED("csv-decoded"), + SQL_ENCODED("sql-encoded"), + SQL_DECODED("sql-decoded"), + FTL_ENCODED("ftl-encoded"), + FTL_DECODED("ftl-decoded"), + CSS_ENCODED("css-encoded"), + XPATH_ENCODED("xpath-encoded"), + LDAP_ENCODED("ldap-encoded"), + OS_ENCODED("os-encoded"), + VBSCRIPT_ENCODED("vbscript-encoded"), ; private final String key; + private static final Map LOOKUP = new HashMap(); + + static { + for (TaintTag t : TaintTag.values()) { + LOOKUP.put(t.key, t); + } + } + TaintTag(String key) { this.key = key; } @@ -23,6 +51,11 @@ public String getKey() { } public boolean equals(String key) { - return this.key.equals(key); + return this.key.equalsIgnoreCase(key); + } + + public static TaintTag get(String name) { + name = name.toLowerCase(); + return LOOKUP.get(name); } } diff --git a/dongtai-core/src/test/fixture/policy/tags/policy-tags-empty.json b/dongtai-core/src/test/fixture/policy/tags/policy-tags-empty.json new file mode 100644 index 000000000..d89dc22fd --- /dev/null +++ b/dongtai-core/src/test/fixture/policy/tags/policy-tags-empty.json @@ -0,0 +1,13 @@ +{ + "status": 201, + "msg": "success", + "data": [ + { + "type": 1, + "signature": "A.b()", + "source": "P2", + "target": "O", + "inherit": "false" + } + ] +} \ No newline at end of file diff --git a/dongtai-core/src/test/fixture/policy/tags/policy-tags-invalid.json b/dongtai-core/src/test/fixture/policy/tags/policy-tags-invalid.json new file mode 100644 index 000000000..dcae282a9 --- /dev/null +++ b/dongtai-core/src/test/fixture/policy/tags/policy-tags-invalid.json @@ -0,0 +1,15 @@ +{ + "status": 201, + "msg": "success", + "data": [ + { + "type": 1, + "signature": "A.b()", + "source": "P2", + "target": "O", + "inherit": "false", + "tags": "foo", + "untags": "bar" + } + ] +} \ No newline at end of file diff --git a/dongtai-core/src/test/fixture/policy/tags/policy-tags-multi-has-dup.json b/dongtai-core/src/test/fixture/policy/tags/policy-tags-multi-has-dup.json new file mode 100644 index 000000000..54c538d86 --- /dev/null +++ b/dongtai-core/src/test/fixture/policy/tags/policy-tags-multi-has-dup.json @@ -0,0 +1,15 @@ +{ + "status": 201, + "msg": "success", + "data": [ + { + "type": 1, + "signature": "A.b()", + "source": "P2", + "target": "O", + "inherit": "false", + "tags": ["url-encoded", "html-encoded"], + "untags": ["url-decoded", "html-encoded"] + } + ] +} \ No newline at end of file diff --git a/dongtai-core/src/test/fixture/policy/tags/policy-tags-multi-has-invalid.json b/dongtai-core/src/test/fixture/policy/tags/policy-tags-multi-has-invalid.json new file mode 100644 index 000000000..0753c8ad2 --- /dev/null +++ b/dongtai-core/src/test/fixture/policy/tags/policy-tags-multi-has-invalid.json @@ -0,0 +1,15 @@ +{ + "status": 201, + "msg": "success", + "data": [ + { + "type": 1, + "signature": "A.b()", + "source": "P2", + "target": "O", + "inherit": "false", + "tags": ["url-encoded", "html-encoded", "foo", "untrusted"], + "untags": ["url-decoded", "html-decoded", "bar", "untrusted"] + } + ] +} \ No newline at end of file diff --git a/dongtai-core/src/test/fixture/policy/tags/policy-tags-valid-multi.json b/dongtai-core/src/test/fixture/policy/tags/policy-tags-valid-multi.json new file mode 100644 index 000000000..37b613907 --- /dev/null +++ b/dongtai-core/src/test/fixture/policy/tags/policy-tags-valid-multi.json @@ -0,0 +1,15 @@ +{ + "status": 201, + "msg": "success", + "data": [ + { + "type": 1, + "signature": "A.b()", + "source": "P2", + "target": "O", + "inherit": "false", + "tags": ["url-encoded", "html-encoded"], + "untags": ["url-decoded", "html-decoded"] + } + ] +} \ No newline at end of file diff --git a/dongtai-core/src/test/fixture/policy/tags/policy-tags-valid-single.json b/dongtai-core/src/test/fixture/policy/tags/policy-tags-valid-single.json new file mode 100644 index 000000000..829b49ba0 --- /dev/null +++ b/dongtai-core/src/test/fixture/policy/tags/policy-tags-valid-single.json @@ -0,0 +1,15 @@ +{ + "status": 201, + "msg": "success", + "data": [ + { + "type": 1, + "signature": "A.b()", + "source": "P2", + "target": "O", + "inherit": "false", + "tags": ["url-encoded"], + "untags": ["url-decoded"] + } + ] +} \ No newline at end of file diff --git a/dongtai-core/src/test/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyBuilderTest.java b/dongtai-core/src/test/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyBuilderTest.java index da5f31995..b711df5eb 100644 --- a/dongtai-core/src/test/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyBuilderTest.java +++ b/dongtai-core/src/test/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyBuilderTest.java @@ -1,5 +1,6 @@ package io.dongtai.iast.core.handler.hookpoint.models.policy; +import io.dongtai.iast.core.handler.hookpoint.models.taint.tag.TaintTag; import io.dongtai.iast.core.utils.PropertyUtils; import org.json.JSONArray; import org.junit.*; @@ -175,4 +176,33 @@ public void run() throws PolicyException { exception.getMessage().startsWith(entry.getValue())); } } + + @Test + public void testTags() throws PolicyException { + Map> tests = new HashMap>() {{ + put("tags/policy-tags-empty.json", Arrays.asList(new String[0], new String[0])); + put("tags/policy-tags-invalid.json", Arrays.asList(new String[0], new String[0])); + put("tags/policy-tags-valid-single.json", Arrays.asList( + new String[]{TaintTag.URL_ENCODED.getKey()}, new String[]{TaintTag.URL_DECODED.getKey()})); + put("tags/policy-tags-valid-multi.json", Arrays.asList( + new String[]{TaintTag.URL_ENCODED.getKey(), TaintTag.HTML_ENCODED.getKey()}, + new String[]{TaintTag.URL_DECODED.getKey(), TaintTag.HTML_DECODED.getKey()})); + put("tags/policy-tags-multi-has-invalid.json", Arrays.asList( + new String[]{TaintTag.URL_ENCODED.getKey(), TaintTag.HTML_ENCODED.getKey()}, + new String[]{TaintTag.URL_DECODED.getKey(), TaintTag.HTML_DECODED.getKey()})); + put("tags/policy-tags-multi-has-dup.json", Arrays.asList( + new String[]{TaintTag.URL_ENCODED.getKey(), TaintTag.HTML_ENCODED.getKey()}, + new String[]{TaintTag.URL_DECODED.getKey(), TaintTag.HTML_ENCODED.getKey()})); + }}; + for (Map.Entry> entry : tests.entrySet()) { + JSONArray policyConfig = PolicyBuilder.fetchFromFile(POLICY_DIR + entry.getKey()); + Policy policy = new Policy(); + PolicyBuilder.buildPropagator(policy, PolicyNodeType.PROPAGATOR, policyConfig.getJSONObject(0)); + Assert.assertEquals("tags/untags policy length " + entry.getKey(), 1, policy.getPolicyNodesMap().size()); + String[] tags = policy.getPropagators().get(0).getTags(); + String[] untags = policy.getPropagators().get(0).getUntags(); + Assert.assertArrayEquals("tags " + entry.getKey(), tags, entry.getValue().get(0)); + Assert.assertArrayEquals("untags " + entry.getKey(), untags, entry.getValue().get(1)); + } + } } \ No newline at end of file diff --git a/dongtai-log/src/main/java/io/dongtai/log/ErrorCode.java b/dongtai-log/src/main/java/io/dongtai/log/ErrorCode.java index 17142e6fa..91ab9a415 100644 --- a/dongtai-log/src/main/java/io/dongtai/log/ErrorCode.java +++ b/dongtai-log/src/main/java/io/dongtai/log/ErrorCode.java @@ -50,7 +50,7 @@ public enum ErrorCode { AGENT_MONITOR_GET_DISK_USAGE_FAILED(10413, "agent monitor get disk usage failed: {}, {}"), // fallback - AGENT_FALLBACK_SYNC_REMOTE_CONFIG_FAILED(10501, "agent fallback sync remote config failed"), + AGENT_FALLBACK_SYNC_REMOTE_CONFIG_FAILED(10501, "agent fallback sync remote config failed: {}, cause: {}"), AGENT_FALLBACK_METRICS_CONFIG_INVALID(10502, "agent fallback metrics config {} invalid: {}"), AGENT_FALLBACK_STATE_CHANGE_WITH_EXCEPTION(10503, "agent fallback state change to {}, but agent currently has exception"), AGENT_FALLBACK_CHECKER_CREATE_FAILED(10511, "agent fallback checker create failed: {}"), From dd90f5186c9685ce04220dbfdf57bdc45c692da8 Mon Sep 17 00:00:00 2001 From: lostsnow Date: Wed, 12 Apr 2023 15:20:26 +0800 Subject: [PATCH 02/42] add policy command parsing from config --- .../controller/impl/PropagatorImpl.java | 4 +- .../models/policy/PolicyBuilder.java | 65 +++- .../models/policy/PolicyException.java | 1 + .../models/policy/PropagatorNode.java | 34 +- .../models/taint/range/TaintCommand.java | 22 ++ .../taint/range/TaintCommandRunner.java | 304 +----------------- .../policy-append-p2-p3-0-with-space.json | 14 + .../policy/command/policy-append-p2-p3-0.json | 14 + .../policy/command/policy-append-p2-p3.json | 14 + .../policy/command/policy-command-empty.json | 13 + .../command/policy-command-invalid-args.json | 14 + .../command/policy-command-invalid-cmd.json | 14 + .../command/policy-command-invalid.json | 14 + .../command/policy-keep-empty-args.json | 14 + .../policy/command/policy-subset-0-p1.json | 14 + .../models/policy/PolicyBuilderTest.java | 39 ++- 16 files changed, 275 insertions(+), 319 deletions(-) create mode 100644 dongtai-core/src/test/fixture/policy/command/policy-append-p2-p3-0-with-space.json create mode 100644 dongtai-core/src/test/fixture/policy/command/policy-append-p2-p3-0.json create mode 100644 dongtai-core/src/test/fixture/policy/command/policy-append-p2-p3.json create mode 100644 dongtai-core/src/test/fixture/policy/command/policy-command-empty.json create mode 100644 dongtai-core/src/test/fixture/policy/command/policy-command-invalid-args.json create mode 100644 dongtai-core/src/test/fixture/policy/command/policy-command-invalid-cmd.json create mode 100644 dongtai-core/src/test/fixture/policy/command/policy-command-invalid.json create mode 100644 dongtai-core/src/test/fixture/policy/command/policy-keep-empty-args.json create mode 100644 dongtai-core/src/test/fixture/policy/command/policy-subset-0-p1.json diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/controller/impl/PropagatorImpl.java b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/controller/impl/PropagatorImpl.java index 5cef90c11..369f8e9ab 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/controller/impl/PropagatorImpl.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/controller/impl/PropagatorImpl.java @@ -45,7 +45,7 @@ private static void addPropagator(PropagatorNode propagatorNode, MethodEvent eve Set sources = propagatorNode.getSources(); Set targets = propagatorNode.getTargets(); - TaintCommandRunner r = TaintCommandRunner.getCommandRunner(event.signature); + TaintCommandRunner r = propagatorNode.getCommandRunner(); // O => O || O => R, source equals target and no change in taint range if (event.getSourceHashes().equals(event.getTargetHashes()) && sources.size() == 1 && targets.size() == 1 @@ -176,7 +176,7 @@ private static TaintRanges getTaintRanges(Object obj) { } private static void trackTaintRange(PropagatorNode propagatorNode, MethodEvent event) { - TaintCommandRunner r = TaintCommandRunner.getCommandRunner(event.signature); + TaintCommandRunner r = propagatorNode.getCommandRunner(); TaintRanges oldTaintRanges = new TaintRanges(); TaintRanges srcTaintRanges = new TaintRanges(); diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyBuilder.java b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyBuilder.java index b783631c3..b249fe001 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyBuilder.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyBuilder.java @@ -1,6 +1,8 @@ package io.dongtai.iast.core.handler.hookpoint.models.policy; import io.dongtai.iast.common.constants.ApiPath; +import io.dongtai.iast.core.handler.hookpoint.models.taint.range.TaintCommand; +import io.dongtai.iast.core.handler.hookpoint.models.taint.range.TaintCommandRunner; import io.dongtai.iast.core.handler.hookpoint.models.taint.tag.TaintTag; import io.dongtai.iast.core.handler.hookpoint.vulscan.VulnType; import io.dongtai.iast.core.utils.HttpClientUtils; @@ -99,12 +101,12 @@ public static void buildPropagator(Policy policy, PolicyNodeType type, JSONObjec Set sources = parseSource(node, type); Set targets = parseTarget(node, type); MethodMatcher methodMatcher = buildMethodMatcher(node); - // @TODO: command - PropagatorNode propagatorNode = new PropagatorNode(sources, targets, null, new String[]{}, methodMatcher); + PropagatorNode propagatorNode = new PropagatorNode(sources, targets, methodMatcher); setInheritable(node, propagatorNode); List tags = parseTags(node, propagatorNode); propagatorNode.setTags(tags.get(0)); propagatorNode.setUntags(tags.get(1)); + parseCommand(node, propagatorNode); parseFlags(node, propagatorNode); policy.addPropagator(propagatorNode); } @@ -282,6 +284,65 @@ private static List parseTags(JSONObject node, PolicyNode policyNode) return Arrays.asList(tags.toArray(new String[0]), untags.toArray(new String[0])); } + private static void parseCommand(JSONObject node, PropagatorNode propagatorNode) { + try { + String cmdConfig = node.getString(KEY_COMMAND); + if (cmdConfig == null) { + return; + } + cmdConfig = cmdConfig.trim(); + if (cmdConfig.isEmpty()) { + return; + } + + boolean isInvalid = false; + int parametersStartIndex = cmdConfig.indexOf("("); + int parametersEndIndex = cmdConfig.indexOf(")"); + + if (parametersStartIndex <= 2 || parametersEndIndex <= 3 + || parametersStartIndex > parametersEndIndex + || parametersEndIndex != cmdConfig.length() - 1) { + isInvalid = true; + } else { + String cmd = cmdConfig.substring(0, parametersStartIndex).trim(); + String argumentsStr = cmdConfig.substring(parametersStartIndex + 1, parametersEndIndex).trim(); + String[] arguments = new String[]{}; + if (!argumentsStr.isEmpty()) { + argumentsStr = argumentsStr.toUpperCase(); + arguments = argumentsStr.replace(" ", "").split(","); + for (String argument : arguments) { + String dig = argument; + if (dig.startsWith("P")) { + dig = dig.substring(1); + } + if (!dig.matches("\\d+")) { + isInvalid = true; + break; + } + } + } + + TaintCommand command = TaintCommand.get(cmd); + if (command == null) { + isInvalid = true; + } else { + if (!(propagatorNode.getMethodMatcher() instanceof SignatureMethodMatcher)) { + return; + } + String signature = ((SignatureMethodMatcher) propagatorNode.getMethodMatcher()).getSignature().toString(); + TaintCommandRunner commandRunner = TaintCommandRunner.create(signature, command, arguments); + propagatorNode.setCommandRunner(commandRunner); + } + } + + if (isInvalid) { + DongTaiLog.warn(ErrorCode.get("POLICY_CONFIG_INVALID"), + new PolicyException(PolicyException.ERR_POLICY_NODE_RANGE_COMMAND_INVALID + ": " + node.toString())); + } + } catch (JSONException ignore) { + } + } + private static void parseFlags(JSONObject node, PolicyNode policyNode) { try { boolean ignoreInternal = node.getBoolean(KEY_IGNORE_INTERNAL); diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyException.java b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyException.java index 443e354a5..aa1a0201b 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyException.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyException.java @@ -13,6 +13,7 @@ public class PolicyException extends Exception { public static final String ERR_POLICY_NODE_TARGET_INVALID = "policy node target is invalid"; public static final String ERR_POLICY_SINK_NODE_VUL_TYPE_INVALID = "policy sink node vul type is invalid"; public static final String ERR_POLICY_NODE_TAGS_UNTAGS_INVALID = "policy node tags/untags has invalid config"; + public static final String ERR_POLICY_NODE_RANGE_COMMAND_INVALID = "policy node range command is invalid"; public PolicyException(String message) { super(message); diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PropagatorNode.java b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PropagatorNode.java index e5ac751a8..8b955ceb4 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PropagatorNode.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PropagatorNode.java @@ -1,22 +1,18 @@ package io.dongtai.iast.core.handler.hookpoint.models.policy; -import io.dongtai.iast.core.handler.hookpoint.models.taint.range.TaintCommand; +import io.dongtai.iast.core.handler.hookpoint.models.taint.range.TaintCommandRunner; import java.util.Set; public class PropagatorNode extends TaintFlowNode { private Set sources; - private TaintCommand command; - private String[] commandArguments; + private TaintCommandRunner commandRunner; private String[] tags; private String[] untags; - public PropagatorNode(Set sources, Set targets, - TaintCommand command, String[] commandArguments, MethodMatcher methodMatcher) { + public PropagatorNode(Set sources, Set targets, MethodMatcher methodMatcher) { super(targets, methodMatcher); this.sources = sources; - this.command = command; - this.commandArguments = commandArguments; } @Override @@ -32,22 +28,6 @@ public void setSources(Set sources) { this.sources = sources; } - public TaintCommand getCommand() { - return this.command; - } - - public void setCommand(TaintCommand command) { - this.command = command; - } - - public String[] getCommandArguments() { - return this.commandArguments; - } - - public void setCommandArguments(String[] commandArguments) { - this.commandArguments = commandArguments; - } - public String[] getTags() { return this.tags; } @@ -67,4 +47,12 @@ public String[] getUntags() { public void setUntags(String[] untags) { this.untags = untags; } + + public TaintCommandRunner getCommandRunner() { + return this.commandRunner; + } + + public void setCommandRunner(TaintCommandRunner r) { + this.commandRunner = r; + } } diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/taint/range/TaintCommand.java b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/taint/range/TaintCommand.java index 261524312..a269fb535 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/taint/range/TaintCommand.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/taint/range/TaintCommand.java @@ -1,5 +1,10 @@ package io.dongtai.iast.core.handler.hookpoint.models.taint.range; +import io.dongtai.iast.core.utils.StringUtils; + +import java.util.HashMap; +import java.util.Map; + public enum TaintCommand { KEEP, APPEND, @@ -11,4 +16,21 @@ public enum TaintCommand { TRIM, TRIM_RIGHT, TRIM_LEFT, + ; + + private static final Map LOOKUP = new HashMap(); + + static { + for (TaintCommand t : TaintCommand.values()) { + LOOKUP.put(t.name(), t); + } + } + + public static TaintCommand get(String cmd) { + if (StringUtils.isEmpty(cmd)) { + return null; + } + cmd = cmd.toUpperCase(); + return LOOKUP.get(cmd); + } } diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/taint/range/TaintCommandRunner.java b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/taint/range/TaintCommandRunner.java index a977c9758..97b5dd204 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/taint/range/TaintCommandRunner.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/taint/range/TaintCommandRunner.java @@ -4,7 +4,8 @@ import io.dongtai.log.DongTaiLog; import io.dongtai.log.ErrorCode; -import java.util.*; +import java.util.ArrayList; +import java.util.List; public class TaintCommandRunner { private String signature; @@ -13,12 +14,14 @@ public class TaintCommandRunner { private TaintCommand command; - private List params = new ArrayList(); + private final List params = new ArrayList(); + + private final List origParams = new ArrayList(); private int paramsCount = 0; static class RunnerParam { - private int position; + private final int position; private boolean isLiteral = false; public RunnerParam(String param) { @@ -50,16 +53,17 @@ public static TaintCommandRunner create(String signature, TaintCommand command) return create(signature, command, null); } - public static TaintCommandRunner create(String signature, TaintCommand command, List params) { + public static TaintCommandRunner create(String signature, TaintCommand command, String[] params) { try { TaintCommandRunner r = new TaintCommandRunner(); r.signature = signature; r.builder = new TaintRangesBuilder(); r.command = command; - if (params != null) { - r.paramsCount = params.size(); + if (params != null && params.length > 0) { + r.paramsCount = params.length; for (String param : params) { r.params.add(new RunnerParam(param)); + r.origParams.add(param); } } return r; @@ -72,6 +76,10 @@ public TaintRangesBuilder getTaintRangesBuilder() { return this.builder; } + public List getOrigParams() { + return origParams; + } + public TaintRanges run(PropagatorNode propagatorNode, Object source, Object target, Object[] params, TaintRanges oldTaintRanges, TaintRanges srcTaintRanges) { int p1 = 0; @@ -141,288 +149,4 @@ public TaintRanges run(PropagatorNode propagatorNode, Object source, Object targ return tr; } - - public static TaintCommandRunner getCommandRunner(String signature) { - return RUNNER_MAP.get(signature); - } - - private static final Map RUNNER_MAP = new HashMap() {{ - // KEEP String - String METHOD = "java.lang.String.(java.lang.String)"; - put(METHOD, create(METHOD, TaintCommand.KEEP)); // P1=>O - METHOD = "java.lang.String.(java.lang.StringBuilder)"; - put(METHOD, create(METHOD, TaintCommand.KEEP)); // P1=>O - METHOD = "java.lang.String.(java.lang.StringBuffer)"; - put(METHOD, create(METHOD, TaintCommand.KEEP)); // P1=>O - METHOD = "java.lang.String.(byte[],int,int)"; - put(METHOD, create(METHOD, TaintCommand.KEEP)); // P1=>O - METHOD = "java.lang.String.(byte[],int,int,int)"; - put(METHOD, create(METHOD, TaintCommand.KEEP)); // P1=>O - METHOD = "java.lang.String.(byte[],int,int,java.lang.String)"; - put(METHOD, create(METHOD, TaintCommand.KEEP)); // P1=>O - METHOD = "java.lang.String.(char[])"; - put(METHOD, create(METHOD, TaintCommand.KEEP)); // P1=>O - METHOD = "java.lang.String.(byte[],java.nio.charset.Charset)"; - put(METHOD, create(METHOD, TaintCommand.KEEP)); // P1=>O - METHOD = "java.lang.String.(byte[],byte)"; // Java-17 - put(METHOD, create(METHOD, TaintCommand.KEEP)); // P1=>O - METHOD = "java.lang.String.toLowerCase(java.util.Locale)"; - put(METHOD, create(METHOD, TaintCommand.KEEP)); // O=>R - METHOD = "java.lang.String.toUpperCase(java.util.Locale)"; - put(METHOD, create(METHOD, TaintCommand.KEEP)); // O=>R - METHOD = "java.lang.String.getBytes()"; - put(METHOD, create(METHOD, TaintCommand.KEEP)); // O=>R - METHOD = "java.lang.String.getBytes(java.lang.String)"; - put(METHOD, create(METHOD, TaintCommand.KEEP)); // O=>R - METHOD = "java.lang.String.getBytes(java.nio.charset.Charset)"; - put(METHOD, create(METHOD, TaintCommand.KEEP)); // O=>R - METHOD = "java.lang.String.toCharArray()"; - put(METHOD, create(METHOD, TaintCommand.KEEP)); // O=>R - - // KEEP StringBuilder - METHOD = "java.lang.StringBuilder.toString()"; - put(METHOD, create(METHOD, TaintCommand.KEEP)); // O=>R - METHOD = "java.lang.StringBuilder.(java.lang.String)"; - put(METHOD, create(METHOD, TaintCommand.KEEP)); // P1=>O - METHOD = "java.lang.StringBuilder.(java.lang.CharSequence)"; - put(METHOD, create(METHOD, TaintCommand.KEEP)); // P1=>O - - // KEEP StringBuffer - METHOD = "java.lang.StringBuffer.toString()"; - put(METHOD, create(METHOD, TaintCommand.KEEP)); // O=>R - METHOD = "java.lang.StringBuffer.(java.lang.String)"; - put(METHOD, create(METHOD, TaintCommand.KEEP)); // P1=>O - METHOD = "java.lang.StringBuffer.(java.lang.CharSequence)"; - put(METHOD, create(METHOD, TaintCommand.KEEP)); // P1=>O - - // KEEP ByteArrayOutputStream - METHOD = "java.io.ByteArrayOutputStream.toByteArray()"; - put(METHOD, create(METHOD, TaintCommand.KEEP)); // O=>R - METHOD = "java.io.ByteArrayOutputStream.toString()"; - put(METHOD, create(METHOD, TaintCommand.KEEP)); // O=>R - METHOD = "java.io.ByteArrayOutputStream.toString(java.lang.String)"; - put(METHOD, create(METHOD, TaintCommand.KEEP)); // O=>R - METHOD = "java.io.ByteArrayOutputStream.toString(int)"; - put(METHOD, create(METHOD, TaintCommand.KEEP)); // O=>R - METHOD = "java.io.ByteArrayOutputStream.toString(java.nio.charset.Charset)"; - put(METHOD, create(METHOD, TaintCommand.KEEP)); // O=>R - - // KEEP StringConcatHelper - METHOD = "java.lang.StringConcatHelper.newString(byte[],int,byte)"; // Java 9-11 - put(METHOD, create(METHOD, TaintCommand.KEEP)); // P1=>R - METHOD = "java.lang.StringConcatHelper.newString(byte[],long)"; // Java 12+, up to 14 - put(METHOD, create(METHOD, TaintCommand.KEEP)); // P1=>R - - // KEEP StringWriter - METHOD = "java.io.StringWriter.toString()"; - put(METHOD, create(METHOD, TaintCommand.KEEP)); // O=>R - - // KEEP - METHOD = "okhttp3.internal.HostnamesKt.toCanonicalHost(java.lang.String)"; - put(METHOD, create(METHOD, TaintCommand.KEEP)); // P1=>R - - // APPEND String - METHOD = "java.lang.String.(char[],int,int)"; - put(METHOD, create(METHOD, TaintCommand.APPEND, Arrays.asList("P2", "P3", "0"))); // P1=>O - METHOD = "java.lang.String.(char[],int,int,boolean)"; // in IBM JDK8 split() - put(METHOD, create(METHOD, TaintCommand.APPEND, Arrays.asList("P2", "P3", "0"))); // P1=>O - - // APPEND StringLatin1/StringUTF16 - METHOD = "java.lang.StringLatin1.newString(byte[],int,int)"; // Java-11 - put(METHOD, create(METHOD, TaintCommand.APPEND, Arrays.asList("P2", "P3", "0"))); // P1=>R - METHOD = "java.lang.StringUTF16.newString(byte[],int,int)"; // Java-11 - put(METHOD, create(METHOD, TaintCommand.APPEND, Arrays.asList("P2", "P3", "0"))); // P1=>R - - // APPEND StringBuilder - METHOD = "java.lang.StringBuilder.append(java.lang.String)"; - put(METHOD, create(METHOD, TaintCommand.APPEND)); // P1=>O - METHOD = "java.lang.StringBuilder.append(java.lang.StringBuffer)"; - put(METHOD, create(METHOD, TaintCommand.APPEND)); // P1=>O - METHOD = "java.lang.StringBuilder.append(java.lang.CharSequence)"; - put(METHOD, create(METHOD, TaintCommand.APPEND)); // P1=>O - METHOD = "java.lang.StringBuilder.append(java.lang.CharSequence,int,int)"; - put(METHOD, create(METHOD, TaintCommand.APPEND, Arrays.asList("P2", "P3"))); // P1=>O - METHOD = "java.lang.StringBuilder.append(char[],int,int)"; - put(METHOD, create(METHOD, TaintCommand.APPEND, Arrays.asList("P2", "P3", "0"))); // P1=>O - - // APPEND AbstractStringBuilder - METHOD = "java.lang.AbstractStringBuilder.append(java.lang.String)"; - put(METHOD, create(METHOD, TaintCommand.APPEND)); // P1=>O - - // APPEND StringBuffer - METHOD = "java.lang.StringBuffer.append(java.lang.String)"; - put(METHOD, create(METHOD, TaintCommand.APPEND)); // P1=>O - METHOD = "java.lang.StringBuffer.append(java.lang.StringBuffer)"; - put(METHOD, create(METHOD, TaintCommand.APPEND)); // P1=>O - METHOD = "java.lang.StringBuffer.append(char[])"; - put(METHOD, create(METHOD, TaintCommand.APPEND)); // P1=>O - METHOD = "java.lang.StringBuffer.append(java.lang.CharSequence)"; - put(METHOD, create(METHOD, TaintCommand.APPEND)); // P1=>O - METHOD = "java.lang.StringBuffer.append(java.lang.CharSequence,int,int)"; - put(METHOD, create(METHOD, TaintCommand.APPEND, Arrays.asList("P2", "P3"))); // P1=>O - METHOD = "java.lang.StringBuffer.append(char[],int,int)"; - put(METHOD, create(METHOD, TaintCommand.APPEND, Arrays.asList("P2", "P3", "0"))); // P1=>O - - // APPEND ByteArrayOutputStream - METHOD = "java.io.ByteArrayOutputStream.write(byte[],int,int)"; - put(METHOD, create(METHOD, TaintCommand.APPEND, Arrays.asList("P2", "P3"))); // P1=>O - - // APPEND apache ByteArrayOutputStream - METHOD = " org.apache.commons.io.output.ByteArrayOutputStream.write(byte[],int,int)".substring(1); - put(METHOD, create(METHOD, TaintCommand.APPEND, Arrays.asList("P2", "P3"))); // P1=>O - - // APPEND StringWriter - METHOD = "java.io.StringWriter.write(char[],int,int)"; - put(METHOD, create(METHOD, TaintCommand.APPEND, Arrays.asList("P2", "P3", "0"))); // P1=>O - METHOD = "java.io.StringWriter.write(java.lang.String)"; - put(METHOD, create(METHOD, TaintCommand.APPEND)); - METHOD = "java.io.StringWriter.write(java.lang.String,int,int)"; - put(METHOD, create(METHOD, TaintCommand.APPEND, Arrays.asList("P2", "P3"))); - - // SUBSET String - METHOD = "java.lang.String.substring(int)"; - put(METHOD, create(METHOD, TaintCommand.SUBSET, Collections.singletonList("P1"))); // O=>R - METHOD = "java.lang.String.substring(int,int)"; - put(METHOD, create(METHOD, TaintCommand.SUBSET, Arrays.asList("P1", "P2"))); // O=>R - METHOD = "java.lang.String.getBytes(int,int,byte[],int)"; - put(METHOD, create(METHOD, TaintCommand.SUBSET, Arrays.asList("P1", "P2", "P4"))); // O=>P3 - METHOD = "java.lang.String.getChars(int,int,char[],int)"; - put(METHOD, create(METHOD, TaintCommand.SUBSET, Arrays.asList("P1", "P2", "P4"))); // O=>P3 - METHOD = "java.lang.String.(byte[],int,int,java.nio.charset.Charset)"; - put(METHOD, create(METHOD, TaintCommand.SUBSET, Arrays.asList("P2", "P3"))); // P1=>O - - // SUBSET StringLatin1/StringUTF16 LinesSpliterator - METHOD = "java.lang.StringLatin1$LinesSpliterator.(byte[],int,int)"; // Java-11 - put(METHOD, create(METHOD, TaintCommand.SUBSET, Arrays.asList("P2", "P3"))); // P1=>O - METHOD = "java.lang.StringUTF16$LinesSpliterator.(byte[],int,int)"; // Java-11 - put(METHOD, create(METHOD, TaintCommand.SUBSET, Arrays.asList("P2", "P3"))); // P1=>O - - // SUBSET StringBuilder - METHOD = "java.lang.StringBuilder.substring(int)"; - put(METHOD, create(METHOD, TaintCommand.SUBSET, Collections.singletonList("P1"))); // O=>R - METHOD = "java.lang.StringBuilder.substring(int,int)"; - put(METHOD, create(METHOD, TaintCommand.SUBSET, Arrays.asList("P1", "P2"))); // O=>R - METHOD = "java.lang.StringBuilder.setLength(int)"; - put(METHOD, create(METHOD, TaintCommand.SUBSET, Arrays.asList("0", "P1"))); // O=>O - METHOD = "java.lang.StringBuilder.getChars(int,int,char[],int)"; - put(METHOD, create(METHOD, TaintCommand.SUBSET, Arrays.asList("P1", "P2", "P4"))); // O=>P3 - - // SUBSET AbstractStringBuilder - METHOD = "java.lang.AbstractStringBuilder.substring(int)"; - put(METHOD, create(METHOD, TaintCommand.SUBSET, Collections.singletonList("P1"))); // O=>R - METHOD = "java.lang.AbstractStringBuilder.substring(int,int)"; - put(METHOD, create(METHOD, TaintCommand.SUBSET, Arrays.asList("P1", "P2"))); // O=>R - METHOD = "java.lang.AbstractStringBuilder.setLength(int)"; - put(METHOD, create(METHOD, TaintCommand.SUBSET, Arrays.asList("0", "P1"))); // O=>O - METHOD = "java.lang.AbstractStringBuilder.getChars(int,int,char[],int)"; - put(METHOD, create(METHOD, TaintCommand.SUBSET, Arrays.asList("P1", "P2", "P4"))); // O=>P3 - - // SUBSET StringBuffer - METHOD = "java.lang.StringBuffer.substring(int)"; - put(METHOD, create(METHOD, TaintCommand.SUBSET, Collections.singletonList("P1"))); // O=>R - METHOD = "java.lang.StringBuffer.substring(int,int)"; - put(METHOD, create(METHOD, TaintCommand.SUBSET, Arrays.asList("P1", "P2"))); // O=>R - METHOD = "java.lang.StringBuffer.setLength(int)"; - put(METHOD, create(METHOD, TaintCommand.SUBSET, Arrays.asList("0", "P1"))); // O=>O - METHOD = "java.lang.StringBuffer.getChars(int,int,char[],int)"; - put(METHOD, create(METHOD, TaintCommand.SUBSET, Arrays.asList("P1", "P2", "P4"))); // O=>P3 - - // SUBSET ByteBuffer - METHOD = "java.nio.ByteBuffer.wrap(byte[],int,int)"; - put(METHOD, create(METHOD, TaintCommand.SUBSET, Arrays.asList("P2", "P3"))); // P1=>R - - // SUBSET Arrays - METHOD = "java.util.Arrays.copyOf(byte[],int)"; - put(METHOD, create(METHOD, TaintCommand.SUBSET, Arrays.asList("0", "P2"))); // P1=>R - METHOD = "java.util.Arrays.copyOfRange(byte[],int,int)"; - put(METHOD, create(METHOD, TaintCommand.SUBSET, Arrays.asList("P2", "P3"))); // P1=>R - METHOD = "java.util.Arrays.copyOf(char[],int)"; - put(METHOD, create(METHOD, TaintCommand.SUBSET, Arrays.asList("0", "P2"))); // P1=>R - METHOD = "java.util.Arrays.copyOfRange(char[],int,int)"; - put(METHOD, create(METHOD, TaintCommand.SUBSET, Arrays.asList("P2", "P3"))); // P1=>R - - // SUBSET - METHOD = "okhttp3.HttpUrl$Companion.percentDecode$okhttp(java.lang.String,int,int,boolean)"; - put(METHOD, create(METHOD, TaintCommand.SUBSET, Arrays.asList("P2", "P3"))); // P1=>R - METHOD = "okhttp3.HttpUrl$Builder.canonicalizeHost(java.lang.String,int,int)"; - put(METHOD, create(METHOD, TaintCommand.SUBSET, Arrays.asList("P2", "P3"))); // P1=>R - METHOD = "com.squareup.okhttp.HttpUrl$Builder.canonicalizeHost(java.lang.String,int,int)"; - put(METHOD, create(METHOD, TaintCommand.SUBSET, Arrays.asList("P2", "P3"))); // P1=>R - - // INSERT CharArrayReader/PipedReader/PipedInputStream - METHOD = "java.io.CharArrayReader.(char[],int,int)"; - put(METHOD, create(METHOD, TaintCommand.INSERT, Arrays.asList("0", "P2", "P3"))); // P1=>O - METHOD = "java.io.CharArrayReader.read(char[],int,int)"; - put(METHOD, create(METHOD, TaintCommand.INSERT, Arrays.asList("0", "P2", "P3"))); // O=>P1 - METHOD = "java.io.PipedReader.read(char[],int,int)"; - put(METHOD, create(METHOD, TaintCommand.INSERT, Arrays.asList("0", "P2", "P3"))); - METHOD = "java.io.PipedInputStream.read(byte[],int,int)"; - put(METHOD, create(METHOD, TaintCommand.INSERT, Arrays.asList("0", "P2", "P3"))); - - // INSERT StringBuilder - METHOD = "java.lang.StringBuilder.insert(int,java.lang.String)"; - put(METHOD, create(METHOD, TaintCommand.INSERT, Collections.singletonList("P1"))); // P2=>O - METHOD = "java.lang.StringBuilder.insert(int,char[])"; - put(METHOD, create(METHOD, TaintCommand.INSERT, Collections.singletonList("P1"))); // P2=>O - METHOD = "java.lang.StringBuilder.insert(int,char)"; - put(METHOD, create(METHOD, TaintCommand.INSERT, Collections.singletonList("P1"))); // P2=>O - METHOD = "java.lang.StringBuilder.insert(int,java.lang.CharSequence)"; - put(METHOD, create(METHOD, TaintCommand.INSERT, Collections.singletonList("P1"))); // P2=>O - METHOD = "java.lang.StringBuilder.insert(int,java.lang.CharSequence,int,int)"; - put(METHOD, create(METHOD, TaintCommand.INSERT, Arrays.asList("P1", "P3", "P4"))); // P2=>O - METHOD = "java.lang.StringBuilder.insert(int,char[],int,int)"; - put(METHOD, create(METHOD, TaintCommand.INSERT, Arrays.asList("P1", "P3", "P4"))); // P2=>O - - // INSERT StringBuffer - METHOD = "java.lang.StringBuffer.insert(int,java.lang.String)"; - put(METHOD, create(METHOD, TaintCommand.INSERT, Collections.singletonList("P1"))); // P2=>O - METHOD = "java.lang.StringBuffer.insert(int,char[])"; - put(METHOD, create(METHOD, TaintCommand.INSERT, Collections.singletonList("P1"))); // P2=>O - METHOD = "java.lang.StringBuffer.insert(int,char)"; - put(METHOD, create(METHOD, TaintCommand.INSERT, Collections.singletonList("P1"))); // P2=>O - METHOD = "java.lang.StringBuffer.insert(int,java.lang.CharSequence)"; - put(METHOD, create(METHOD, TaintCommand.INSERT, Collections.singletonList("P1"))); // P2=>O - METHOD = "java.lang.StringBuffer.insert(int,java.lang.CharSequence,int,int)"; - put(METHOD, create(METHOD, TaintCommand.INSERT, Arrays.asList("P1", "P3", "P4"))); // P2=>O - METHOD = "java.lang.StringBuffer.insert(int,char[],int,int)"; - put(METHOD, create(METHOD, TaintCommand.INSERT, Arrays.asList("P1", "P3", "P4"))); // P2=>O - - // REPLACE - METHOD = "java.lang.StringBuilder.replace(int,int,java.lang.String)"; - put(METHOD, create(METHOD, TaintCommand.REPLACE, Arrays.asList("P1", "P2"))); // P3=>O - METHOD = "java.lang.StringBuffer.replace(int,int,java.lang.String)"; - put(METHOD, create(METHOD, TaintCommand.REPLACE, Arrays.asList("P1", "P2"))); // P3=>O - - // REMOVE StringBuilder - METHOD = "java.lang.StringBuilder.delete(int,int)"; - put(METHOD, create(METHOD, TaintCommand.REMOVE, Arrays.asList("P1", "P2"))); // O=>O - METHOD = "java.lang.StringBuilder.deleteCharAt(int)"; - put(METHOD, create(METHOD, TaintCommand.REMOVE, Collections.singletonList("P1"))); // O=>O - - // REMOVE StringBuffer - METHOD = "java.lang.StringBuffer.delete(int,int)"; - put(METHOD, create(METHOD, TaintCommand.REMOVE, Arrays.asList("P1", "P2"))); // O=>O - METHOD = "java.lang.StringBuffer.deleteCharAt(int)"; - put(METHOD, create(METHOD, TaintCommand.REMOVE, Collections.singletonList("P1"))); // O=>O - - // REMOVE ByteArrayOutputStream/apache ByteArrayOutputStream - METHOD = "java.io.ByteArrayOutputStream.reset()"; - put(METHOD, create(METHOD, TaintCommand.REMOVE)); // O=>O - METHOD = " org.apache.commons.io.output.ByteArrayOutputStream.reset()".substring(1); - put(METHOD, create(METHOD, TaintCommand.REMOVE)); // O=>O - - // CONCAT String - METHOD = "java.lang.String.concat(java.lang.String)"; - put(METHOD, create(METHOD, TaintCommand.CONCAT)); // O|P1=>R - - // TRIM String - METHOD = "java.lang.String.strip()"; // Java-11 - put(METHOD, create(METHOD, TaintCommand.TRIM)); - METHOD = "java.lang.String.stripLeading()"; // Java-11 - put(METHOD, create(METHOD, TaintCommand.TRIM_LEFT)); - METHOD = "java.lang.String.stripTrailing()"; // Java-11 - put(METHOD, create(METHOD, TaintCommand.TRIM_RIGHT)); - METHOD = "java.lang.String.trim()"; - put(METHOD, create(METHOD, TaintCommand.TRIM)); - }}; } diff --git a/dongtai-core/src/test/fixture/policy/command/policy-append-p2-p3-0-with-space.json b/dongtai-core/src/test/fixture/policy/command/policy-append-p2-p3-0-with-space.json new file mode 100644 index 000000000..6e59f9f2e --- /dev/null +++ b/dongtai-core/src/test/fixture/policy/command/policy-append-p2-p3-0-with-space.json @@ -0,0 +1,14 @@ +{ + "status": 201, + "msg": "success", + "data": [ + { + "type": 1, + "signature": "A.b()", + "source": "P2", + "target": "O", + "inherit": "false", + "command": " appEND ( p2 , P3 , 0 ) " + } + ] +} \ No newline at end of file diff --git a/dongtai-core/src/test/fixture/policy/command/policy-append-p2-p3-0.json b/dongtai-core/src/test/fixture/policy/command/policy-append-p2-p3-0.json new file mode 100644 index 000000000..f662a9c82 --- /dev/null +++ b/dongtai-core/src/test/fixture/policy/command/policy-append-p2-p3-0.json @@ -0,0 +1,14 @@ +{ + "status": 201, + "msg": "success", + "data": [ + { + "type": 1, + "signature": "A.b()", + "source": "P2", + "target": "O", + "inherit": "false", + "command": "APPEND(P2,P3,0)" + } + ] +} \ No newline at end of file diff --git a/dongtai-core/src/test/fixture/policy/command/policy-append-p2-p3.json b/dongtai-core/src/test/fixture/policy/command/policy-append-p2-p3.json new file mode 100644 index 000000000..c8616c6f5 --- /dev/null +++ b/dongtai-core/src/test/fixture/policy/command/policy-append-p2-p3.json @@ -0,0 +1,14 @@ +{ + "status": 201, + "msg": "success", + "data": [ + { + "type": 1, + "signature": "A.b()", + "source": "P2", + "target": "O", + "inherit": "false", + "command": "APPEND(P2,P3)" + } + ] +} \ No newline at end of file diff --git a/dongtai-core/src/test/fixture/policy/command/policy-command-empty.json b/dongtai-core/src/test/fixture/policy/command/policy-command-empty.json new file mode 100644 index 000000000..d89dc22fd --- /dev/null +++ b/dongtai-core/src/test/fixture/policy/command/policy-command-empty.json @@ -0,0 +1,13 @@ +{ + "status": 201, + "msg": "success", + "data": [ + { + "type": 1, + "signature": "A.b()", + "source": "P2", + "target": "O", + "inherit": "false" + } + ] +} \ No newline at end of file diff --git a/dongtai-core/src/test/fixture/policy/command/policy-command-invalid-args.json b/dongtai-core/src/test/fixture/policy/command/policy-command-invalid-args.json new file mode 100644 index 000000000..232ca38a0 --- /dev/null +++ b/dongtai-core/src/test/fixture/policy/command/policy-command-invalid-args.json @@ -0,0 +1,14 @@ +{ + "status": 201, + "msg": "success", + "data": [ + { + "type": 1, + "signature": "A.b()", + "source": "P2", + "target": "O", + "inherit": "false", + "command": "foo(bar)" + } + ] +} \ No newline at end of file diff --git a/dongtai-core/src/test/fixture/policy/command/policy-command-invalid-cmd.json b/dongtai-core/src/test/fixture/policy/command/policy-command-invalid-cmd.json new file mode 100644 index 000000000..8a0437172 --- /dev/null +++ b/dongtai-core/src/test/fixture/policy/command/policy-command-invalid-cmd.json @@ -0,0 +1,14 @@ +{ + "status": 201, + "msg": "success", + "data": [ + { + "type": 1, + "signature": "A.b()", + "source": "P2", + "target": "O", + "inherit": "false", + "command": "foo()" + } + ] +} \ No newline at end of file diff --git a/dongtai-core/src/test/fixture/policy/command/policy-command-invalid.json b/dongtai-core/src/test/fixture/policy/command/policy-command-invalid.json new file mode 100644 index 000000000..e47c83c0e --- /dev/null +++ b/dongtai-core/src/test/fixture/policy/command/policy-command-invalid.json @@ -0,0 +1,14 @@ +{ + "status": 201, + "msg": "success", + "data": [ + { + "type": 1, + "signature": "A.b()", + "source": "P2", + "target": "O", + "inherit": "false", + "command": "foo" + } + ] +} \ No newline at end of file diff --git a/dongtai-core/src/test/fixture/policy/command/policy-keep-empty-args.json b/dongtai-core/src/test/fixture/policy/command/policy-keep-empty-args.json new file mode 100644 index 000000000..60353ebca --- /dev/null +++ b/dongtai-core/src/test/fixture/policy/command/policy-keep-empty-args.json @@ -0,0 +1,14 @@ +{ + "status": 201, + "msg": "success", + "data": [ + { + "type": 1, + "signature": "A.b()", + "source": "P2", + "target": "O", + "inherit": "false", + "command": "KEEP()" + } + ] +} \ No newline at end of file diff --git a/dongtai-core/src/test/fixture/policy/command/policy-subset-0-p1.json b/dongtai-core/src/test/fixture/policy/command/policy-subset-0-p1.json new file mode 100644 index 000000000..72ef57f9a --- /dev/null +++ b/dongtai-core/src/test/fixture/policy/command/policy-subset-0-p1.json @@ -0,0 +1,14 @@ +{ + "status": 201, + "msg": "success", + "data": [ + { + "type": 1, + "signature": "A.b()", + "source": "P2", + "target": "O", + "inherit": "false", + "command": "SUBSET(0,P1)" + } + ] +} \ No newline at end of file diff --git a/dongtai-core/src/test/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyBuilderTest.java b/dongtai-core/src/test/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyBuilderTest.java index b711df5eb..4e18eec62 100644 --- a/dongtai-core/src/test/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyBuilderTest.java +++ b/dongtai-core/src/test/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyBuilderTest.java @@ -1,5 +1,7 @@ package io.dongtai.iast.core.handler.hookpoint.models.policy; +import io.dongtai.iast.core.handler.hookpoint.models.taint.range.TaintCommand; +import io.dongtai.iast.core.handler.hookpoint.models.taint.range.TaintCommandRunner; import io.dongtai.iast.core.handler.hookpoint.models.taint.tag.TaintTag; import io.dongtai.iast.core.utils.PropertyUtils; import org.json.JSONArray; @@ -201,8 +203,41 @@ public void testTags() throws PolicyException { Assert.assertEquals("tags/untags policy length " + entry.getKey(), 1, policy.getPolicyNodesMap().size()); String[] tags = policy.getPropagators().get(0).getTags(); String[] untags = policy.getPropagators().get(0).getUntags(); - Assert.assertArrayEquals("tags " + entry.getKey(), tags, entry.getValue().get(0)); - Assert.assertArrayEquals("untags " + entry.getKey(), untags, entry.getValue().get(1)); + Assert.assertArrayEquals("tags " + entry.getKey(), entry.getValue().get(0), tags); + Assert.assertArrayEquals("untags " + entry.getKey(), entry.getValue().get(1), untags); + } + } + + @Test + public void testCommand() throws PolicyException { + Map tests = new HashMap() {{ + put("command/policy-command-empty.json", null); + put("command/policy-command-invalid.json", null); + put("command/policy-command-invalid-cmd.json", null); + put("command/policy-command-invalid-args.json", null); + put("command/policy-keep-empty-args.json", TaintCommandRunner.create("", + TaintCommand.KEEP, new String[0])); + put("command/policy-append-p2-p3.json", TaintCommandRunner.create("", TaintCommand.APPEND, + new String[]{"P2", "P3"})); + put("command/policy-append-p2-p3-0.json", TaintCommandRunner.create("", TaintCommand.APPEND, + new String[]{"P2", "P3", "0"})); + put("command/policy-append-p2-p3-0-with-space.json", TaintCommandRunner.create("", TaintCommand.APPEND, + new String[]{"P2", "P3", "0"})); + put("command/policy-subset-0-p1.json", TaintCommandRunner.create("", TaintCommand.SUBSET, + new String[]{"0", "P1"})); + }}; + for (Map.Entry entry : tests.entrySet()) { + JSONArray policyConfig = PolicyBuilder.fetchFromFile(POLICY_DIR + entry.getKey()); + Policy policy = new Policy(); + PolicyBuilder.buildPropagator(policy, PolicyNodeType.PROPAGATOR, policyConfig.getJSONObject(0)); + TaintCommandRunner r = policy.getPropagators().get(0).getCommandRunner(); + if (entry.getValue() == null) { + Assert.assertNull(r); + } else { + Assert.assertEquals("policy command " + entry.getKey(), entry.getValue().getCommand(), r.getCommand()); + Assert.assertEquals("policy command args " + entry.getKey(), + entry.getValue().getOrigParams(), r.getOrigParams()); + } } } } \ No newline at end of file From 6f5b9186289e7e70fc70ae315b72fc8506a49b95 Mon Sep 17 00:00:00 2001 From: lostsnow Date: Wed, 12 Apr 2023 17:38:35 +0800 Subject: [PATCH 03/42] add policy stack blacklist parsing from config --- .../models/policy/PolicyBuilder.java | 180 ++++++++++-------- .../models/policy/PolicyException.java | 1 + .../hookpoint/models/policy/SinkNode.java | 4 + .../command/policy-command-invalid-type.json | 14 ++ .../policy-stack-blacklist-empty.json | 13 ++ ...cy-stack-blacklist-invalid-type-value.json | 17 ++ .../policy-stack-blacklist-invalid-type.json | 14 ++ .../policy-stack-blacklist-invalid.json | 14 ++ .../policy-stack-blacklist-valid-empty.json | 14 ++ .../policy-stack-blacklist-valid.json | 17 ++ .../policy-tags-invalid-type-tags-value.json | 15 ++ .../tags/policy-tags-invalid-type-tags.json | 15 ++ ...policy-tags-invalid-type-untags-value.json | 15 ++ .../tags/policy-tags-invalid-type-untags.json | 15 ++ .../policy/tags/policy-tags-valid-empty.json | 15 ++ .../models/policy/PolicyBuilderTest.java | 84 +++++++- 16 files changed, 362 insertions(+), 85 deletions(-) create mode 100644 dongtai-core/src/test/fixture/policy/command/policy-command-invalid-type.json create mode 100644 dongtai-core/src/test/fixture/policy/stack-blacklist/policy-stack-blacklist-empty.json create mode 100644 dongtai-core/src/test/fixture/policy/stack-blacklist/policy-stack-blacklist-invalid-type-value.json create mode 100644 dongtai-core/src/test/fixture/policy/stack-blacklist/policy-stack-blacklist-invalid-type.json create mode 100644 dongtai-core/src/test/fixture/policy/stack-blacklist/policy-stack-blacklist-invalid.json create mode 100644 dongtai-core/src/test/fixture/policy/stack-blacklist/policy-stack-blacklist-valid-empty.json create mode 100644 dongtai-core/src/test/fixture/policy/stack-blacklist/policy-stack-blacklist-valid.json create mode 100644 dongtai-core/src/test/fixture/policy/tags/policy-tags-invalid-type-tags-value.json create mode 100644 dongtai-core/src/test/fixture/policy/tags/policy-tags-invalid-type-tags.json create mode 100644 dongtai-core/src/test/fixture/policy/tags/policy-tags-invalid-type-untags-value.json create mode 100644 dongtai-core/src/test/fixture/policy/tags/policy-tags-invalid-type-untags.json create mode 100644 dongtai-core/src/test/fixture/policy/tags/policy-tags-valid-empty.json diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyBuilder.java b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyBuilder.java index b249fe001..5e85585fe 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyBuilder.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyBuilder.java @@ -27,6 +27,7 @@ public class PolicyBuilder { private static final String KEY_TAGS = "tags"; private static final String KEY_UNTAGS = "untags"; private static final String KEY_COMMAND = "command"; + private static final String KEY_STACK_BLACKLIST = "stack_blacklist"; private static final String KEY_IGNORE_INTERNAL = "ignore_internal"; private static final String KEY_IGNORE_BLACKLIST = "ignore_blacklist"; @@ -126,7 +127,7 @@ public static void buildSink(Policy policy, PolicyNodeType type, JSONObject node } setInheritable(node, sinkNode); sinkNode.setVulType(vulType); - sinkNode.setStackDenyList(parseStackDenyList(sinkNode)); + parseStackDenyList(node, sinkNode); parseFlags(node, sinkNode); policy.addSink(sinkNode); } @@ -214,21 +215,20 @@ private static MethodMatcher buildMethodMatcher(JSONObject node) throws PolicyEx /** * stack deny list for sink node - * TODO: parse stack deny list from policy */ - private static String[] parseStackDenyList(SinkNode node) { - if (!(node.getMethodMatcher() instanceof SignatureMethodMatcher)) { - return new String[0]; - } - - String signature = ((SignatureMethodMatcher) node.getMethodMatcher()).getSignature().toString(); - if ("java.lang.Class.forName(java.lang.String)".equals(signature)) { - return new String[]{"java.net.URL.getURLStreamHandler"}; - } else if ("java.lang.Class.forName(java.lang.String,boolean,java.lang.ClassLoader)".equals(signature)) { - return new String[]{"org.jruby.javasupport.JavaSupport.loadJavaClass"}; + private static void parseStackDenyList(JSONObject node, SinkNode sinkNode) { + try { + if (node.has(KEY_STACK_BLACKLIST)) { + JSONArray arr = node.getJSONArray(KEY_STACK_BLACKLIST); + sinkNode.setStackDenyList(arr.toList().toArray(new String[0])); + } + } catch (JSONException ignore) { + DongTaiLog.warn(ErrorCode.get("POLICY_CONFIG_INVALID"), + new PolicyException(PolicyException.ERR_POLICY_NODE_STACK_BLACKLIST_INVALID + ": " + node.toString())); + } catch (ArrayStoreException ignore) { + DongTaiLog.warn(ErrorCode.get("POLICY_CONFIG_INVALID"), + new PolicyException(PolicyException.ERR_POLICY_NODE_STACK_BLACKLIST_INVALID + ": " + node.toString())); } - - return new String[0]; } private static List parseTags(JSONObject node, PolicyNode policyNode) { @@ -241,39 +241,49 @@ private static List parseTags(JSONObject node, PolicyNode policyNode) List tags = new ArrayList(); List untags = new ArrayList(); try { - JSONArray ts = node.getJSONArray(KEY_TAGS); - for (Object o : ts) { - String t = (String) o; - if (TaintTag.UNTRUSTED.equals(t)) { - continue; - } - if (TaintTag.get(t) != null) { - tags.add(TaintTag.get(t).getKey()); - } else { - hasInvalid = true; + if (node.has(KEY_TAGS)) { + JSONArray ts = node.getJSONArray(KEY_TAGS); + for (Object o : ts) { + String t = (String) o; + if (TaintTag.UNTRUSTED.equals(t)) { + continue; + } + if (TaintTag.get(t) != null) { + tags.add(TaintTag.get(t).getKey()); + } else { + hasInvalid = true; + } } } } catch (JSONException ignore) { + hasInvalid = true; + } catch (ClassCastException ignore) { + hasInvalid = true; } try { - JSONArray uts = node.getJSONArray(KEY_UNTAGS); - for (Object o : uts) { - String ut = (String) o; - if (TaintTag.UNTRUSTED.equals(ut)) { - continue; - } - TaintTag tt = TaintTag.get(ut); - if (tt != null) { - if (tags.contains(tt.getKey())) { + if (node.has(KEY_TAGS)) { + JSONArray uts = node.getJSONArray(KEY_UNTAGS); + for (Object o : uts) { + String ut = (String) o; + if (TaintTag.UNTRUSTED.equals(ut)) { + continue; + } + TaintTag tt = TaintTag.get(ut); + if (tt != null) { + if (tags.contains(tt.getKey())) { + hasInvalid = true; + } + untags.add(tt.getKey()); + } else { hasInvalid = true; } - untags.add(tt.getKey()); - } else { - hasInvalid = true; } } } catch (JSONException ignore) { + hasInvalid = true; + } catch (ClassCastException ignore) { + hasInvalid = true; } if (hasInvalid) { @@ -286,60 +296,64 @@ private static List parseTags(JSONObject node, PolicyNode policyNode) private static void parseCommand(JSONObject node, PropagatorNode propagatorNode) { try { - String cmdConfig = node.getString(KEY_COMMAND); - if (cmdConfig == null) { - return; - } - cmdConfig = cmdConfig.trim(); - if (cmdConfig.isEmpty()) { - return; - } - - boolean isInvalid = false; - int parametersStartIndex = cmdConfig.indexOf("("); - int parametersEndIndex = cmdConfig.indexOf(")"); - - if (parametersStartIndex <= 2 || parametersEndIndex <= 3 - || parametersStartIndex > parametersEndIndex - || parametersEndIndex != cmdConfig.length() - 1) { - isInvalid = true; - } else { - String cmd = cmdConfig.substring(0, parametersStartIndex).trim(); - String argumentsStr = cmdConfig.substring(parametersStartIndex + 1, parametersEndIndex).trim(); - String[] arguments = new String[]{}; - if (!argumentsStr.isEmpty()) { - argumentsStr = argumentsStr.toUpperCase(); - arguments = argumentsStr.replace(" ", "").split(","); - for (String argument : arguments) { - String dig = argument; - if (dig.startsWith("P")) { - dig = dig.substring(1); - } - if (!dig.matches("\\d+")) { - isInvalid = true; - break; - } - } + if (node.has(KEY_COMMAND)) { + String cmdConfig = node.getString(KEY_COMMAND); + if (cmdConfig == null) { + return; } + cmdConfig = cmdConfig.trim(); + if (cmdConfig.isEmpty()) { + return; + } + + boolean isInvalid = false; + int parametersStartIndex = cmdConfig.indexOf("("); + int parametersEndIndex = cmdConfig.indexOf(")"); - TaintCommand command = TaintCommand.get(cmd); - if (command == null) { + if (parametersStartIndex <= 2 || parametersEndIndex <= 3 + || parametersStartIndex > parametersEndIndex + || parametersEndIndex != cmdConfig.length() - 1) { isInvalid = true; } else { - if (!(propagatorNode.getMethodMatcher() instanceof SignatureMethodMatcher)) { - return; + String cmd = cmdConfig.substring(0, parametersStartIndex).trim(); + String argumentsStr = cmdConfig.substring(parametersStartIndex + 1, parametersEndIndex).trim(); + String[] arguments = new String[]{}; + if (!argumentsStr.isEmpty()) { + argumentsStr = argumentsStr.toUpperCase(); + arguments = argumentsStr.replace(" ", "").split(","); + for (String argument : arguments) { + String dig = argument; + if (dig.startsWith("P")) { + dig = dig.substring(1); + } + if (!dig.matches("\\d+")) { + isInvalid = true; + break; + } + } + } + + TaintCommand command = TaintCommand.get(cmd); + if (command == null) { + isInvalid = true; + } else { + if (!(propagatorNode.getMethodMatcher() instanceof SignatureMethodMatcher)) { + return; + } + String signature = ((SignatureMethodMatcher) propagatorNode.getMethodMatcher()).getSignature().toString(); + TaintCommandRunner commandRunner = TaintCommandRunner.create(signature, command, arguments); + propagatorNode.setCommandRunner(commandRunner); } - String signature = ((SignatureMethodMatcher) propagatorNode.getMethodMatcher()).getSignature().toString(); - TaintCommandRunner commandRunner = TaintCommandRunner.create(signature, command, arguments); - propagatorNode.setCommandRunner(commandRunner); } - } - if (isInvalid) { - DongTaiLog.warn(ErrorCode.get("POLICY_CONFIG_INVALID"), - new PolicyException(PolicyException.ERR_POLICY_NODE_RANGE_COMMAND_INVALID + ": " + node.toString())); + if (isInvalid) { + DongTaiLog.warn(ErrorCode.get("POLICY_CONFIG_INVALID"), + new PolicyException(PolicyException.ERR_POLICY_NODE_RANGE_COMMAND_INVALID + ": " + node.toString())); + } } } catch (JSONException ignore) { + DongTaiLog.warn(ErrorCode.get("POLICY_CONFIG_INVALID"), + new PolicyException(PolicyException.ERR_POLICY_NODE_RANGE_COMMAND_INVALID + ": " + node.toString())); } } @@ -347,6 +361,10 @@ private static void parseFlags(JSONObject node, PolicyNode policyNode) { try { boolean ignoreInternal = node.getBoolean(KEY_IGNORE_INTERNAL); policyNode.setIgnoreInternal(ignoreInternal); + } catch (JSONException ignore) { + } + + try { boolean ignoreBlackList = node.getBoolean(KEY_IGNORE_BLACKLIST); policyNode.setIgnoreBlacklist(ignoreBlackList); } catch (JSONException ignore) { diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyException.java b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyException.java index aa1a0201b..a005a30d1 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyException.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyException.java @@ -14,6 +14,7 @@ public class PolicyException extends Exception { public static final String ERR_POLICY_SINK_NODE_VUL_TYPE_INVALID = "policy sink node vul type is invalid"; public static final String ERR_POLICY_NODE_TAGS_UNTAGS_INVALID = "policy node tags/untags has invalid config"; public static final String ERR_POLICY_NODE_RANGE_COMMAND_INVALID = "policy node range command is invalid"; + public static final String ERR_POLICY_NODE_STACK_BLACKLIST_INVALID = "policy node stack blacklist is invalid"; public PolicyException(String message) { super(message); diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/SinkNode.java b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/SinkNode.java index 84d7e2d80..3a240d29e 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/SinkNode.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/SinkNode.java @@ -33,6 +33,10 @@ public void setVulType(String vulType) { this.vulType = vulType; } + public String[] getStackDenyList() { + return this.stackDenyList; + } + public boolean hasDenyStack(StackTraceElement[] stackTraceElements) { if (this.stackDenyList == null || this.stackDenyList.length == 0) { return false; diff --git a/dongtai-core/src/test/fixture/policy/command/policy-command-invalid-type.json b/dongtai-core/src/test/fixture/policy/command/policy-command-invalid-type.json new file mode 100644 index 000000000..ea4b96c19 --- /dev/null +++ b/dongtai-core/src/test/fixture/policy/command/policy-command-invalid-type.json @@ -0,0 +1,14 @@ +{ + "status": 201, + "msg": "success", + "data": [ + { + "type": 1, + "signature": "A.b()", + "source": "P2", + "target": "O", + "inherit": "false", + "command": 1 + } + ] +} \ No newline at end of file diff --git a/dongtai-core/src/test/fixture/policy/stack-blacklist/policy-stack-blacklist-empty.json b/dongtai-core/src/test/fixture/policy/stack-blacklist/policy-stack-blacklist-empty.json new file mode 100644 index 000000000..3b52fea29 --- /dev/null +++ b/dongtai-core/src/test/fixture/policy/stack-blacklist/policy-stack-blacklist-empty.json @@ -0,0 +1,13 @@ +{ + "status": 201, + "msg": "success", + "data": [ + { + "type": 4, + "signature": "A.b()", + "source": "P2", + "inherit": "false", + "vul_type": "xss" + } + ] +} \ No newline at end of file diff --git a/dongtai-core/src/test/fixture/policy/stack-blacklist/policy-stack-blacklist-invalid-type-value.json b/dongtai-core/src/test/fixture/policy/stack-blacklist/policy-stack-blacklist-invalid-type-value.json new file mode 100644 index 000000000..ef6d0fd9c --- /dev/null +++ b/dongtai-core/src/test/fixture/policy/stack-blacklist/policy-stack-blacklist-invalid-type-value.json @@ -0,0 +1,17 @@ +{ + "status": 201, + "msg": "success", + "data": [ + { + "type": 4, + "signature": "A.b()", + "source": "P2", + "inherit": "false", + "vul_type": "xss", + "stack_blacklist": [ + 1, + 2 + ] + } + ] +} \ No newline at end of file diff --git a/dongtai-core/src/test/fixture/policy/stack-blacklist/policy-stack-blacklist-invalid-type.json b/dongtai-core/src/test/fixture/policy/stack-blacklist/policy-stack-blacklist-invalid-type.json new file mode 100644 index 000000000..b9fd67d72 --- /dev/null +++ b/dongtai-core/src/test/fixture/policy/stack-blacklist/policy-stack-blacklist-invalid-type.json @@ -0,0 +1,14 @@ +{ + "status": 201, + "msg": "success", + "data": [ + { + "type": 4, + "signature": "A.b()", + "source": "P2", + "inherit": "false", + "vul_type": "xss", + "stack_blacklist": 1 + } + ] +} \ No newline at end of file diff --git a/dongtai-core/src/test/fixture/policy/stack-blacklist/policy-stack-blacklist-invalid.json b/dongtai-core/src/test/fixture/policy/stack-blacklist/policy-stack-blacklist-invalid.json new file mode 100644 index 000000000..7fd3a6bf2 --- /dev/null +++ b/dongtai-core/src/test/fixture/policy/stack-blacklist/policy-stack-blacklist-invalid.json @@ -0,0 +1,14 @@ +{ + "status": 201, + "msg": "success", + "data": [ + { + "type": 4, + "signature": "A.b()", + "source": "P2", + "inherit": "false", + "vul_type": "xss", + "stack_blacklist": "foo" + } + ] +} \ No newline at end of file diff --git a/dongtai-core/src/test/fixture/policy/stack-blacklist/policy-stack-blacklist-valid-empty.json b/dongtai-core/src/test/fixture/policy/stack-blacklist/policy-stack-blacklist-valid-empty.json new file mode 100644 index 000000000..3962d6b68 --- /dev/null +++ b/dongtai-core/src/test/fixture/policy/stack-blacklist/policy-stack-blacklist-valid-empty.json @@ -0,0 +1,14 @@ +{ + "status": 201, + "msg": "success", + "data": [ + { + "type": 4, + "signature": "A.b()", + "source": "P2", + "inherit": "false", + "vul_type": "xss", + "stack_blacklist": [] + } + ] +} \ No newline at end of file diff --git a/dongtai-core/src/test/fixture/policy/stack-blacklist/policy-stack-blacklist-valid.json b/dongtai-core/src/test/fixture/policy/stack-blacklist/policy-stack-blacklist-valid.json new file mode 100644 index 000000000..b3c3538bd --- /dev/null +++ b/dongtai-core/src/test/fixture/policy/stack-blacklist/policy-stack-blacklist-valid.json @@ -0,0 +1,17 @@ +{ + "status": 201, + "msg": "success", + "data": [ + { + "type": 4, + "signature": "A.b()", + "source": "P2", + "inherit": "false", + "vul_type": "xss", + "stack_blacklist": [ + "foo.Bar", + "foo.Bar(baz)" + ] + } + ] +} \ No newline at end of file diff --git a/dongtai-core/src/test/fixture/policy/tags/policy-tags-invalid-type-tags-value.json b/dongtai-core/src/test/fixture/policy/tags/policy-tags-invalid-type-tags-value.json new file mode 100644 index 000000000..e72104c3e --- /dev/null +++ b/dongtai-core/src/test/fixture/policy/tags/policy-tags-invalid-type-tags-value.json @@ -0,0 +1,15 @@ +{ + "status": 201, + "msg": "success", + "data": [ + { + "type": 1, + "signature": "A.b()", + "source": "P2", + "target": "O", + "inherit": "false", + "tags": [1], + "untags": [] + } + ] +} \ No newline at end of file diff --git a/dongtai-core/src/test/fixture/policy/tags/policy-tags-invalid-type-tags.json b/dongtai-core/src/test/fixture/policy/tags/policy-tags-invalid-type-tags.json new file mode 100644 index 000000000..59562afba --- /dev/null +++ b/dongtai-core/src/test/fixture/policy/tags/policy-tags-invalid-type-tags.json @@ -0,0 +1,15 @@ +{ + "status": 201, + "msg": "success", + "data": [ + { + "type": 1, + "signature": "A.b()", + "source": "P2", + "target": "O", + "inherit": "false", + "tags": 1, + "untags": [] + } + ] +} \ No newline at end of file diff --git a/dongtai-core/src/test/fixture/policy/tags/policy-tags-invalid-type-untags-value.json b/dongtai-core/src/test/fixture/policy/tags/policy-tags-invalid-type-untags-value.json new file mode 100644 index 000000000..0093afdcf --- /dev/null +++ b/dongtai-core/src/test/fixture/policy/tags/policy-tags-invalid-type-untags-value.json @@ -0,0 +1,15 @@ +{ + "status": 201, + "msg": "success", + "data": [ + { + "type": 1, + "signature": "A.b()", + "source": "P2", + "target": "O", + "inherit": "false", + "tags": [], + "untags": 1 + } + ] +} \ No newline at end of file diff --git a/dongtai-core/src/test/fixture/policy/tags/policy-tags-invalid-type-untags.json b/dongtai-core/src/test/fixture/policy/tags/policy-tags-invalid-type-untags.json new file mode 100644 index 000000000..0093afdcf --- /dev/null +++ b/dongtai-core/src/test/fixture/policy/tags/policy-tags-invalid-type-untags.json @@ -0,0 +1,15 @@ +{ + "status": 201, + "msg": "success", + "data": [ + { + "type": 1, + "signature": "A.b()", + "source": "P2", + "target": "O", + "inherit": "false", + "tags": [], + "untags": 1 + } + ] +} \ No newline at end of file diff --git a/dongtai-core/src/test/fixture/policy/tags/policy-tags-valid-empty.json b/dongtai-core/src/test/fixture/policy/tags/policy-tags-valid-empty.json new file mode 100644 index 000000000..8e2e5a09a --- /dev/null +++ b/dongtai-core/src/test/fixture/policy/tags/policy-tags-valid-empty.json @@ -0,0 +1,15 @@ +{ + "status": 201, + "msg": "success", + "data": [ + { + "type": 1, + "signature": "A.b()", + "source": "P2", + "target": "O", + "inherit": "false", + "tags": [], + "untags": [] + } + ] +} \ No newline at end of file diff --git a/dongtai-core/src/test/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyBuilderTest.java b/dongtai-core/src/test/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyBuilderTest.java index 4e18eec62..0cf658c0f 100644 --- a/dongtai-core/src/test/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyBuilderTest.java +++ b/dongtai-core/src/test/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyBuilderTest.java @@ -4,25 +4,40 @@ import io.dongtai.iast.core.handler.hookpoint.models.taint.range.TaintCommandRunner; import io.dongtai.iast.core.handler.hookpoint.models.taint.tag.TaintTag; import io.dongtai.iast.core.utils.PropertyUtils; +import io.dongtai.log.DongTaiLog; import org.json.JSONArray; import org.junit.*; import org.junit.function.ThrowingRunnable; +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; import java.util.*; public class PolicyBuilderTest { private static final String POLICY_DIR = "src/test/fixture/policy/"; private static final String PROPERTY_FILE = "src/test/fixture/property/policy-test-invalid.properties"; + private final PrintStream standardOut = System.out; + private final ByteArrayOutputStream outputStreamCaptor = new ByteArrayOutputStream(); + @Before public void setUp() { PropertyUtils.getInstance(PROPERTY_FILE); - System.setProperty("dongtai.log", "false"); + DongTaiLog.ENABLED = true; + clear(); + System.setOut(new PrintStream(outputStreamCaptor)); } @After public void tearDown() { PropertyUtils.clear(); + DongTaiLog.ENABLED = false; + clear(); + System.setOut(standardOut); + } + + private void clear() { + outputStreamCaptor.reset(); } @Test @@ -184,6 +199,11 @@ public void testTags() throws PolicyException { Map> tests = new HashMap>() {{ put("tags/policy-tags-empty.json", Arrays.asList(new String[0], new String[0])); put("tags/policy-tags-invalid.json", Arrays.asList(new String[0], new String[0])); + put("tags/policy-tags-invalid-type-tags.json", Arrays.asList(new String[0], new String[0])); + put("tags/policy-tags-invalid-type-tags-value.json", Arrays.asList(new String[0], new String[0])); + put("tags/policy-tags-invalid-type-untags.json", Arrays.asList(new String[0], new String[0])); + put("tags/policy-tags-invalid-type-untags-value.json", Arrays.asList(new String[0], new String[0])); + put("tags/policy-tags-valid-empty.json", Arrays.asList(new String[0], new String[0])); put("tags/policy-tags-valid-single.json", Arrays.asList( new String[]{TaintTag.URL_ENCODED.getKey()}, new String[]{TaintTag.URL_DECODED.getKey()})); put("tags/policy-tags-valid-multi.json", Arrays.asList( @@ -197,14 +217,28 @@ public void testTags() throws PolicyException { new String[]{TaintTag.URL_DECODED.getKey(), TaintTag.HTML_ENCODED.getKey()})); }}; for (Map.Entry> entry : tests.entrySet()) { + clear(); JSONArray policyConfig = PolicyBuilder.fetchFromFile(POLICY_DIR + entry.getKey()); Policy policy = new Policy(); PolicyBuilder.buildPropagator(policy, PolicyNodeType.PROPAGATOR, policyConfig.getJSONObject(0)); - Assert.assertEquals("tags/untags policy length " + entry.getKey(), 1, policy.getPolicyNodesMap().size()); + + if ("tags/policy-tags-invalid.json".equals(entry.getKey()) + || "tags/policy-tags-invalid-type-tags.json".equals(entry.getKey()) + || "tags/policy-tags-invalid-type-tags-value.json".equals(entry.getKey()) + || "tags/policy-tags-invalid-type-untags.json".equals(entry.getKey()) + || "tags/policy-tags-invalid-type-untags-value.json".equals(entry.getKey()) + || "tags/policy-tags-multi-has-invalid.json".equals(entry.getKey()) + || "tags/policy-tags-multi-has-dup.json".equals(entry.getKey())) { + Assert.assertTrue("policy tags/untags warn " + entry.getKey(), outputStreamCaptor.size() > 0); + } else { + Assert.assertEquals("policy tags/untags no warn " + entry.getKey(), 0, outputStreamCaptor.size()); + } + + Assert.assertEquals("policy tags/untags length " + entry.getKey(), 1, policy.getPolicyNodesMap().size()); String[] tags = policy.getPropagators().get(0).getTags(); String[] untags = policy.getPropagators().get(0).getUntags(); - Assert.assertArrayEquals("tags " + entry.getKey(), entry.getValue().get(0), tags); - Assert.assertArrayEquals("untags " + entry.getKey(), entry.getValue().get(1), untags); + Assert.assertArrayEquals("policy tags " + entry.getKey(), entry.getValue().get(0), tags); + Assert.assertArrayEquals("policy untags " + entry.getKey(), entry.getValue().get(1), untags); } } @@ -213,6 +247,7 @@ public void testCommand() throws PolicyException { Map tests = new HashMap() {{ put("command/policy-command-empty.json", null); put("command/policy-command-invalid.json", null); + put("command/policy-command-invalid-type.json", null); put("command/policy-command-invalid-cmd.json", null); put("command/policy-command-invalid-args.json", null); put("command/policy-keep-empty-args.json", TaintCommandRunner.create("", @@ -227,10 +262,21 @@ public void testCommand() throws PolicyException { new String[]{"0", "P1"})); }}; for (Map.Entry entry : tests.entrySet()) { + clear(); JSONArray policyConfig = PolicyBuilder.fetchFromFile(POLICY_DIR + entry.getKey()); Policy policy = new Policy(); PolicyBuilder.buildPropagator(policy, PolicyNodeType.PROPAGATOR, policyConfig.getJSONObject(0)); TaintCommandRunner r = policy.getPropagators().get(0).getCommandRunner(); + + if ("command/policy-command-invalid.json".equals(entry.getKey()) + || "command/policy-command-invalid-type.json".equals(entry.getKey()) + || "command/policy-command-invalid-cmd.json".equals(entry.getKey()) + || "command/policy-command-invalid-args.json".equals(entry.getKey())) { + Assert.assertTrue("policy command warn " + entry.getKey(), outputStreamCaptor.size() > 0); + } else { + Assert.assertEquals("policy command no warn " + entry.getKey(), 0, outputStreamCaptor.size()); + } + if (entry.getValue() == null) { Assert.assertNull(r); } else { @@ -240,4 +286,34 @@ public void testCommand() throws PolicyException { } } } + + @Test + public void testStackBlacklist() throws PolicyException { + Map tests = new HashMap() {{ + put("stack-blacklist/policy-stack-blacklist-empty.json", null); + put("stack-blacklist/policy-stack-blacklist-invalid.json", null); + put("stack-blacklist/policy-stack-blacklist-invalid-type.json", null); + put("stack-blacklist/policy-stack-blacklist-invalid-type-value.json", null); + put("stack-blacklist/policy-stack-blacklist-valid-empty.json", new String[0]); + put("stack-blacklist/policy-stack-blacklist-valid.json", new String[]{"foo.Bar", "foo.Bar(baz)"}); + }}; + for (Map.Entry entry : tests.entrySet()) { + clear(); + JSONArray policyConfig = PolicyBuilder.fetchFromFile(POLICY_DIR + entry.getKey()); + Policy policy = new Policy(); + PolicyBuilder.buildSink(policy, PolicyNodeType.SINK, policyConfig.getJSONObject(0)); + SinkNode sinkNode = policy.getSinks().get(0); + + if ("stack-blacklist/policy-stack-blacklist-invalid.json".equals(entry.getKey()) + || "stack-blacklist/policy-stack-blacklist-invalid-type.json".equals(entry.getKey()) + || "stack-blacklist/policy-stack-blacklist-invalid-type-value.json".equals(entry.getKey())) { + Assert.assertTrue("policy stack blacklist warn " + entry.getKey(), outputStreamCaptor.size() > 0); + } else { + Assert.assertEquals("policy stack blacklist no warn " + entry.getKey(), 0, outputStreamCaptor.size()); + } + + Assert.assertArrayEquals("policy stack blacklist " + entry.getKey(), + entry.getValue(), sinkNode.getStackDenyList()); + } + } } \ No newline at end of file From 375b4e1ef29e8d0b07e3f3a8ba758e23ba284389 Mon Sep 17 00:00:00 2001 From: lostsnow Date: Thu, 13 Apr 2023 17:41:48 +0800 Subject: [PATCH 04/42] fixes policy command syntax check --- .../core/handler/hookpoint/models/policy/PolicyBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyBuilder.java b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyBuilder.java index 5e85585fe..6d0f1f7df 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyBuilder.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyBuilder.java @@ -310,7 +310,7 @@ private static void parseCommand(JSONObject node, PropagatorNode propagatorNode) int parametersStartIndex = cmdConfig.indexOf("("); int parametersEndIndex = cmdConfig.indexOf(")"); - if (parametersStartIndex <= 2 || parametersEndIndex <= 3 + if (parametersStartIndex <= 0 || parametersEndIndex <= 1 || parametersStartIndex > parametersEndIndex || parametersEndIndex != cmdConfig.length() - 1) { isInvalid = true; From 0cc589a678d9c65e36ff3ddfc57b70ffefd36772 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98niuerzhuang=E2=80=99?= <‘niuerzhuang@huoxian.cn’> Date: Tue, 18 Apr 2023 15:18:37 +0800 Subject: [PATCH 05/42] fix: fastjson1.2.83 replaces org.json. --- .../iast/agent/fallback/FallbackConfig.java | 5 +++-- .../agent/monitor/impl/AgentStateMonitor.java | 5 +++-- .../agent/report/AgentRegisterReport.java | 10 +++++---- .../iast/agent/report/HeartBeatReport.java | 2 +- .../src/main/resources/iast.properties | 22 +++++++++++-------- dongtai-common/pom.xml | 6 ++--- .../iast/common/config/ConfigBuilder.java | 9 +++++--- .../iast/common/config/RequestDeny.java | 6 +++-- .../iast/common/config/RequestDenyList.java | 10 ++++----- .../iast/common/config/ConfigBuilderTest.java | 17 +++++++------- .../utils/AbstractHttpClientUtilsTest.java | 11 +++++----- .../hardcoded/DispatchHardcodedPlugin.java | 2 +- .../iast/core/bytecode/sca/ScaReport.java | 3 +-- .../iast/core/bytecode/sca/ScaScanner.java | 10 ++++----- .../core/handler/hookpoint/api/ApiReport.java | 2 +- .../hookpoint/controller/impl/DubboImpl.java | 4 ++-- .../hookpoint/graphy/GraphBuilder.java | 6 +++-- .../handler/hookpoint/graphy/GraphNode.java | 18 ++++++--------- .../handler/hookpoint/models/MethodEvent.java | 2 +- .../models/policy/PolicyBuilder.java | 17 ++++++++------ .../models/policy/PolicyManager.java | 2 +- .../models/taint/range/TaintRange.java | 2 +- .../models/taint/range/TaintRanges.java | 4 ++-- .../hookpoint/service/ServiceHandler.java | 2 +- .../vulscan/normal/AbstractNormalVulScan.java | 7 +++--- .../iast/core/replay/HttpRequestReplay.java | 9 ++++---- .../iast/core/service/AgentQueueReport.java | 2 +- .../core/service/ServerAddressReport.java | 2 +- .../iast/core/service/ServiceDirReport.java | 3 ++- .../iast/core/service/StartUpTimeReport.java | 2 +- .../models/policy/PolicyBuilderTest.java | 4 ++-- pom.xml | 1 + 32 files changed, 113 insertions(+), 94 deletions(-) diff --git a/dongtai-agent/src/main/java/io/dongtai/iast/agent/fallback/FallbackConfig.java b/dongtai-agent/src/main/java/io/dongtai/iast/agent/fallback/FallbackConfig.java index 3e5021c8a..226145958 100644 --- a/dongtai-agent/src/main/java/io/dongtai/iast/agent/fallback/FallbackConfig.java +++ b/dongtai-agent/src/main/java/io/dongtai/iast/agent/fallback/FallbackConfig.java @@ -1,5 +1,6 @@ package io.dongtai.iast.agent.fallback; +import com.alibaba.fastjson.JSONObject; import com.google.gson.reflect.TypeToken; import io.dongtai.iast.agent.IastProperties; import io.dongtai.iast.agent.fallback.entity.*; @@ -15,7 +16,7 @@ import io.dongtai.iast.common.state.State; import io.dongtai.log.DongTaiLog; import io.dongtai.log.ErrorCode; -import org.json.JSONObject; + import java.lang.reflect.Field; import java.util.*; @@ -111,7 +112,7 @@ private static FallbackConfigEntity parseRemoteConfigResponseV2(String remoteRes try { // 默认响应标识调用失败 if (REMOTE_CONFIG_DEFAULT_META.equals(remoteResponse) - || REMOTE_CONFIG_DEFAULT_META.equals(new JSONObject(remoteResponse).get("data").toString())) { + || REMOTE_CONFIG_DEFAULT_META.equals(JSONObject.parseObject(remoteResponse).get("data").toString())) { FallbackConfig.enableAutoFallback = false; if (AgentState.getInstance().isFallback()) { DongTaiLog.info("fallback remote config empty, auto fallback closed, starting agent"); diff --git a/dongtai-agent/src/main/java/io/dongtai/iast/agent/monitor/impl/AgentStateMonitor.java b/dongtai-agent/src/main/java/io/dongtai/iast/agent/monitor/impl/AgentStateMonitor.java index 63a870d1d..07a628f8d 100644 --- a/dongtai-agent/src/main/java/io/dongtai/iast/agent/monitor/impl/AgentStateMonitor.java +++ b/dongtai-agent/src/main/java/io/dongtai/iast/agent/monitor/impl/AgentStateMonitor.java @@ -1,5 +1,7 @@ package io.dongtai.iast.agent.monitor.impl; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; import io.dongtai.iast.agent.manager.EngineManager; import io.dongtai.iast.agent.monitor.IMonitor; import io.dongtai.iast.agent.monitor.MonitorDaemonThread; @@ -13,7 +15,6 @@ import io.dongtai.iast.common.state.StateCause; import io.dongtai.log.DongTaiLog; import io.dongtai.log.ErrorCode; -import org.json.JSONObject; import java.util.HashMap; import java.util.Map; @@ -73,7 +74,7 @@ private String checkExpectState() { parameters.put("agentId", String.valueOf(AgentRegisterReport.getAgentId())); String respRaw = HttpClientUtils.sendGet(ApiPath.EXCEPT_ACTION, parameters).toString(); if (!respRaw.isEmpty()) { - JSONObject resp = new JSONObject(respRaw); + JSONObject resp = JSON.parseObject(respRaw); JSONObject data = (JSONObject) resp.get("data"); return data.get("exceptRunningStatus").toString(); } diff --git a/dongtai-agent/src/main/java/io/dongtai/iast/agent/report/AgentRegisterReport.java b/dongtai-agent/src/main/java/io/dongtai/iast/agent/report/AgentRegisterReport.java index ec92afb0e..0e7cca19e 100644 --- a/dongtai-agent/src/main/java/io/dongtai/iast/agent/report/AgentRegisterReport.java +++ b/dongtai-agent/src/main/java/io/dongtai/iast/agent/report/AgentRegisterReport.java @@ -1,5 +1,8 @@ package io.dongtai.iast.agent.report; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; import io.dongtai.iast.agent.IastProperties; import io.dongtai.iast.agent.manager.EngineManager; import io.dongtai.iast.agent.middlewarerecognition.IServer; @@ -10,8 +13,7 @@ import io.dongtai.iast.common.utils.base64.Base64Encoder; import io.dongtai.log.DongTaiLog; import io.dongtai.log.ErrorCode; -import org.json.JSONArray; -import org.json.JSONObject; + import java.io.*; import java.net.*; @@ -211,7 +213,7 @@ private String readIpInfo() { } else { jsonObject.put("isAddress", "0"); } - network.put(jsonObject); + network.add(jsonObject); } } return network.toString(); @@ -258,7 +260,7 @@ public static Boolean send() { */ private void setAgentData(StringBuilder responseRaw) { try { - JSONObject responseObj = new JSONObject(responseRaw.toString()); + JSONObject responseObj = JSON.parseObject(responseRaw.toString()); Integer status = (Integer) responseObj.get("status"); if (status == 201) { JSONObject data = (JSONObject) responseObj.get("data"); diff --git a/dongtai-agent/src/main/java/io/dongtai/iast/agent/report/HeartBeatReport.java b/dongtai-agent/src/main/java/io/dongtai/iast/agent/report/HeartBeatReport.java index 298031dcd..4446b5ab0 100644 --- a/dongtai-agent/src/main/java/io/dongtai/iast/agent/report/HeartBeatReport.java +++ b/dongtai-agent/src/main/java/io/dongtai/iast/agent/report/HeartBeatReport.java @@ -1,12 +1,12 @@ package io.dongtai.iast.agent.report; +import com.alibaba.fastjson.JSONObject; import io.dongtai.iast.agent.monitor.impl.PerformanceMonitor; import io.dongtai.iast.agent.util.ByteUtils; import io.dongtai.iast.common.constants.ReportKey; import io.dongtai.iast.common.constants.ReportType; import io.dongtai.iast.common.entity.performance.metrics.MemoryUsageMetrics; import io.dongtai.iast.common.state.AgentState; -import org.json.JSONObject; /** * 心跳机制实现,默认30s diff --git a/dongtai-agent/src/main/resources/iast.properties b/dongtai-agent/src/main/resources/iast.properties index f98756581..5a8d9cdb2 100644 --- a/dongtai-agent/src/main/resources/iast.properties +++ b/dongtai-agent/src/main/resources/iast.properties @@ -1,14 +1,18 @@ -iast.name=dongtai-Enterprise -iast.server.url=https://iast.io/openapi -iast.server.token=39133a96f5735c253edd908078846c1051824edc +iast.response.name=DongTai Iast +iast.server.url=https://iast-beta.huoxian.cn/openapi +iast.server.token=GROUP1f6b147d1790d2226e49ae6b822d83f2f911b55b +iast.allhook.enable=false iast.dump.class.enable=false iast.dump.class.path=/tmp/iast-class-dump/ -engine.name=java.action.github.com -project.name=ExampleApplication -project.create= -project.version=V1.0 -dongtai.app.template=0 +iast.service.report.interval=30000 +app.name=DongTai +engine.status=start +engine.name=caec05c4106b4a24afb9b3dd12086a91 +jdk.version=1 +project.name=webgoat-server-8.2.2 iast.proxy.enable=false iast.proxy.host= iast.proxy.port= -iast.server.mode=local \ No newline at end of file +iast.server.mode=local +dongtai.app.template=1 +project.version=V1.0 \ No newline at end of file diff --git a/dongtai-common/pom.xml b/dongtai-common/pom.xml index cdb516cfc..c1a6c0a4e 100644 --- a/dongtai-common/pom.xml +++ b/dongtai-common/pom.xml @@ -28,9 +28,9 @@ ${apache-httpclient.version} - org.json - json - ${json.version} + com.alibaba + fastjson + ${fastjson.version} diff --git a/dongtai-common/src/main/java/io/dongtai/iast/common/config/ConfigBuilder.java b/dongtai-common/src/main/java/io/dongtai/iast/common/config/ConfigBuilder.java index 39a3ff44a..4ad9748f6 100644 --- a/dongtai-common/src/main/java/io/dongtai/iast/common/config/ConfigBuilder.java +++ b/dongtai-common/src/main/java/io/dongtai/iast/common/config/ConfigBuilder.java @@ -1,6 +1,9 @@ package io.dongtai.iast.common.config; -import org.json.*; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONException; +import com.alibaba.fastjson.JSONObject; import java.util.HashMap; import java.util.Map; @@ -44,7 +47,7 @@ public Config getConfig(ConfigKey key) { public void updateFromRemote(String content) { JSONObject config = null; try { - JSONObject json = new JSONObject(content); + JSONObject json = JSON.parseObject(content); config = json.getJSONObject("data"); } catch (JSONException ignore) { } @@ -91,7 +94,7 @@ private void updateInt(JSONObject config, ConfigKey.JsonKey jsonKey) { try { Config conf = (Config) getConfig(jsonKey.getConfigKey()); if (conf != null) { - Integer value = config.getInt(jsonKey.getKey()); + Integer value = config.getIntValue(jsonKey.getKey()); conf.setValue(value); } } catch (Throwable ignore) { diff --git a/dongtai-common/src/main/java/io/dongtai/iast/common/config/RequestDeny.java b/dongtai-common/src/main/java/io/dongtai/iast/common/config/RequestDeny.java index 6b4e10eb3..0efedb358 100644 --- a/dongtai-common/src/main/java/io/dongtai/iast/common/config/RequestDeny.java +++ b/dongtai-common/src/main/java/io/dongtai/iast/common/config/RequestDeny.java @@ -1,7 +1,9 @@ package io.dongtai.iast.common.config; -import org.json.JSONException; -import org.json.JSONObject; + + +import com.alibaba.fastjson.JSONException; +import com.alibaba.fastjson.JSONObject; import java.util.*; diff --git a/dongtai-common/src/main/java/io/dongtai/iast/common/config/RequestDenyList.java b/dongtai-common/src/main/java/io/dongtai/iast/common/config/RequestDenyList.java index ca71c2628..b7c7713a8 100644 --- a/dongtai-common/src/main/java/io/dongtai/iast/common/config/RequestDenyList.java +++ b/dongtai-common/src/main/java/io/dongtai/iast/common/config/RequestDenyList.java @@ -1,6 +1,6 @@ package io.dongtai.iast.common.config; -import org.json.JSONArray; +import com.alibaba.fastjson.JSONArray; import java.util.*; @@ -8,18 +8,18 @@ public class RequestDenyList { private final List> denies = new ArrayList>(); public static RequestDenyList parse(JSONArray config) { - if (config == null || config.length() == 0) { + if (config == null || config.size() == 0) { return null; } RequestDenyList denyList = new RequestDenyList(); - int orLen = config.length(); + int orLen = config.size(); for (int i = 0; i < orLen; i++) { JSONArray andConfig = config.getJSONArray(i); - if (andConfig == null || andConfig.length() == 0) { + if (andConfig == null || andConfig.size() == 0) { continue; } - int andLen = andConfig.length(); + int andLen = andConfig.size(); List andList = new ArrayList(); for (int j = 0; j < andLen; j++) { RequestDeny requestDeny = RequestDeny.parse(andConfig.getJSONObject(j)); diff --git a/dongtai-common/src/test/java/io/dongtai/iast/common/config/ConfigBuilderTest.java b/dongtai-common/src/test/java/io/dongtai/iast/common/config/ConfigBuilderTest.java index d00075220..f32b845bb 100644 --- a/dongtai-common/src/test/java/io/dongtai/iast/common/config/ConfigBuilderTest.java +++ b/dongtai-common/src/test/java/io/dongtai/iast/common/config/ConfigBuilderTest.java @@ -1,6 +1,7 @@ package io.dongtai.iast.common.config; -import org.json.JSONObject; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; import org.junit.Assert; import org.junit.Test; @@ -30,13 +31,13 @@ public void testGetConfigAndUpdate() { // update configString = "{\"gather_res_body\": false}"; - configJson = new JSONObject(configString); + configJson = JSON.parseObject(configString); builder.update(configJson); configString = "{\"method_pool_max_length\": 1000}"; - configJson = new JSONObject(configString); + configJson = JSON.parseObject(configString); builder.update(configJson); configString = "{\"blacklist_rules\": [[{\"target_type\": \"HEADER_KEY\", \"operator\": \"EXISTS\", \"value\": \"key1\"}]]}"; - configJson = new JSONObject(configString); + configJson = JSON.parseObject(configString); builder.update(configJson); RequestDenyList expectRequestDenyList = new RequestDenyList(); @@ -53,16 +54,16 @@ public void testGetConfigAndUpdate() { // update invalid configString = "{\"gather_res_body\": \"invalid\"}"; - configJson = new JSONObject(configString); + configJson = JSON.parseObject(configString); builder.update(configJson); configString = "{\"method_pool_max_length\": \"invalid\"}"; - configJson = new JSONObject(configString); + configJson = JSON.parseObject(configString); builder.update(configJson); configString = "{\"blacklist_rules\": \"invalid\"}"; - configJson = new JSONObject(configString); + configJson = JSON.parseObject(configString); builder.update(configJson); configString = "{\"invalid\": \"invalid\"}"; - configJson = new JSONObject(configString); + configJson = JSON.parseObject(configString); builder.update(configJson); reportResponseBody = builder.get(ConfigKey.REPORT_RESPONSE_BODY); diff --git a/dongtai-common/src/test/java/io/dongtai/iast/common/utils/AbstractHttpClientUtilsTest.java b/dongtai-common/src/test/java/io/dongtai/iast/common/utils/AbstractHttpClientUtilsTest.java index e08e7204c..9db189b4c 100644 --- a/dongtai-common/src/test/java/io/dongtai/iast/common/utils/AbstractHttpClientUtilsTest.java +++ b/dongtai-common/src/test/java/io/dongtai/iast/common/utils/AbstractHttpClientUtilsTest.java @@ -1,12 +1,13 @@ package io.dongtai.iast.common.utils; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; import io.dongtai.iast.common.enums.HttpMethods; import io.dongtai.log.DongTaiLog; import io.dongtai.log.ErrorCode; import org.apache.http.client.config.RequestConfig; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; -import org.json.JSONObject; import org.junit.*; import java.io.ByteArrayOutputStream; @@ -57,15 +58,15 @@ public void sendRequest() { url = BASE_URL + "/api/v1/captcha/refresh"; resp = AbstractHttpClientUtils.sendRequest(HttpMethods.GET, url, null, headers, 0, "", -1, null); - respObj = new JSONObject(resp.toString()); - status = respObj.getInt("status"); + respObj = JSON.parseObject(resp.toString()); + status = respObj.getInteger("status"); Assert.assertEquals("captcha/refresh status", 201, status); url = BASE_URL + "/api/v1/user/login"; data = "{\"username\":\"test\",\"password\":\"test\",\"captcha\":\"test\",\"captcha_hash_key\":\"test\"}"; resp = AbstractHttpClientUtils.sendRequest(HttpMethods.POST, url, data, headers, 0, "", -1, null); - respObj = new JSONObject(resp.toString()); - status = respObj.getInt("status"); + respObj = JSON.parseObject(resp.toString()); + status = respObj.getInteger("status"); Assert.assertEquals("user/login status", 202, status); url = BASE_URL + "/api/v1/profiles"; diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/hardcoded/DispatchHardcodedPlugin.java b/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/hardcoded/DispatchHardcodedPlugin.java index b2b59a013..e9227b850 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/hardcoded/DispatchHardcodedPlugin.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/hardcoded/DispatchHardcodedPlugin.java @@ -1,5 +1,6 @@ package io.dongtai.iast.core.bytecode.enhance.plugin.hardcoded; +import com.alibaba.fastjson.JSONObject; import io.dongtai.iast.common.constants.*; import io.dongtai.iast.common.utils.base64.Base64Encoder; import io.dongtai.iast.core.EngineManager; @@ -9,7 +10,6 @@ import io.dongtai.iast.core.handler.hookpoint.models.policy.Policy; import io.dongtai.iast.core.service.ThreadPools; import io.dongtai.iast.core.utils.commonUtils; -import org.json.JSONObject; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.FieldVisitor; diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/sca/ScaReport.java b/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/sca/ScaReport.java index d7d949a2c..2766a45d3 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/sca/ScaReport.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/sca/ScaReport.java @@ -1,12 +1,11 @@ package io.dongtai.iast.core.bytecode.sca; +import com.alibaba.fastjson.JSONObject; import io.dongtai.iast.common.constants.*; import io.dongtai.iast.core.EngineManager; import io.dongtai.iast.core.utils.HttpClientUtils; import io.dongtai.log.DongTaiLog; import io.dongtai.log.ErrorCode; -import org.json.JSONObject; - /** * 定时发送资产信息 diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/sca/ScaScanner.java b/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/sca/ScaScanner.java index 3f703f41b..fd449a370 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/sca/ScaScanner.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/sca/ScaScanner.java @@ -1,13 +1,13 @@ package io.dongtai.iast.core.bytecode.sca; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; import io.dongtai.iast.common.constants.ReportKey; import io.dongtai.iast.common.constants.ReportType; import io.dongtai.iast.core.EngineManager; import io.dongtai.iast.core.service.ThreadPools; import io.dongtai.log.DongTaiLog; import io.dongtai.log.ErrorCode; -import org.json.JSONArray; -import org.json.JSONObject; import java.io.File; import java.io.InputStream; @@ -112,7 +112,7 @@ public void scan(File file) { packageObj.put(ScaReport.KEY_SCA_PACKAGE_NAME, packageName); packageObj.put(ScaReport.KEY_SCA_PACKAGE_SIGNATURE, signature); packageObj.put(ScaReport.KEY_SCA_PACKAGE_ALGORITHM, ScaScanner.ALGORITHM); - packages.put(packageObj); + packages.add(packageObj); } } } @@ -143,7 +143,7 @@ public void scanClassPath(String packagesPath) { packageObj.put(ScaReport.KEY_SCA_PACKAGE_SIGNATURE, SignatureAlgorithm.getSignature(file, ScaScanner.ALGORITHM)); packageObj.put(ScaReport.KEY_SCA_PACKAGE_ALGORITHM, ScaScanner.ALGORITHM); - this.packages.put(packageObj); + this.packages.add(packageObj); } } } @@ -177,7 +177,7 @@ private void scanJarLib(String packagePath) { packageObj.put(ScaReport.KEY_SCA_PACKAGE_NAME, packageName); packageObj.put(ScaReport.KEY_SCA_PACKAGE_SIGNATURE, signature); packageObj.put(ScaReport.KEY_SCA_PACKAGE_ALGORITHM, ScaScanner.ALGORITHM); - packages.put(packageObj); + packages.add(packageObj); } } } catch (Throwable e) { diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/api/ApiReport.java b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/api/ApiReport.java index 006cd12de..dc02e9bfc 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/api/ApiReport.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/api/ApiReport.java @@ -1,9 +1,9 @@ package io.dongtai.iast.core.handler.hookpoint.api; +import com.alibaba.fastjson.JSONObject; import io.dongtai.iast.common.constants.*; import io.dongtai.iast.core.EngineManager; import io.dongtai.iast.core.service.ThreadPools; -import org.json.JSONObject; import java.util.Map; diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/controller/impl/DubboImpl.java b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/controller/impl/DubboImpl.java index 0c213f95d..521e50553 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/controller/impl/DubboImpl.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/controller/impl/DubboImpl.java @@ -1,5 +1,6 @@ package io.dongtai.iast.core.handler.hookpoint.controller.impl; +import com.alibaba.fastjson.JSONArray; import io.dongtai.iast.common.config.ConfigBuilder; import io.dongtai.iast.common.config.ConfigKey; import io.dongtai.iast.core.EngineManager; @@ -11,7 +12,6 @@ import io.dongtai.iast.core.utils.StackUtils; import io.dongtai.iast.core.utils.TaintPoolUtils; import io.dongtai.log.DongTaiLog; -import org.json.JSONArray; import java.io.ByteArrayOutputStream; import java.net.URI; @@ -110,7 +110,7 @@ public static void collectDubboRequestSource(Object handler, Object invocation, requestMeta.put("headers", sHeaders); JSONArray arr = new JSONArray(); for (Object arg : arguments) { - arr.put(event.obj2String(arg)); + arr.add(event.obj2String(arg)); } requestMeta.put("body", arr.toString()); EngineManager.REQUEST_CONTEXT.set(requestMeta); diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/graphy/GraphBuilder.java b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/graphy/GraphBuilder.java index b50b9380a..ead871213 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/graphy/GraphBuilder.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/graphy/GraphBuilder.java @@ -1,5 +1,7 @@ package io.dongtai.iast.core.handler.hookpoint.graphy; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; import io.dongtai.iast.common.constants.*; import io.dongtai.iast.common.scope.ScopeManager; import io.dongtai.iast.common.utils.base64.Base64Encoder; @@ -11,8 +13,7 @@ import io.dongtai.iast.core.utils.StringUtils; import io.dongtai.log.DongTaiLog; import io.dongtai.log.ErrorCode; -import org.json.JSONArray; -import org.json.JSONObject; + import java.nio.charset.Charset; import java.util.*; @@ -111,6 +112,7 @@ public static String convertToReport(List nodeList) { for (GraphNode node : nodeList) { methodPool.put(node.toJson()); } + return report.toString(); } } diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/graphy/GraphNode.java b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/graphy/GraphNode.java index e33f1d2d4..4ed4cfe78 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/graphy/GraphNode.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/graphy/GraphNode.java @@ -1,10 +1,10 @@ package io.dongtai.iast.core.handler.hookpoint.graphy; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; import io.dongtai.iast.core.handler.hookpoint.models.MethodEvent; import io.dongtai.iast.core.handler.hookpoint.models.policy.TaintPosition; import io.dongtai.iast.core.utils.StringUtils; -import org.json.JSONArray; -import org.json.JSONObject; import java.util.*; @@ -138,7 +138,7 @@ public JSONObject toJson() { } if (this.parameterValues != null && this.parameterValues.size() > 0) { for (MethodEvent.Parameter parameter : this.parameterValues) { - parameterArray.put(parameter.toJson()); + parameterArray.add(parameter.toJson()); } value.put("parameterValues", parameterArray); } @@ -146,19 +146,15 @@ public JSONObject toJson() { value.put("retValue", returnValue); } - for (Integer hash : sourceHash) { - sourceHashArray.put(hash); - } + sourceHashArray.addAll(sourceHash); - for (Integer hash : targetHash) { - targetHashArray.put(hash); - } + targetHashArray.addAll(targetHash); if (targetRanges.size() > 0) { JSONArray tr = new JSONArray(); value.put("targetRange", tr); for (MethodEvent.MethodEventTargetRange range : targetRanges) { - tr.put(range.toJson()); + tr.add(range.toJson()); } } @@ -166,7 +162,7 @@ public JSONObject toJson() { JSONArray st = new JSONArray(); value.put("sourceType", st); for (MethodEvent.MethodEventSourceType s : sourceTypes) { - st.put(s.toJson()); + st.add(s.toJson()); } } diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/MethodEvent.java b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/MethodEvent.java index de141a7f2..968eb2523 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/MethodEvent.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/MethodEvent.java @@ -1,9 +1,9 @@ package io.dongtai.iast.core.handler.hookpoint.models; +import com.alibaba.fastjson.JSONObject; import io.dongtai.iast.core.handler.hookpoint.models.policy.TaintPosition; import io.dongtai.iast.core.handler.hookpoint.models.taint.range.TaintRanges; import io.dongtai.iast.core.utils.StringUtils; -import org.json.JSONObject; import java.io.StringWriter; import java.util.*; diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyBuilder.java b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyBuilder.java index c6a9fd26b..77f49782a 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyBuilder.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyBuilder.java @@ -1,5 +1,9 @@ package io.dongtai.iast.core.handler.hookpoint.models.policy; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONException; +import com.alibaba.fastjson.JSONObject; import io.dongtai.iast.common.constants.ApiPath; import io.dongtai.iast.core.handler.hookpoint.vulscan.VulnType; import io.dongtai.iast.core.utils.HttpClientUtils; @@ -7,7 +11,6 @@ import io.dongtai.log.DongTaiLog; import io.dongtai.log.ErrorCode; import org.apache.commons.io.FileUtils; -import org.json.*; import java.io.File; import java.io.IOException; @@ -28,7 +31,7 @@ public class PolicyBuilder { public static JSONArray fetchFromServer() throws PolicyException { try { StringBuilder resp = HttpClientUtils.sendGet(ApiPath.HOOK_PROFILE, null); - JSONObject respObj = new JSONObject(resp.toString()); + JSONObject respObj = JSON.parseObject(resp.toString()); return respObj.getJSONArray(KEY_DATA); } catch (JSONException e) { throw new PolicyException(PolicyException.ERR_POLICY_CONFIG_FROM_SERVER_INVALID, e); @@ -39,7 +42,7 @@ public static JSONArray fetchFromFile(String path) throws PolicyException { try { File file = new File(path); String content = FileUtils.readFileToString(file); - JSONObject respObj = new JSONObject(content); + JSONObject respObj = JSON.parseObject(content); return respObj.getJSONArray(KEY_DATA); } catch (IOException e) { throw new PolicyException(String.format(PolicyException.ERR_POLICY_CONFIG_FILE_READ_FAILED, path), e); @@ -49,14 +52,14 @@ public static JSONArray fetchFromFile(String path) throws PolicyException { } public static Policy build(JSONArray policyConfig) throws PolicyException { - if (policyConfig == null || policyConfig.length() == 0) { + if (policyConfig == null || policyConfig.size() == 0) { throw new PolicyException(PolicyException.ERR_POLICY_CONFIG_EMPTY); } - int policyLen = policyConfig.length(); + int policyLen = policyConfig.size(); Policy policy = new Policy(); for (int i = 0; i < policyLen; i++) { JSONObject node = policyConfig.getJSONObject(i); - if (node == null || node.length() == 0) { + if (node == null || node.size() == 0) { throw new PolicyException(PolicyException.ERR_POLICY_NODE_EMPTY); } @@ -128,7 +131,7 @@ public static void buildSink(Policy policy, PolicyNodeType type, JSONObject node private static PolicyNodeType parseNodeType(JSONObject node) throws PolicyException { try { - int type = node.getInt(KEY_TYPE); + int type = node.getInteger(KEY_TYPE); PolicyNodeType nodeType = PolicyNodeType.get(type); if (nodeType == null) { throw new PolicyException(PolicyException.ERR_POLICY_NODE_TYPE_INVALID + ": " + node.toString()); diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyManager.java b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyManager.java index a924a5037..1b4b3dadf 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyManager.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyManager.java @@ -1,12 +1,12 @@ package io.dongtai.iast.core.handler.hookpoint.models.policy; +import com.alibaba.fastjson.JSONArray; import io.dongtai.iast.core.bytecode.enhance.plugin.framework.dubbo.DispatchDubbo; import io.dongtai.iast.core.bytecode.enhance.plugin.framework.feign.DispatchFeign; import io.dongtai.iast.core.bytecode.enhance.plugin.framework.j2ee.dispatch.DispatchJ2ee; import io.dongtai.iast.core.utils.StringUtils; import io.dongtai.log.DongTaiLog; import io.dongtai.log.ErrorCode; -import org.json.JSONArray; import java.util.*; diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/taint/range/TaintRange.java b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/taint/range/TaintRange.java index c0a50d101..f5c532ae2 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/taint/range/TaintRange.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/taint/range/TaintRange.java @@ -1,7 +1,7 @@ package io.dongtai.iast.core.handler.hookpoint.models.taint.range; +import com.alibaba.fastjson.JSONObject; import io.dongtai.iast.core.handler.hookpoint.models.taint.tag.TaintTag; -import org.json.JSONObject; public class TaintRange { private String name; diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/taint/range/TaintRanges.java b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/taint/range/TaintRanges.java index af7616478..0027a2e72 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/taint/range/TaintRanges.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/taint/range/TaintRanges.java @@ -1,8 +1,8 @@ package io.dongtai.iast.core.handler.hookpoint.models.taint.range; +import com.alibaba.fastjson.JSONArray; import io.dongtai.iast.core.handler.hookpoint.models.taint.tag.TaintTag; import io.dongtai.iast.core.utils.StringUtils; -import org.json.JSONArray; import java.util.*; @@ -309,7 +309,7 @@ public String toString() { public JSONArray toJson() { JSONArray json = new JSONArray(); for (TaintRange tr : this.taintRanges) { - json.put(tr.toJson()); + json.add(tr.toJson()); } return json; } diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/service/ServiceHandler.java b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/service/ServiceHandler.java index 63dc6f9ee..1b676fcd2 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/service/ServiceHandler.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/service/ServiceHandler.java @@ -1,11 +1,11 @@ package io.dongtai.iast.core.handler.hookpoint.service; +import com.alibaba.fastjson.JSONObject; import io.dongtai.iast.common.constants.*; import io.dongtai.iast.core.EngineManager; import io.dongtai.iast.core.handler.hookpoint.service.url.*; import io.dongtai.iast.core.service.ThreadPools; import io.dongtai.log.DongTaiLog; -import org.json.JSONObject; import java.util.*; diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/vulscan/normal/AbstractNormalVulScan.java b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/vulscan/normal/AbstractNormalVulScan.java index 146847fd5..967ba9232 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/vulscan/normal/AbstractNormalVulScan.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/vulscan/normal/AbstractNormalVulScan.java @@ -1,13 +1,14 @@ package io.dongtai.iast.core.handler.hookpoint.vulscan.normal; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; import io.dongtai.iast.common.constants.*; import io.dongtai.iast.common.utils.base64.Base64Encoder; import io.dongtai.iast.core.EngineManager; import io.dongtai.iast.core.handler.hookpoint.vulscan.IVulScan; import io.dongtai.iast.core.service.ThreadPools; import io.dongtai.iast.core.utils.StackUtils; -import org.json.JSONArray; -import org.json.JSONObject; + import java.util.Collection; import java.util.Map; @@ -50,7 +51,7 @@ public void sendReport(StackTraceElement[] stacks, String vulType) { detail.put(ReportKey.VULN_CALLER, vulStacks); for (StackTraceElement element : stacks) { - vulStacks.put(element.toString()); + vulStacks.add(element.toString()); } ThreadPools.sendPriorityReport(ApiPath.REPORT_UPLOAD, report.toString()); } diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/replay/HttpRequestReplay.java b/dongtai-core/src/main/java/io/dongtai/iast/core/replay/HttpRequestReplay.java index 1a0d28684..0b59ff9dc 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/replay/HttpRequestReplay.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/replay/HttpRequestReplay.java @@ -1,13 +1,14 @@ package io.dongtai.iast.core.replay; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; import io.dongtai.iast.common.utils.base64.Base64Decoder; import io.dongtai.iast.core.handler.context.ContextManager; import io.dongtai.iast.core.handler.hookpoint.models.IastReplayModel; import io.dongtai.iast.core.utils.HttpClientUtils; import io.dongtai.log.DongTaiLog; import io.dongtai.log.ErrorCode; -import org.json.JSONArray; -import org.json.JSONObject; import java.util.HashMap; @@ -78,7 +79,7 @@ private static HashMap splitHeaderStringToHashmap(String origina @Override public void run() { try { - JSONObject resp = new JSONObject(replayRequestRaw.toString()); + JSONObject resp = JSON.parseObject(replayRequestRaw.toString()); Integer statusCode = (Integer) resp.get("status"); if (statusCode != 201) { return; @@ -90,7 +91,7 @@ public void run() { } JSONArray replayRequests = (JSONArray) resp.get("data"); - for (int index = 0, total = replayRequests.length(); index < total; index++) { + for (int index = 0, total = replayRequests.size(); index < total; index++) { JSONObject replayRequest = (JSONObject) replayRequests.get(index); IastReplayModel replayModel = new IastReplayModel( replayRequest.get("method"), diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/service/AgentQueueReport.java b/dongtai-core/src/main/java/io/dongtai/iast/core/service/AgentQueueReport.java index 06d573222..78d9215a2 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/service/AgentQueueReport.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/service/AgentQueueReport.java @@ -1,10 +1,10 @@ package io.dongtai.iast.core.service; +import com.alibaba.fastjson.JSONObject; import io.dongtai.iast.common.constants.*; import io.dongtai.iast.core.EngineManager; import io.dongtai.iast.core.utils.HttpClientUtils; import io.dongtai.log.DongTaiLog; -import org.json.JSONObject; /** * 上报agent队列与请求数量 diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/service/ServerAddressReport.java b/dongtai-core/src/main/java/io/dongtai/iast/core/service/ServerAddressReport.java index 7860a0156..03fe4c838 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/service/ServerAddressReport.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/service/ServerAddressReport.java @@ -1,10 +1,10 @@ package io.dongtai.iast.core.service; +import com.alibaba.fastjson.JSONObject; import io.dongtai.iast.common.constants.ApiPath; import io.dongtai.iast.common.constants.ReportKey; import io.dongtai.iast.core.EngineManager; import io.dongtai.log.DongTaiLog; -import org.json.JSONObject; /** * 上报agent队列与请求数量 diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/service/ServiceDirReport.java b/dongtai-core/src/main/java/io/dongtai/iast/core/service/ServiceDirReport.java index d6a6cc71e..7ba16dac7 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/service/ServiceDirReport.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/service/ServiceDirReport.java @@ -1,9 +1,10 @@ package io.dongtai.iast.core.service; +import com.alibaba.fastjson.JSONObject; import io.dongtai.iast.common.constants.*; import io.dongtai.iast.core.EngineManager; import io.dongtai.log.DongTaiLog; -import org.json.JSONObject; + import java.io.File; diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/service/StartUpTimeReport.java b/dongtai-core/src/main/java/io/dongtai/iast/core/service/StartUpTimeReport.java index 48c3b95f1..6c9ec15bc 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/service/StartUpTimeReport.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/service/StartUpTimeReport.java @@ -1,8 +1,8 @@ package io.dongtai.iast.core.service; +import com.alibaba.fastjson.JSONObject; import io.dongtai.iast.common.constants.ApiPath; import io.dongtai.iast.common.constants.ReportKey; -import org.json.JSONObject; /** * @author owefsad diff --git a/dongtai-core/src/test/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyBuilderTest.java b/dongtai-core/src/test/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyBuilderTest.java index da5f31995..b1c83fd77 100644 --- a/dongtai-core/src/test/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyBuilderTest.java +++ b/dongtai-core/src/test/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyBuilderTest.java @@ -1,7 +1,7 @@ package io.dongtai.iast.core.handler.hookpoint.models.policy; +import com.alibaba.fastjson.JSONArray; import io.dongtai.iast.core.utils.PropertyUtils; -import org.json.JSONArray; import org.junit.*; import org.junit.function.ThrowingRunnable; @@ -38,7 +38,7 @@ public void run() throws PolicyException { public void testFetchFromFile() throws PolicyException { JSONArray policy = PolicyBuilder.fetchFromFile(POLICY_DIR + "policy.json"); Assert.assertNotNull("fetch file", policy); - Assert.assertEquals("fetch file", 3, policy.length()); + Assert.assertEquals("fetch file", 3, policy.size()); PolicyException exception; Map exceptionTest = new HashMap() {{ diff --git a/pom.xml b/pom.xml index ee0d8649c..58afa46db 100644 --- a/pom.xml +++ b/pom.xml @@ -37,6 +37,7 @@ 1.7.1 2.8.9 + 1.2.83 io.dongtai.iast From e6d89234a1205ea6bb774fb11ccaa2877e1e0e75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98niuerzhuang=E2=80=99?= <‘niuerzhuang@huoxian.cn’> Date: Tue, 18 Apr 2023 15:22:42 +0800 Subject: [PATCH 06/42] fix: Method call chain merge. --- .../iast/core/handler/hookpoint/graphy/GraphBuilder.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/graphy/GraphBuilder.java b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/graphy/GraphBuilder.java index ead871213..f18d246b1 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/graphy/GraphBuilder.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/graphy/GraphBuilder.java @@ -109,8 +109,10 @@ public static String convertToReport(List nodeList) { detail.put(ReportKey.METHOD_POOL, methodPool); detail.put(ReportKey.TRACE_ID, ContextManager.currentTraceId()); - for (GraphNode node : nodeList) { - methodPool.put(node.toJson()); + int nodeListSize = nodeList.size(); + for (int i=0;i Date: Tue, 18 Apr 2023 15:45:42 +0800 Subject: [PATCH 07/42] fix: Rollback iast.properties. --- .../src/main/resources/iast.properties | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/dongtai-agent/src/main/resources/iast.properties b/dongtai-agent/src/main/resources/iast.properties index 5a8d9cdb2..f98756581 100644 --- a/dongtai-agent/src/main/resources/iast.properties +++ b/dongtai-agent/src/main/resources/iast.properties @@ -1,18 +1,14 @@ -iast.response.name=DongTai Iast -iast.server.url=https://iast-beta.huoxian.cn/openapi -iast.server.token=GROUP1f6b147d1790d2226e49ae6b822d83f2f911b55b -iast.allhook.enable=false +iast.name=dongtai-Enterprise +iast.server.url=https://iast.io/openapi +iast.server.token=39133a96f5735c253edd908078846c1051824edc iast.dump.class.enable=false iast.dump.class.path=/tmp/iast-class-dump/ -iast.service.report.interval=30000 -app.name=DongTai -engine.status=start -engine.name=caec05c4106b4a24afb9b3dd12086a91 -jdk.version=1 -project.name=webgoat-server-8.2.2 +engine.name=java.action.github.com +project.name=ExampleApplication +project.create= +project.version=V1.0 +dongtai.app.template=0 iast.proxy.enable=false iast.proxy.host= iast.proxy.port= -iast.server.mode=local -dongtai.app.template=1 -project.version=V1.0 \ No newline at end of file +iast.server.mode=local \ No newline at end of file From f566e6313fbfbc02a5e2a0c1e28ec33c560b4ce0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98niuerzhuang=E2=80=99?= <‘niuerzhuang@huoxian.cn’> Date: Tue, 18 Apr 2023 15:47:45 +0800 Subject: [PATCH 08/42] fix: add com.alibaba to shade file. --- dongtai-common/pom.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dongtai-common/pom.xml b/dongtai-common/pom.xml index c1a6c0a4e..9911d1cdd 100644 --- a/dongtai-common/pom.xml +++ b/dongtai-common/pom.xml @@ -72,6 +72,10 @@ org.json ${shade-prefix}.org.json + + org.json + ${shade-prefix}.com.alibaba + From 6d7704b820bb095ea134d85ea124edfd8383d908 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98niuerzhuang=E2=80=99?= <‘niuerzhuang@huoxian.cn’> Date: Tue, 18 Apr 2023 15:51:37 +0800 Subject: [PATCH 09/42] fix: add com.alibaba to shade file. --- dongtai-common/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dongtai-common/pom.xml b/dongtai-common/pom.xml index 9911d1cdd..d65afb356 100644 --- a/dongtai-common/pom.xml +++ b/dongtai-common/pom.xml @@ -73,7 +73,7 @@ ${shade-prefix}.org.json - org.json + com.alibaba ${shade-prefix}.com.alibaba From d0162fcc97d27149d6793f3ec4727972d7c91fc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98niuerzhuang=E2=80=99?= <‘niuerzhuang@huoxian.cn’> Date: Tue, 18 Apr 2023 16:18:32 +0800 Subject: [PATCH 10/42] fix: org.json change to fastjson1.2.83. --- .../hookpoint/models/policy/PolicyBuilder.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyBuilder.java b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyBuilder.java index 28cea4fbc..4c218c908 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyBuilder.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyBuilder.java @@ -221,9 +221,10 @@ private static MethodMatcher buildMethodMatcher(JSONObject node) throws PolicyEx */ private static void parseStackDenyList(JSONObject node, SinkNode sinkNode) { try { - if (node.has(KEY_STACK_BLACKLIST)) { + if (node.containsKey(KEY_STACK_BLACKLIST)) { JSONArray arr = node.getJSONArray(KEY_STACK_BLACKLIST); - sinkNode.setStackDenyList(arr.toList().toArray(new String[0])); + sinkNode.setStackDenyList(arr.toArray(new String[0])); + org.json.JSONArray objects = new org.json.JSONArray(); } } catch (JSONException ignore) { DongTaiLog.warn(ErrorCode.get("POLICY_CONFIG_INVALID"), @@ -244,7 +245,7 @@ private static List parseTags(JSONObject node, PolicyNode policyNode) List tags = new ArrayList(); List untags = new ArrayList(); try { - if (node.has(KEY_TAGS)) { + if (node.containsKey(KEY_TAGS)) { JSONArray ts = node.getJSONArray(KEY_TAGS); for (Object o : ts) { String t = (String) o; @@ -265,7 +266,7 @@ private static List parseTags(JSONObject node, PolicyNode policyNode) } try { - if (node.has(KEY_TAGS)) { + if (node.containsKey(KEY_TAGS)) { JSONArray uts = node.getJSONArray(KEY_UNTAGS); for (Object o : uts) { String ut = (String) o; @@ -299,7 +300,7 @@ private static List parseTags(JSONObject node, PolicyNode policyNode) private static void parseCommand(JSONObject node, PropagatorNode propagatorNode) { try { - if (node.has(KEY_COMMAND)) { + if (node.containsKey(KEY_COMMAND)) { String cmdConfig = node.getString(KEY_COMMAND); if (cmdConfig == null) { return; From c9c1ed4bc667060c8a8da47701ab8dacd1ac2544 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98niuerzhuang=E2=80=99?= <‘niuerzhuang@huoxian.cn’> Date: Tue, 18 Apr 2023 16:22:00 +0800 Subject: [PATCH 11/42] fix: org.json change to fastjson1.2.83. --- .../iast/core/handler/hookpoint/models/policy/PolicyBuilder.java | 1 - 1 file changed, 1 deletion(-) diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyBuilder.java b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyBuilder.java index 4c218c908..d99cd5396 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyBuilder.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/policy/PolicyBuilder.java @@ -224,7 +224,6 @@ private static void parseStackDenyList(JSONObject node, SinkNode sinkNode) { if (node.containsKey(KEY_STACK_BLACKLIST)) { JSONArray arr = node.getJSONArray(KEY_STACK_BLACKLIST); sinkNode.setStackDenyList(arr.toArray(new String[0])); - org.json.JSONArray objects = new org.json.JSONArray(); } } catch (JSONException ignore) { DongTaiLog.warn(ErrorCode.get("POLICY_CONFIG_INVALID"), From 0d36b23e60aff80b628ab06c362e84cd3feb625d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98niuerzhuang=E2=80=99?= <‘niuerzhuang@huoxian.cn’> Date: Tue, 18 Apr 2023 18:15:26 +0800 Subject: [PATCH 12/42] fix: CodeQL Action upgrade to v2. --- .github/workflows/codeql-analysis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index a32cb192e..bb50f297d 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -61,7 +61,7 @@ jobs: uses: actions/checkout@v2 - name: Initialize CodeQL - uses: github/codeql-action/init@v1 + uses: github/codeql-action/init@v2 with: languages: ${{ matrix.language }} @@ -76,7 +76,7 @@ jobs: maven-version: 3.2.5 - name: Autobuild - uses: github/codeql-action/autobuild@v1 + uses: github/codeql-action/autobuild@v2 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + uses: github/codeql-action/analyze@v2 From 57832340f6d4e949066e53b67856ab6798d4c4dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98niuerzhuang=E2=80=99?= <‘niuerzhuang@huoxian.cn’> Date: Tue, 18 Apr 2023 18:33:56 +0800 Subject: [PATCH 13/42] fix: add dependency fastjson. --- dongtai-core/pom.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dongtai-core/pom.xml b/dongtai-core/pom.xml index f719bd441..d62fe471e 100755 --- a/dongtai-core/pom.xml +++ b/dongtai-core/pom.xml @@ -194,6 +194,12 @@ ${json.version} + + com.alibaba + fastjson + ${fastjson.version} + + org.projectlombok lombok From 21ce05875c2f02511c8679c30079807c4b443072 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98niuerzhuang=E2=80=99?= <‘niuerzhuang@huoxian.cn’> Date: Tue, 18 Apr 2023 18:36:55 +0800 Subject: [PATCH 14/42] fix: add dependency fastjson. --- dongtai-agent/pom.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dongtai-agent/pom.xml b/dongtai-agent/pom.xml index 125673afd..e42bbf651 100755 --- a/dongtai-agent/pom.xml +++ b/dongtai-agent/pom.xml @@ -84,6 +84,11 @@ gson ${gson.version} + + com.alibaba + fastjson + ${fastjson.version} + From 67c2f4419a25b00bcac335706a50f4957f66ac86 Mon Sep 17 00:00:00 2001 From: lostsnow Date: Tue, 18 Apr 2023 18:42:40 +0800 Subject: [PATCH 15/42] fixes JSR/RET for old jar when hook class --- .../iast/core/bytecode/IastClassFileTransformer.java | 4 +++- .../enhance/plugin/core/DispatchClassPlugin.java | 12 +++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/IastClassFileTransformer.java b/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/IastClassFileTransformer.java index 1788bec93..4c647cad4 100755 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/IastClassFileTransformer.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/IastClassFileTransformer.java @@ -119,7 +119,9 @@ public byte[] transform(final ClassLoader loader, || internalClassName.startsWith("io/dongtai/") || internalClassName.startsWith("com/secnium/iast/") || internalClassName.startsWith("java/lang/iast/") - || internalClassName.startsWith("cn/huoxian/iast/")) { + || internalClassName.startsWith("cn/huoxian/iast/") + || internalClassName.startsWith("META-INF/") + || "module-info".equals(internalClassName)) { return null; } diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/core/DispatchClassPlugin.java b/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/core/DispatchClassPlugin.java index f378892fe..e31b811f9 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/core/DispatchClassPlugin.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/core/DispatchClassPlugin.java @@ -36,12 +36,17 @@ public ClassVisitor dispatch(ClassVisitor classVisitor, ClassContext classContex } classContext.setMatchedClassName(matchedClassName); - return new ClassVisit(classVisitor, classContext, policy); + ClassVisit cv = new ClassVisit(classVisitor, classContext, policy); + if (cv.isNeedTransform()) { + return cv; + } + return classVisitor; } public class ClassVisit extends AbstractClassVisitor { private int classVersion; private final MethodAdapter[] methodAdapters; + private boolean needTransform; ClassVisit(ClassVisitor classVisitor, ClassContext classContext, Policy policy) { super(classVisitor, classContext, policy); @@ -52,6 +57,10 @@ public class ClassVisit extends AbstractClassVisitor { }; } + public boolean isNeedTransform() { + return this.needTransform; + } + @Override public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { @@ -88,6 +97,7 @@ public MethodVisitor visitMethod(final int access, final String name, final Stri } if (methodIsTransformed) { + this.needTransform = true; DongTaiLog.trace("rewrite method {} for listener[class={}]", matchedSignature, context.getClassName()); } From d3fc06ba0a1554046b4b613f67cd31305bfede01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98niuerzhuang=E2=80=99?= <‘niuerzhuang@huoxian.cn’> Date: Wed, 19 Apr 2023 15:41:16 +0800 Subject: [PATCH 16/42] fix: method chain merge. --- dongtai-agent/pom.xml | 4 + dongtai-common/pom.xml | 5 + .../iast/common/config/ConfigBuilder.java | 9 +- .../iast/common/config/RequestDeny.java | 6 +- .../iast/common/config/RequestDenyList.java | 10 +- .../iast/common/config/ConfigBuilderTest.java | 17 ++- .../utils/AbstractHttpClientUtilsTest.java | 11 +- dongtai-core/pom.xml | 15 +++ .../hookpoint/graphy/GraphBuilder.java | 114 ++++++++++++++---- .../models/policy/PolicyBuilder.java | 27 ++--- .../models/policy/PolicyManager.java | 2 +- .../models/policy/PolicyBuilderTest.java | 6 +- 12 files changed, 151 insertions(+), 75 deletions(-) diff --git a/dongtai-agent/pom.xml b/dongtai-agent/pom.xml index e42bbf651..7efe220eb 100755 --- a/dongtai-agent/pom.xml +++ b/dongtai-agent/pom.xml @@ -181,6 +181,10 @@ com.google ${shade-prefix}.com.google + + com.alibaba + ${shade-prefix}.com.alibaba + diff --git a/dongtai-common/pom.xml b/dongtai-common/pom.xml index d65afb356..63694515e 100644 --- a/dongtai-common/pom.xml +++ b/dongtai-common/pom.xml @@ -27,6 +27,11 @@ httpclient ${apache-httpclient.version} + + org.json + json + ${json.version} + com.alibaba fastjson diff --git a/dongtai-common/src/main/java/io/dongtai/iast/common/config/ConfigBuilder.java b/dongtai-common/src/main/java/io/dongtai/iast/common/config/ConfigBuilder.java index 4ad9748f6..39a3ff44a 100644 --- a/dongtai-common/src/main/java/io/dongtai/iast/common/config/ConfigBuilder.java +++ b/dongtai-common/src/main/java/io/dongtai/iast/common/config/ConfigBuilder.java @@ -1,9 +1,6 @@ package io.dongtai.iast.common.config; -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONArray; -import com.alibaba.fastjson.JSONException; -import com.alibaba.fastjson.JSONObject; +import org.json.*; import java.util.HashMap; import java.util.Map; @@ -47,7 +44,7 @@ public Config getConfig(ConfigKey key) { public void updateFromRemote(String content) { JSONObject config = null; try { - JSONObject json = JSON.parseObject(content); + JSONObject json = new JSONObject(content); config = json.getJSONObject("data"); } catch (JSONException ignore) { } @@ -94,7 +91,7 @@ private void updateInt(JSONObject config, ConfigKey.JsonKey jsonKey) { try { Config conf = (Config) getConfig(jsonKey.getConfigKey()); if (conf != null) { - Integer value = config.getIntValue(jsonKey.getKey()); + Integer value = config.getInt(jsonKey.getKey()); conf.setValue(value); } } catch (Throwable ignore) { diff --git a/dongtai-common/src/main/java/io/dongtai/iast/common/config/RequestDeny.java b/dongtai-common/src/main/java/io/dongtai/iast/common/config/RequestDeny.java index 0efedb358..6b4e10eb3 100644 --- a/dongtai-common/src/main/java/io/dongtai/iast/common/config/RequestDeny.java +++ b/dongtai-common/src/main/java/io/dongtai/iast/common/config/RequestDeny.java @@ -1,9 +1,7 @@ package io.dongtai.iast.common.config; - - -import com.alibaba.fastjson.JSONException; -import com.alibaba.fastjson.JSONObject; +import org.json.JSONException; +import org.json.JSONObject; import java.util.*; diff --git a/dongtai-common/src/main/java/io/dongtai/iast/common/config/RequestDenyList.java b/dongtai-common/src/main/java/io/dongtai/iast/common/config/RequestDenyList.java index b7c7713a8..ca71c2628 100644 --- a/dongtai-common/src/main/java/io/dongtai/iast/common/config/RequestDenyList.java +++ b/dongtai-common/src/main/java/io/dongtai/iast/common/config/RequestDenyList.java @@ -1,6 +1,6 @@ package io.dongtai.iast.common.config; -import com.alibaba.fastjson.JSONArray; +import org.json.JSONArray; import java.util.*; @@ -8,18 +8,18 @@ public class RequestDenyList { private final List> denies = new ArrayList>(); public static RequestDenyList parse(JSONArray config) { - if (config == null || config.size() == 0) { + if (config == null || config.length() == 0) { return null; } RequestDenyList denyList = new RequestDenyList(); - int orLen = config.size(); + int orLen = config.length(); for (int i = 0; i < orLen; i++) { JSONArray andConfig = config.getJSONArray(i); - if (andConfig == null || andConfig.size() == 0) { + if (andConfig == null || andConfig.length() == 0) { continue; } - int andLen = andConfig.size(); + int andLen = andConfig.length(); List andList = new ArrayList(); for (int j = 0; j < andLen; j++) { RequestDeny requestDeny = RequestDeny.parse(andConfig.getJSONObject(j)); diff --git a/dongtai-common/src/test/java/io/dongtai/iast/common/config/ConfigBuilderTest.java b/dongtai-common/src/test/java/io/dongtai/iast/common/config/ConfigBuilderTest.java index f32b845bb..d00075220 100644 --- a/dongtai-common/src/test/java/io/dongtai/iast/common/config/ConfigBuilderTest.java +++ b/dongtai-common/src/test/java/io/dongtai/iast/common/config/ConfigBuilderTest.java @@ -1,7 +1,6 @@ package io.dongtai.iast.common.config; -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONObject; +import org.json.JSONObject; import org.junit.Assert; import org.junit.Test; @@ -31,13 +30,13 @@ public void testGetConfigAndUpdate() { // update configString = "{\"gather_res_body\": false}"; - configJson = JSON.parseObject(configString); + configJson = new JSONObject(configString); builder.update(configJson); configString = "{\"method_pool_max_length\": 1000}"; - configJson = JSON.parseObject(configString); + configJson = new JSONObject(configString); builder.update(configJson); configString = "{\"blacklist_rules\": [[{\"target_type\": \"HEADER_KEY\", \"operator\": \"EXISTS\", \"value\": \"key1\"}]]}"; - configJson = JSON.parseObject(configString); + configJson = new JSONObject(configString); builder.update(configJson); RequestDenyList expectRequestDenyList = new RequestDenyList(); @@ -54,16 +53,16 @@ public void testGetConfigAndUpdate() { // update invalid configString = "{\"gather_res_body\": \"invalid\"}"; - configJson = JSON.parseObject(configString); + configJson = new JSONObject(configString); builder.update(configJson); configString = "{\"method_pool_max_length\": \"invalid\"}"; - configJson = JSON.parseObject(configString); + configJson = new JSONObject(configString); builder.update(configJson); configString = "{\"blacklist_rules\": \"invalid\"}"; - configJson = JSON.parseObject(configString); + configJson = new JSONObject(configString); builder.update(configJson); configString = "{\"invalid\": \"invalid\"}"; - configJson = JSON.parseObject(configString); + configJson = new JSONObject(configString); builder.update(configJson); reportResponseBody = builder.get(ConfigKey.REPORT_RESPONSE_BODY); diff --git a/dongtai-common/src/test/java/io/dongtai/iast/common/utils/AbstractHttpClientUtilsTest.java b/dongtai-common/src/test/java/io/dongtai/iast/common/utils/AbstractHttpClientUtilsTest.java index 9db189b4c..e08e7204c 100644 --- a/dongtai-common/src/test/java/io/dongtai/iast/common/utils/AbstractHttpClientUtilsTest.java +++ b/dongtai-common/src/test/java/io/dongtai/iast/common/utils/AbstractHttpClientUtilsTest.java @@ -1,13 +1,12 @@ package io.dongtai.iast.common.utils; -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONObject; import io.dongtai.iast.common.enums.HttpMethods; import io.dongtai.log.DongTaiLog; import io.dongtai.log.ErrorCode; import org.apache.http.client.config.RequestConfig; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; +import org.json.JSONObject; import org.junit.*; import java.io.ByteArrayOutputStream; @@ -58,15 +57,15 @@ public void sendRequest() { url = BASE_URL + "/api/v1/captcha/refresh"; resp = AbstractHttpClientUtils.sendRequest(HttpMethods.GET, url, null, headers, 0, "", -1, null); - respObj = JSON.parseObject(resp.toString()); - status = respObj.getInteger("status"); + respObj = new JSONObject(resp.toString()); + status = respObj.getInt("status"); Assert.assertEquals("captcha/refresh status", 201, status); url = BASE_URL + "/api/v1/user/login"; data = "{\"username\":\"test\",\"password\":\"test\",\"captcha\":\"test\",\"captcha_hash_key\":\"test\"}"; resp = AbstractHttpClientUtils.sendRequest(HttpMethods.POST, url, data, headers, 0, "", -1, null); - respObj = JSON.parseObject(resp.toString()); - status = respObj.getInteger("status"); + respObj = new JSONObject(resp.toString()); + status = respObj.getInt("status"); Assert.assertEquals("user/login status", 202, status); url = BASE_URL + "/api/v1/profiles"; diff --git a/dongtai-core/pom.xml b/dongtai-core/pom.xml index d62fe471e..7242e6548 100755 --- a/dongtai-core/pom.xml +++ b/dongtai-core/pom.xml @@ -252,6 +252,21 @@ ${pkg.jdom.version} test + + javax.xml.bind + jaxb-api + 2.3.0 + + + com.sun.xml.bind + jaxb-core + 2.3.0.1 + + + com.sun.xml.bind + jaxb-impl + 2.3.0.1 + 2.8.9 1.2.83 + 2.0.28 io.dongtai.iast From fcae53d01c762a7cd373d6be616ad1ccee926822 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98niuerzhuang=E2=80=99?= <‘niuerzhuang@huoxian.cn’> Date: Fri, 21 Apr 2023 10:20:18 +0800 Subject: [PATCH 20/42] fix: upgrade to fastjson2. --- .../dongtai/iast/core/handler/hookpoint/models/MethodEvent.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/MethodEvent.java b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/MethodEvent.java index 968eb2523..476c5c585 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/MethodEvent.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/MethodEvent.java @@ -1,6 +1,6 @@ package io.dongtai.iast.core.handler.hookpoint.models; -import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson2.JSONObject; import io.dongtai.iast.core.handler.hookpoint.models.policy.TaintPosition; import io.dongtai.iast.core.handler.hookpoint.models.taint.range.TaintRanges; import io.dongtai.iast.core.utils.StringUtils; From 6a18d5ca42a1196c5df3586e81936ec4f986838d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98niuerzhuang=E2=80=99?= <‘niuerzhuang@huoxian.cn’> Date: Fri, 21 Apr 2023 11:21:09 +0800 Subject: [PATCH 21/42] feature: sink point add stacks. --- .../handler/hookpoint/graphy/GraphBuilder.java | 5 +++++ .../core/handler/hookpoint/models/MethodEvent.java | 14 ++++++++++++++ .../vulscan/dynamic/DynamicPropagatorScanner.java | 1 + 3 files changed, 20 insertions(+) diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/graphy/GraphBuilder.java b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/graphy/GraphBuilder.java index 9fcae245c..7d64f461c 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/graphy/GraphBuilder.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/graphy/GraphBuilder.java @@ -179,6 +179,11 @@ public static JSONObject toJson(MethodEvent event) { value.put("traceId", event.traceId); } + if (null != event.getStacks()){ + JSONArray methodStacksArray = new JSONArray(event.getStacks()); + value.put("stacks",methodStacksArray); + } + return value; } } diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/MethodEvent.java b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/MethodEvent.java index 476c5c585..856878b7c 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/MethodEvent.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/models/MethodEvent.java @@ -92,6 +92,8 @@ public class MethodEvent { private StackTraceElement callStack; + private List stacks; + public String traceId = null; public static class Parameter { @@ -302,4 +304,16 @@ public String obj2String(Object value) { } return sb.toString(); } + + public List getStacks() { + return stacks; + } + + public void setStacks(StackTraceElement[] stackTraceElements) { + List stacks = new ArrayList<>(); + for(StackTraceElement stackTraceElement:stackTraceElements){ + stacks.add(stackTraceElement.toString()); + } + this.stacks = stacks; + } } diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/vulscan/dynamic/DynamicPropagatorScanner.java b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/vulscan/dynamic/DynamicPropagatorScanner.java index 73c60be05..0a0f78583 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/vulscan/dynamic/DynamicPropagatorScanner.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/vulscan/dynamic/DynamicPropagatorScanner.java @@ -66,6 +66,7 @@ public void scan(MethodEvent event, SinkNode sinkNode) { int invokeId = SpyDispatcherImpl.INVOKE_ID_SEQUENCER.getAndIncrement(); event.setInvokeId(invokeId); event.setTaintPositions(sinkNode.getSources(), null); + event.setStacks(stackTraceElements); EngineManager.TRACK_MAP.addTrackMethod(invokeId, event); } From b5e6b50c9912e244223dc4c7749b85901e397b4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98niuerzhuang=E2=80=99?= <‘niuerzhuang@huoxian.cn’> Date: Fri, 21 Apr 2023 12:07:10 +0800 Subject: [PATCH 22/42] fix: pom.xml --- dongtai-core/pom.xml | 4 ---- pom.xml | 1 - 2 files changed, 5 deletions(-) diff --git a/dongtai-core/pom.xml b/dongtai-core/pom.xml index aaf531f9e..8f513948c 100755 --- a/dongtai-core/pom.xml +++ b/dongtai-core/pom.xml @@ -105,10 +105,6 @@ com.alibaba ${shade-prefix}.com.alibaba - - com.sun.xml - ${shade-prefix}.com.sun.xml - diff --git a/pom.xml b/pom.xml index 973cd9f48..4f4d68691 100644 --- a/pom.xml +++ b/pom.xml @@ -37,7 +37,6 @@ 1.7.1 2.8.9 - 1.2.83 2.0.28 From 87e4ad2467704f58e092e2b491e9db4c4a302b71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98niuerzhuang=E2=80=99?= <‘niuerzhuang@huoxian.cn’> Date: Fri, 21 Apr 2023 14:14:24 +0800 Subject: [PATCH 23/42] fix: AbstractNormalVulScan.sendReport --- .../io/dongtai/iast/common/constants/ReportKey.java | 1 + .../vulscan/normal/AbstractNormalVulScan.java | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/dongtai-common/src/main/java/io/dongtai/iast/common/constants/ReportKey.java b/dongtai-common/src/main/java/io/dongtai/iast/common/constants/ReportKey.java index 5775ac3f8..73b922e9e 100644 --- a/dongtai-common/src/main/java/io/dongtai/iast/common/constants/ReportKey.java +++ b/dongtai-common/src/main/java/io/dongtai/iast/common/constants/ReportKey.java @@ -28,4 +28,5 @@ public class ReportKey { public static final String VULN_CALLER = "appCaller"; public static final String API_DATA = "apiData"; public static final String TRACE_ID = "traceId"; + public static final String STACKS = "stacks"; } diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/vulscan/normal/AbstractNormalVulScan.java b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/vulscan/normal/AbstractNormalVulScan.java index ab9873345..22fe27f99 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/vulscan/normal/AbstractNormalVulScan.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/vulscan/normal/AbstractNormalVulScan.java @@ -10,7 +10,9 @@ import io.dongtai.iast.core.utils.StackUtils; +import java.util.ArrayList; import java.util.Collection; +import java.util.List; import java.util.Map; /** @@ -27,6 +29,8 @@ public void sendReport(StackTraceElement[] stacks, String vulType) { JSONObject report = new JSONObject(); JSONObject detail = new JSONObject(); JSONArray vulStacks = new JSONArray(); + List stacksList = new ArrayList<>(); + JSONArray stacksJsonArray = new JSONArray(stacksList); report.put(ReportKey.TYPE, ReportType.VULN_NORMAL); report.put(ReportKey.DETAIL, detail); @@ -50,6 +54,12 @@ public void sendReport(StackTraceElement[] stacks, String vulType) { detail.put(ReportKey.REPLAY_REQUEST, requestMeta.get("replay-request")); detail.put(ReportKey.VULN_CALLER, vulStacks); + // 获取方法调用栈 + for(StackTraceElement stackTraceElement:stacks){ + stacksList.add(stackTraceElement.toString()); + } + detail.put(ReportKey.STACKS, stacksJsonArray); + for (StackTraceElement element : stacks) { vulStacks.add(element.toString()); } From 28e829150122f5229545e0d55d166ddf6b07ac25 Mon Sep 17 00:00:00 2001 From: lostsnow Date: Fri, 21 Apr 2023 17:14:12 +0800 Subject: [PATCH 24/42] fixes exception when check method collect is allowed --- .../iast/core/handler/hookpoint/SpyDispatcherImpl.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/SpyDispatcherImpl.java b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/SpyDispatcherImpl.java index 22b25a0b4..8462f4c3b 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/SpyDispatcherImpl.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/SpyDispatcherImpl.java @@ -711,6 +711,10 @@ private boolean isCollectAllowed(boolean isEnterEntry) { return false; } + if (EngineManager.TRACK_MAP.get() == null) { + return false; + } + Integer methodPoolMaxSize = ConfigBuilder.getInstance().get(ConfigKey.REPORT_MAX_METHOD_POOL_SIZE); if (methodPoolMaxSize != null && methodPoolMaxSize > 0 && EngineManager.TRACK_MAP.get().size() >= methodPoolMaxSize) { From 5f8ecc881c300e73f63dc7e194b5f4e74c2366d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98niuerzhuang=E2=80=99?= <‘niuerzhuang@huoxian.cn’> Date: Sun, 23 Apr 2023 12:33:09 +0800 Subject: [PATCH 25/42] fix: AbstractNormalVulScan.sendReport --- .../io/dongtai/iast/common/constants/ReportKey.java | 1 - .../vulscan/normal/AbstractNormalVulScan.java | 10 ---------- 2 files changed, 11 deletions(-) diff --git a/dongtai-common/src/main/java/io/dongtai/iast/common/constants/ReportKey.java b/dongtai-common/src/main/java/io/dongtai/iast/common/constants/ReportKey.java index 73b922e9e..5775ac3f8 100644 --- a/dongtai-common/src/main/java/io/dongtai/iast/common/constants/ReportKey.java +++ b/dongtai-common/src/main/java/io/dongtai/iast/common/constants/ReportKey.java @@ -28,5 +28,4 @@ public class ReportKey { public static final String VULN_CALLER = "appCaller"; public static final String API_DATA = "apiData"; public static final String TRACE_ID = "traceId"; - public static final String STACKS = "stacks"; } diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/vulscan/normal/AbstractNormalVulScan.java b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/vulscan/normal/AbstractNormalVulScan.java index 22fe27f99..ab9873345 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/vulscan/normal/AbstractNormalVulScan.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/vulscan/normal/AbstractNormalVulScan.java @@ -10,9 +10,7 @@ import io.dongtai.iast.core.utils.StackUtils; -import java.util.ArrayList; import java.util.Collection; -import java.util.List; import java.util.Map; /** @@ -29,8 +27,6 @@ public void sendReport(StackTraceElement[] stacks, String vulType) { JSONObject report = new JSONObject(); JSONObject detail = new JSONObject(); JSONArray vulStacks = new JSONArray(); - List stacksList = new ArrayList<>(); - JSONArray stacksJsonArray = new JSONArray(stacksList); report.put(ReportKey.TYPE, ReportType.VULN_NORMAL); report.put(ReportKey.DETAIL, detail); @@ -54,12 +50,6 @@ public void sendReport(StackTraceElement[] stacks, String vulType) { detail.put(ReportKey.REPLAY_REQUEST, requestMeta.get("replay-request")); detail.put(ReportKey.VULN_CALLER, vulStacks); - // 获取方法调用栈 - for(StackTraceElement stackTraceElement:stacks){ - stacksList.add(stackTraceElement.toString()); - } - detail.put(ReportKey.STACKS, stacksJsonArray); - for (StackTraceElement element : stacks) { vulStacks.add(element.toString()); } From 6c15feba4db11525b9691dbe0856ee71939cc8eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98niuerzhuang=E2=80=99?= <‘niuerzhuang@huoxian.cn’> Date: Tue, 25 Apr 2023 11:57:52 +0800 Subject: [PATCH 26/42] feature: allow data report --- .../io/dongtai/iast/agent/AgentLauncher.java | 11 +--- .../iast/agent/manager/EngineManager.java | 4 +- .../agent/monitor/MonitorDaemonThread.java | 5 +- .../agent/monitor/impl/AgentStateMonitor.java | 57 ++++++++++++++----- .../agent/report/AgentRegisterReport.java | 6 -- .../dongtai/iast/common/state/AgentState.java | 21 +++++++ .../io/dongtai/iast/core/EngineManager.java | 2 +- 7 files changed, 73 insertions(+), 33 deletions(-) diff --git a/dongtai-agent/src/main/java/io/dongtai/iast/agent/AgentLauncher.java b/dongtai-agent/src/main/java/io/dongtai/iast/agent/AgentLauncher.java index 4a5385a55..d4dcc4dab 100755 --- a/dongtai-agent/src/main/java/io/dongtai/iast/agent/AgentLauncher.java +++ b/dongtai-agent/src/main/java/io/dongtai/iast/agent/AgentLauncher.java @@ -152,6 +152,8 @@ public static void agentmain(String args, Instrumentation inst) { public static synchronized void uninstall() { EngineManager engineManager = EngineManager.getInstance(); engineManager.uninstall(); + // 手动卸载时将线程停止 + MonitorDaemonThread.isExit = true; } /** @@ -164,13 +166,6 @@ private static void install(final Instrumentation inst) { if (send) { LogCollector.extractFluent(); DongTaiLog.info("Agent registered successfully."); - Boolean agentStat = AgentRegisterReport.agentStat(); - if (!agentStat) { - AgentStateMonitor.isCoreRegisterStart = false; - DongTaiLog.info("Detection engine not started, agent waiting to be audited."); - } else { - AgentStateMonitor.isCoreRegisterStart = true; - } shutdownHook = new ShutdownThread(); Runtime.getRuntime().addShutdownHook(shutdownHook); loadEngine(inst); @@ -187,7 +182,7 @@ private static void install(final Instrumentation inst) { private static void loadEngine(final Instrumentation inst) { EngineManager engineManager = EngineManager.getInstance(inst, LAUNCH_MODE, EngineManager.getPID(), AGENT_STATE); MonitorDaemonThread daemonThread = MonitorDaemonThread.getInstance(engineManager); - if (MonitorDaemonThread.delayTime <= 0 && AgentStateMonitor.isCoreRegisterStart) { + if (MonitorDaemonThread.delayTime <= 0) { daemonThread.startEngine(); } diff --git a/dongtai-agent/src/main/java/io/dongtai/iast/agent/manager/EngineManager.java b/dongtai-agent/src/main/java/io/dongtai/iast/agent/manager/EngineManager.java index 2fcd8ecaa..27f141dc1 100644 --- a/dongtai-agent/src/main/java/io/dongtai/iast/agent/manager/EngineManager.java +++ b/dongtai-agent/src/main/java/io/dongtai/iast/agent/manager/EngineManager.java @@ -2,6 +2,7 @@ import io.dongtai.iast.agent.*; import io.dongtai.iast.agent.fallback.FallbackManager; +import io.dongtai.iast.agent.monitor.MonitorDaemonThread; import io.dongtai.iast.agent.report.AgentRegisterReport; import io.dongtai.iast.agent.util.*; import io.dongtai.iast.common.state.AgentState; @@ -36,7 +37,7 @@ public class EngineManager { private final IastProperties properties; private final String launchMode; private Class classOfEngine; - private FallbackManager fallbackManager; + private final FallbackManager fallbackManager; private final AgentState agentState; /** @@ -175,6 +176,7 @@ public boolean install() { String.class) .invoke(null, launchMode, this.properties.getPropertiesFilePath(), AgentRegisterReport.getAgentId(), inst, agentPath); + MonitorDaemonThread.isExit = false; return true; } catch (Throwable e) { DongTaiLog.error(ErrorCode.AGENT_REFLECTION_INSTALL_FAILED, e); diff --git a/dongtai-agent/src/main/java/io/dongtai/iast/agent/monitor/MonitorDaemonThread.java b/dongtai-agent/src/main/java/io/dongtai/iast/agent/monitor/MonitorDaemonThread.java index 8009d58cc..6d9882b72 100644 --- a/dongtai-agent/src/main/java/io/dongtai/iast/agent/monitor/MonitorDaemonThread.java +++ b/dongtai-agent/src/main/java/io/dongtai/iast/agent/monitor/MonitorDaemonThread.java @@ -55,10 +55,8 @@ public void run() { if (MonitorDaemonThread.delayTime > 0) { try { Thread.sleep(delayTime); - } catch (InterruptedException ignore) { - } - if (AgentStateMonitor.isCoreRegisterStart) { startEngine(); + } catch (InterruptedException ignore) { } } // 引擎启动成功后,创建子线程执行monitor任务 @@ -81,7 +79,6 @@ public void startEngine() { // jdk8以上 status = engineManager.extractPackage(); status = status && engineManager.install(); - status = status && engineManager.start(); } if (!status) { DongTaiLog.info("DongTai IAST started failure"); diff --git a/dongtai-agent/src/main/java/io/dongtai/iast/agent/monitor/impl/AgentStateMonitor.java b/dongtai-agent/src/main/java/io/dongtai/iast/agent/monitor/impl/AgentStateMonitor.java index ada93c5c3..63b1b03c4 100644 --- a/dongtai-agent/src/main/java/io/dongtai/iast/agent/monitor/impl/AgentStateMonitor.java +++ b/dongtai-agent/src/main/java/io/dongtai/iast/agent/monitor/impl/AgentStateMonitor.java @@ -11,6 +11,7 @@ import io.dongtai.iast.agent.util.ThreadUtils; import io.dongtai.iast.common.constants.AgentConstant; import io.dongtai.iast.common.constants.ApiPath; +import io.dongtai.iast.common.state.AgentState; import io.dongtai.iast.common.state.State; import io.dongtai.iast.common.state.StateCause; import io.dongtai.log.DongTaiLog; @@ -24,7 +25,6 @@ */ public class AgentStateMonitor implements IMonitor { private final EngineManager engineManager; - public static Boolean isCoreRegisterStart = false; private static final String NAME = "AgentStateMonitor"; public AgentStateMonitor(EngineManager engineManager) { @@ -38,37 +38,65 @@ public String getName() { @Override public void check() { + AgentState agentState = this.engineManager.getAgentState(); try { - if (this.engineManager.getAgentState().getState() == null) { + if (agentState.getState() == null) { return; } - if (this.engineManager.getAgentState().isUninstalledByCli()) { + if (agentState.isUninstalledByCli()) { HttpClientUtils.sendPost(ApiPath.ACTUAL_ACTION, - HeartBeatReport.generateAgentActualActionMsg(this.engineManager.getAgentState())); + HeartBeatReport.generateAgentActualActionMsg(agentState)); return; } - if (!this.engineManager.getAgentState().isFallback() && !this.engineManager.getAgentState().isException()) { - String expectState = checkExpectState(); - if (State.RUNNING.equals(expectState) && this.engineManager.getAgentState().isPaused()) { + Map stringStringMap = checkExpectState(); + // 默认值 + String expectState = "other"; + String allowReport = "1"; + + if (stringStringMap != null) { + expectState = stringStringMap.get("exceptRunningStatus"); + allowReport = stringStringMap.get("isAllowDateReport"); + } + + if (!agentState.isAllowReport(allowReport)) { + if (null == agentState.getAllowReport()) { + DongTaiLog.info("engine is not allowed to report data"); + agentState.setAllowReport(allowReport); + return; + } + if (!allowReport.equals(agentState.getAllowReport())) { + DongTaiLog.info("engine is not allowed to report data"); + agentState.setAllowReport(allowReport); + engineManager.stop(); + } + } else if (agentState.isAllowReport(allowReport) && !allowReport.equals(agentState.getAllowReport())) { + DongTaiLog.info("engine is allowed to report data"); + agentState.setAllowReport(allowReport); + engineManager.start(); + return; + } + + if (!agentState.isFallback() && !agentState.isException()) { + if (State.RUNNING.equals(expectState) && agentState.isPaused()) { DongTaiLog.info("engine start by server expect state"); engineManager.start(); engineManager.getAgentState().setState(State.RUNNING).setCause(StateCause.RUNNING_BY_SERVER); - } else if (State.PAUSED.equals(expectState) && this.engineManager.getAgentState().isRunning()) { + } else if (State.PAUSED.equals(expectState) && agentState.isRunning()) { DongTaiLog.info("engine stop by server expect state"); engineManager.stop(); engineManager.getAgentState().setState(State.PAUSED).setCause(StateCause.PAUSE_BY_SERVER); } } HttpClientUtils.sendPost(ApiPath.ACTUAL_ACTION, - HeartBeatReport.generateAgentActualActionMsg(this.engineManager.getAgentState())); + HeartBeatReport.generateAgentActualActionMsg(agentState)); } catch (Throwable t) { DongTaiLog.warn(ErrorCode.AGENT_MONITOR_THREAD_CHECK_FAILED, getName(), t); } } - private String checkExpectState() { + private Map checkExpectState() { try { Map parameters = new HashMap(); parameters.put("agentId", String.valueOf(AgentRegisterReport.getAgentId())); @@ -76,12 +104,15 @@ private String checkExpectState() { if (!respRaw.isEmpty()) { JSONObject resp = JSON.parseObject(respRaw); JSONObject data = (JSONObject) resp.get("data"); - return data.get("exceptRunningStatus").toString(); + Map objectObjectHashMap = new HashMap<>(2); + String s = data.toJSONString(); + objectObjectHashMap = JSON.parseObject(s, Map.class); + return objectObjectHashMap; } } catch (Throwable e) { - return "other"; + return null; } - return "other"; + return null; } @Override diff --git a/dongtai-agent/src/main/java/io/dongtai/iast/agent/report/AgentRegisterReport.java b/dongtai-agent/src/main/java/io/dongtai/iast/agent/report/AgentRegisterReport.java index 53030287f..8b0a9170e 100644 --- a/dongtai-agent/src/main/java/io/dongtai/iast/agent/report/AgentRegisterReport.java +++ b/dongtai-agent/src/main/java/io/dongtai/iast/agent/report/AgentRegisterReport.java @@ -29,7 +29,6 @@ public class AgentRegisterReport { public static AgentRegisterReport INSTANCE; private String projectName = null; private static Integer agentId = -1; - private static Integer coreRegisterStart = 1; final IServer server = ServerDetect.getWebserver(); private static String AGENT_NAME = null; private static String HOST_NAME = null; @@ -265,7 +264,6 @@ private void setAgentData(StringBuilder responseRaw) { if (status == 201) { JSONObject data = (JSONObject) responseObj.get("data"); agentId = (Integer) data.get("id"); - coreRegisterStart = (Integer) data.get("coreAutoStart"); } else { DongTaiLog.error(ErrorCode.AGENT_REGISTER_RESPONSE_CODE_INVALID, responseRaw); } @@ -275,10 +273,6 @@ private void setAgentData(StringBuilder responseRaw) { } } - public static Boolean agentStat() { - return coreRegisterStart == 1; - } - private static String generateUUID() { String uuidPath = IastProperties.getInstance().getUUIDPath(); if (uuidPath == null || uuidPath.isEmpty()) { diff --git a/dongtai-common/src/main/java/io/dongtai/iast/common/state/AgentState.java b/dongtai-common/src/main/java/io/dongtai/iast/common/state/AgentState.java index e16200ace..9ac88e875 100644 --- a/dongtai-common/src/main/java/io/dongtai/iast/common/state/AgentState.java +++ b/dongtai-common/src/main/java/io/dongtai/iast/common/state/AgentState.java @@ -5,6 +5,7 @@ public class AgentState { private State pendingState; private StateCause cause; private boolean fallback; + private Integer allowReport; private static AgentState INSTANCE; public static AgentState getInstance() { @@ -95,4 +96,24 @@ public void fallbackRecover() { public boolean isFallback() { return this.fallback; } + + public Boolean isAllowReport(String allowReport) { + if (null == allowReport) { + return true; + } else { + return Integer.valueOf(allowReport).equals(1); + } + } + + public Boolean isAllowReport() { + return 1 == this.allowReport; + } + + public void setAllowReport(String allowReport) { + this.allowReport = Integer.valueOf(allowReport); + } + + public String getAllowReport() { + return String.valueOf(allowReport); + } } diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/EngineManager.java b/dongtai-core/src/main/java/io/dongtai/iast/core/EngineManager.java index 150670aa4..3bca2f889 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/EngineManager.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/EngineManager.java @@ -89,7 +89,7 @@ public static int getRequestCount() { * @return true - 引擎已启动;false - 引擎未启动 */ public static boolean isEngineRunning() { - return AGENT_STATE.isRunning() && AGENT_STATE.getPendingState() == null; + return AGENT_STATE.isRunning() && AGENT_STATE.getPendingState() == null && AGENT_STATE.isAllowReport(); } public boolean isEnableDumpClass() { From 8619d8f5708f852d6824bcc401b9d7e28c1fe981 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98niuerzhuang=E2=80=99?= <‘niuerzhuang@huoxian.cn’> Date: Tue, 25 Apr 2023 12:18:18 +0800 Subject: [PATCH 27/42] feature: allow data report --- .../iast/agent/monitor/impl/AgentStateMonitor.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/dongtai-agent/src/main/java/io/dongtai/iast/agent/monitor/impl/AgentStateMonitor.java b/dongtai-agent/src/main/java/io/dongtai/iast/agent/monitor/impl/AgentStateMonitor.java index 63b1b03c4..5dad68047 100644 --- a/dongtai-agent/src/main/java/io/dongtai/iast/agent/monitor/impl/AgentStateMonitor.java +++ b/dongtai-agent/src/main/java/io/dongtai/iast/agent/monitor/impl/AgentStateMonitor.java @@ -58,6 +58,9 @@ public void check() { if (stringStringMap != null) { expectState = stringStringMap.get("exceptRunningStatus"); allowReport = stringStringMap.get("isAllowDateReport"); + if ("null".equals(allowReport)){ + allowReport = "1"; + } } if (!agentState.isAllowReport(allowReport)) { @@ -70,6 +73,7 @@ public void check() { DongTaiLog.info("engine is not allowed to report data"); agentState.setAllowReport(allowReport); engineManager.stop(); + return; } } else if (agentState.isAllowReport(allowReport) && !allowReport.equals(agentState.getAllowReport())) { DongTaiLog.info("engine is allowed to report data"); @@ -78,15 +82,15 @@ public void check() { return; } - if (!agentState.isFallback() && !agentState.isException()) { + if (!agentState.isFallback() && !agentState.isException() && agentState.isAllowReport()) { if (State.RUNNING.equals(expectState) && agentState.isPaused()) { DongTaiLog.info("engine start by server expect state"); engineManager.start(); - engineManager.getAgentState().setState(State.RUNNING).setCause(StateCause.RUNNING_BY_SERVER); + agentState.setState(State.RUNNING).setCause(StateCause.RUNNING_BY_SERVER); } else if (State.PAUSED.equals(expectState) && agentState.isRunning()) { DongTaiLog.info("engine stop by server expect state"); engineManager.stop(); - engineManager.getAgentState().setState(State.PAUSED).setCause(StateCause.PAUSE_BY_SERVER); + agentState.setState(State.PAUSED).setCause(StateCause.PAUSE_BY_SERVER); } } HttpClientUtils.sendPost(ApiPath.ACTUAL_ACTION, From 1ce229fc4f1b41906e0935eea63576b71937ff7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98niuerzhuang=E2=80=99?= <‘niuerzhuang@huoxian.cn’> Date: Tue, 25 Apr 2023 14:20:28 +0800 Subject: [PATCH 28/42] feature: allow data report --- .../src/main/java/io/dongtai/iast/agent/AgentLauncher.java | 2 -- .../java/io/dongtai/iast/agent/manager/EngineManager.java | 1 - .../dongtai/iast/agent/monitor/impl/AgentStateMonitor.java | 5 +---- 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/dongtai-agent/src/main/java/io/dongtai/iast/agent/AgentLauncher.java b/dongtai-agent/src/main/java/io/dongtai/iast/agent/AgentLauncher.java index d4dcc4dab..7752663cb 100755 --- a/dongtai-agent/src/main/java/io/dongtai/iast/agent/AgentLauncher.java +++ b/dongtai-agent/src/main/java/io/dongtai/iast/agent/AgentLauncher.java @@ -152,8 +152,6 @@ public static void agentmain(String args, Instrumentation inst) { public static synchronized void uninstall() { EngineManager engineManager = EngineManager.getInstance(); engineManager.uninstall(); - // 手动卸载时将线程停止 - MonitorDaemonThread.isExit = true; } /** diff --git a/dongtai-agent/src/main/java/io/dongtai/iast/agent/manager/EngineManager.java b/dongtai-agent/src/main/java/io/dongtai/iast/agent/manager/EngineManager.java index 27f141dc1..ec818175d 100644 --- a/dongtai-agent/src/main/java/io/dongtai/iast/agent/manager/EngineManager.java +++ b/dongtai-agent/src/main/java/io/dongtai/iast/agent/manager/EngineManager.java @@ -176,7 +176,6 @@ public boolean install() { String.class) .invoke(null, launchMode, this.properties.getPropertiesFilePath(), AgentRegisterReport.getAgentId(), inst, agentPath); - MonitorDaemonThread.isExit = false; return true; } catch (Throwable e) { DongTaiLog.error(ErrorCode.AGENT_REFLECTION_INSTALL_FAILED, e); diff --git a/dongtai-agent/src/main/java/io/dongtai/iast/agent/monitor/impl/AgentStateMonitor.java b/dongtai-agent/src/main/java/io/dongtai/iast/agent/monitor/impl/AgentStateMonitor.java index 5dad68047..1c4219301 100644 --- a/dongtai-agent/src/main/java/io/dongtai/iast/agent/monitor/impl/AgentStateMonitor.java +++ b/dongtai-agent/src/main/java/io/dongtai/iast/agent/monitor/impl/AgentStateMonitor.java @@ -67,22 +67,19 @@ public void check() { if (null == agentState.getAllowReport()) { DongTaiLog.info("engine is not allowed to report data"); agentState.setAllowReport(allowReport); - return; } if (!allowReport.equals(agentState.getAllowReport())) { DongTaiLog.info("engine is not allowed to report data"); agentState.setAllowReport(allowReport); engineManager.stop(); - return; } } else if (agentState.isAllowReport(allowReport) && !allowReport.equals(agentState.getAllowReport())) { DongTaiLog.info("engine is allowed to report data"); agentState.setAllowReport(allowReport); engineManager.start(); - return; } - if (!agentState.isFallback() && !agentState.isException() && agentState.isAllowReport()) { + if (!agentState.isFallback() && !agentState.isException() && agentState.isAllowReport() && agentState.isAllowReport()) { if (State.RUNNING.equals(expectState) && agentState.isPaused()) { DongTaiLog.info("engine start by server expect state"); engineManager.start(); From a551c69d84ed01d6dde44477117566585b607f42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98niuerzhuang=E2=80=99?= <‘niuerzhuang@huoxian.cn’> Date: Tue, 25 Apr 2023 14:55:49 +0800 Subject: [PATCH 29/42] feature: allow data report --- .../agent/monitor/impl/AgentStateMonitor.java | 31 +++++++------------ .../dongtai/iast/common/state/AgentState.java | 22 +++---------- 2 files changed, 17 insertions(+), 36 deletions(-) diff --git a/dongtai-agent/src/main/java/io/dongtai/iast/agent/monitor/impl/AgentStateMonitor.java b/dongtai-agent/src/main/java/io/dongtai/iast/agent/monitor/impl/AgentStateMonitor.java index 1c4219301..b135cdc11 100644 --- a/dongtai-agent/src/main/java/io/dongtai/iast/agent/monitor/impl/AgentStateMonitor.java +++ b/dongtai-agent/src/main/java/io/dongtai/iast/agent/monitor/impl/AgentStateMonitor.java @@ -50,33 +50,26 @@ public void check() { return; } - Map stringStringMap = checkExpectState(); + Map stringStringMap = checkExpectState(); // 默认值 String expectState = "other"; - String allowReport = "1"; + boolean allowReport = true; if (stringStringMap != null) { - expectState = stringStringMap.get("exceptRunningStatus"); - allowReport = stringStringMap.get("isAllowDateReport"); - if ("null".equals(allowReport)){ - allowReport = "1"; + expectState = stringStringMap.get("exceptRunningStatus").toString(); + if (null != stringStringMap.get("isAllowDateReport")) { + allowReport = (boolean) stringStringMap.get("isAllowDateReport"); } } - if (!agentState.isAllowReport(allowReport)) { - if (null == agentState.getAllowReport()) { - DongTaiLog.info("engine is not allowed to report data"); - agentState.setAllowReport(allowReport); - } - if (!allowReport.equals(agentState.getAllowReport())) { - DongTaiLog.info("engine is not allowed to report data"); - agentState.setAllowReport(allowReport); - engineManager.stop(); - } - } else if (agentState.isAllowReport(allowReport) && !allowReport.equals(agentState.getAllowReport())) { + if (allowReport && !agentState.isAllowReport()) { DongTaiLog.info("engine is allowed to report data"); agentState.setAllowReport(allowReport); engineManager.start(); + } else if (!allowReport && agentState.isAllowReport()) { + DongTaiLog.info("engine is not allowed to report data"); + agentState.setAllowReport(allowReport); + engineManager.stop(); } if (!agentState.isFallback() && !agentState.isException() && agentState.isAllowReport() && agentState.isAllowReport()) { @@ -97,7 +90,7 @@ public void check() { } } - private Map checkExpectState() { + private Map checkExpectState() { try { Map parameters = new HashMap(); parameters.put("agentId", String.valueOf(AgentRegisterReport.getAgentId())); @@ -105,7 +98,7 @@ private Map checkExpectState() { if (!respRaw.isEmpty()) { JSONObject resp = JSON.parseObject(respRaw); JSONObject data = (JSONObject) resp.get("data"); - Map objectObjectHashMap = new HashMap<>(2); + Map objectObjectHashMap = new HashMap<>(2); String s = data.toJSONString(); objectObjectHashMap = JSON.parseObject(s, Map.class); return objectObjectHashMap; diff --git a/dongtai-common/src/main/java/io/dongtai/iast/common/state/AgentState.java b/dongtai-common/src/main/java/io/dongtai/iast/common/state/AgentState.java index 9ac88e875..ac276d8a4 100644 --- a/dongtai-common/src/main/java/io/dongtai/iast/common/state/AgentState.java +++ b/dongtai-common/src/main/java/io/dongtai/iast/common/state/AgentState.java @@ -5,7 +5,7 @@ public class AgentState { private State pendingState; private StateCause cause; private boolean fallback; - private Integer allowReport; + private boolean allowReport = true; private static AgentState INSTANCE; public static AgentState getInstance() { @@ -97,23 +97,11 @@ public boolean isFallback() { return this.fallback; } - public Boolean isAllowReport(String allowReport) { - if (null == allowReport) { - return true; - } else { - return Integer.valueOf(allowReport).equals(1); - } - } - - public Boolean isAllowReport() { - return 1 == this.allowReport; - } - - public void setAllowReport(String allowReport) { - this.allowReport = Integer.valueOf(allowReport); + public boolean isAllowReport() { + return this.allowReport; } - public String getAllowReport() { - return String.valueOf(allowReport); + public void setAllowReport(boolean allowReport) { + this.allowReport = allowReport; } } From 9208b5874aaebeedf6f2a0c1cc04f1703e77704d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98niuerzhuang=E2=80=99?= <‘niuerzhuang@huoxian.cn’> Date: Tue, 25 Apr 2023 17:45:39 +0800 Subject: [PATCH 30/42] feature: allow data report --- .../iast/agent/monitor/impl/AgentStateMonitor.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/dongtai-agent/src/main/java/io/dongtai/iast/agent/monitor/impl/AgentStateMonitor.java b/dongtai-agent/src/main/java/io/dongtai/iast/agent/monitor/impl/AgentStateMonitor.java index b135cdc11..d68aabda1 100644 --- a/dongtai-agent/src/main/java/io/dongtai/iast/agent/monitor/impl/AgentStateMonitor.java +++ b/dongtai-agent/src/main/java/io/dongtai/iast/agent/monitor/impl/AgentStateMonitor.java @@ -50,15 +50,15 @@ public void check() { return; } - Map stringStringMap = checkExpectState(); + Map stringStringMap = checkExpectState(); // 默认值 String expectState = "other"; boolean allowReport = true; if (stringStringMap != null) { - expectState = stringStringMap.get("exceptRunningStatus").toString(); + expectState = stringStringMap.get("exceptRunningStatus"); if (null != stringStringMap.get("isAllowDateReport")) { - allowReport = (boolean) stringStringMap.get("isAllowDateReport"); + allowReport = !"0".equals(stringStringMap.get("isAllowDateReport")); } } @@ -90,15 +90,15 @@ public void check() { } } - private Map checkExpectState() { + private Map checkExpectState() { try { - Map parameters = new HashMap(); + Map parameters = new HashMap<>(); parameters.put("agentId", String.valueOf(AgentRegisterReport.getAgentId())); String respRaw = HttpClientUtils.sendGet(ApiPath.EXCEPT_ACTION, parameters).toString(); if (!respRaw.isEmpty()) { JSONObject resp = JSON.parseObject(respRaw); JSONObject data = (JSONObject) resp.get("data"); - Map objectObjectHashMap = new HashMap<>(2); + Map objectObjectHashMap = new HashMap<>(2); String s = data.toJSONString(); objectObjectHashMap = JSON.parseObject(s, Map.class); return objectObjectHashMap; From 8f743b2456112348f56fd8e783319dc82a6f29aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98niuerzhuang=E2=80=99?= <‘niuerzhuang@huoxian.cn’> Date: Tue, 25 Apr 2023 17:47:51 +0800 Subject: [PATCH 31/42] feature: allow data report --- .../io/dongtai/iast/agent/monitor/impl/AgentStateMonitor.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/dongtai-agent/src/main/java/io/dongtai/iast/agent/monitor/impl/AgentStateMonitor.java b/dongtai-agent/src/main/java/io/dongtai/iast/agent/monitor/impl/AgentStateMonitor.java index d68aabda1..db0514677 100644 --- a/dongtai-agent/src/main/java/io/dongtai/iast/agent/monitor/impl/AgentStateMonitor.java +++ b/dongtai-agent/src/main/java/io/dongtai/iast/agent/monitor/impl/AgentStateMonitor.java @@ -65,11 +65,9 @@ public void check() { if (allowReport && !agentState.isAllowReport()) { DongTaiLog.info("engine is allowed to report data"); agentState.setAllowReport(allowReport); - engineManager.start(); } else if (!allowReport && agentState.isAllowReport()) { DongTaiLog.info("engine is not allowed to report data"); agentState.setAllowReport(allowReport); - engineManager.stop(); } if (!agentState.isFallback() && !agentState.isException() && agentState.isAllowReport() && agentState.isAllowReport()) { From c2439958411156487ca6f3288d14f4134464e9b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98niuerzhuang=E2=80=99?= <‘niuerzhuang@huoxian.cn’> Date: Wed, 26 Apr 2023 10:56:19 +0800 Subject: [PATCH 32/42] =?UTF-8?q?fix:=201.=20OpenJ9=20linux=20=E4=B8=8B=20?= =?UTF-8?q?attach=20=E5=91=BD=E4=BB=A4=E6=8A=A5=E9=94=99,=20=E5=AE=9E?= =?UTF-8?q?=E9=99=85=E6=89=A7=E8=A1=8C=E6=88=90=E5=8A=9F=202.=20Windows=20?= =?UTF-8?q?=E4=B8=8B=E4=BD=BF=E7=94=A8=20administrator=20=E8=B4=A6?= =?UTF-8?q?=E5=8F=B7(=E6=9D=83=E9=99=90)=20attach=20=E5=A4=B1=E8=B4=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/bin/jattach-arm | Bin 74368 -> 29144 bytes .../src/main/resources/bin/jattach-linux | Bin 26996 -> 24850 bytes .../src/main/resources/bin/jattach-mac | Bin 153296 -> 153296 bytes .../src/main/resources/bin/jattach.exe | Bin 130048 -> 130048 bytes 4 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 dongtai-agent/src/main/resources/bin/jattach-mac diff --git a/dongtai-agent/src/main/resources/bin/jattach-arm b/dongtai-agent/src/main/resources/bin/jattach-arm index 3d957495b9ab13d731eb3a9acf55748832bab858..aef7d876f7827a68b3425841eb9f367eb0e874a8 100755 GIT binary patch literal 29144 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 literal 74368 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 diff --git a/dongtai-agent/src/main/resources/bin/jattach-mac b/dongtai-agent/src/main/resources/bin/jattach-mac old mode 100644 new mode 100755 index 932216cdaae35661e2d9d505757848dc44664d4a..5e4dae179121b84bbe95139d483e4a1d8c9bfe32 GIT binary patch delta 11254 zcmeHsd0dR^`|$nDOevZ6J!w()Wh!kH6HO+HHe{_tDoY|xPMA@~F=q_riLpglj%3T0 zvZR!yY!MY5Ejov%g^-g*nBR5JGaa1sem~#O`_KFS^Yi(f?)$p#Yv1l??o)A6v*M&? zZUt9Qw=Y5jLde++{=h%obB)|>EZxa3yf0VAjybpKV4~WR8M>XMkT-}3kP$w_)N@@t zQ)7}d$6`PV@OX(!sW@20CEntNx5d1>eCev&eCae;{U3Xa+o?7(evZ-PAW(y${iX=< zrOp#o;5HicP=P`Ky~H;q>+ZUDC$K3I$Q2doh$LW_WZi8q_sw_L+(7;T3#_iip@>>Xj+i@8eH*}34mo@7K(hk8#d=%)eZ`&P zZa>L-4L`AhY9RN{9cUD5+an?n=={W=K*VFRdaj4Dp7I3o#k>l>)Cl{-m$FOA!Snj+ z87RHDP*JZ?@Wu6%t|>WvUVnyWUovT)rJ%?JD8==KxnM0N2eVVU6bUZkThtTSi;7ky z@ugRloYD&wwF(8b59l3gQ@RMV+K-i584Vcs9!T9w5(4BM2l}Uz4q@hY+W^a#s6Dd6yrLpt1n3G4RL69G;?!r_t{y@Mo!2a)z5J{ofQP2v?YBiu^xyP-goUmj9V;$y`_o;4b0mI7wE^2DWUY*kpZF`~0bG1>2}DWo_*!pJNA&|t>i|f( z14!aaG(f`%sG36HL6>lUQQ06v-%HtRILZqE1oCcjNTi*B4W!f=z~Gaiu+nt6f^dIG z5PuA>BB8j|4xejbPO0Zrs1s@(EoJ9-RC}qrdP;&MOfUxsTF(Hv4OTG)pyrthg(7tt zU;Jk!Hy^$D{q9bHm@08)4is7gN8m1yvTwnHoAu*2_5R|wU_l=C5vBnFC3h(g0t~qEfP=c-e4!T}qvBhI zaE7QFT^hR!u-EzlMwtSKN7UFgKo3JioKaM*P$YzViEl{M_Ci;PMHF^SqP9udo1z99 zT24bXG&GCsztGOZT`4?aL36DJNXPnmqD5cgJD&mxt8XJpDkJNKtL zO6x>xfePljLnk$mwpSDj7(UE0tWLTEM*z?LFDiOJvSDFg9Ujp5iLYjZ{SFFhBdHZ- zD=2|pa_EF`Tvw7N4uLwQ#asevJh1M;0c4E>3tu8qDiDiqgAB;Rc4a5Be}=)ua{$B- zp@)%Did7X+H!&{`zdD3pNQXa2sZXG@`GXpczqj~gE)er{F5U#W5g^wO%=oBEq@VaB zUn0dyLE0KDEwVyf?Wj8G6xHQ1zG=GQW{R$P@XB zOZnhsJ0QV@Ru9S^b`n!>@keSL>?mXSBR2Joyyd011r?qKY4sKl+u#SSb(xG_G;xHj za^A3AK&P*`2&!;1Ai&HtVEkvzS!$Ed7g-2S!0m}k&kcHuC;qG12UaX_E#SQ+%0PfK zUbNs_ctrddS&(k2lAeW&b{X(N0YhM+x?$i`wJHTc(66_YIm4eDQMW{oAtZ?WDcat0 zKaeQyq;wO4W+=9D+&N-VCPWyZ^JGD^y)l-mEHbG6U;EG&mov!^(YD5>a0DS-zm89o z@Kd^NSJ!~OJ4sGVUx6+@g4qa)F2OVasdZGUk~?7`h`xapDF)1 zU$yW&gMcVtIe0hc@4+h1D`;>i~+X6%D}Pp@a6F1P*9Fr zPvwLR2L@c9>9FFmS`St!)9wM*d{>^s@4$#@28pVRm&}c|m_8GT@rQ#Gtjbzs(kjKu z&+Q*N0&1}yJKR%?900znMMPx)0+-?`MA|GKJt_=9FU13|6a^umS{Fe~N}xAVx*0ub z-Etgk!Qo0^`Ad9s!CyPFW2wzdN4SmgOm3(AU`O@GSGFmH#}S4NbrBybZ)LCpG{AQ% zKCh>&VYv(*foUDf`hX|}fF-TbSjc!Rq;&$Yrqiqo zv>~poqw$%Ruf#_Krf@z~76?5?+QeD#Lus;*e+zvHx9LsMgO4!SRO+aAfbtdJ^i|w+ zsErz-W3>^i#IpxJsz_m+2O%P_#@!*R&xx0Z5=1=tB7O_;$GNx_m(-0Ntmm(aS(0EK zx6FFdswLKr&eo0`N5^yH)+|&fbjc$ESAC%gVjxpQa7^JBj~OC#&Cb0MFujMTx)EV$ z2@_R}Mu-s|m#}hqTmsra#4TUAEY=-K2sjyom?(21{zLXF9j}$@R>Tkz6Xq4_{xKYhZH0XG{5W2sf-B$##A#fog01anSgL{p&bi+ht3l+GiT54|i0(g)-(H{I zb$afK+n+^tzC)IU25~flP49{q%Kh!mwXLc;SOW^mLyVkJKV~3#)WB9+l>; zx?;LK<47v;K8KXOE^Dck)ZfuG>qvGM4vk=3-=9-EPc*v8Y}X(O_e$mPUOuY=?HklC zp8RX&)Kt>v)NJW6$JCnBiPI(#I^?bULhHZAB|bUow|HV7ANkXxzb>ixBw0M}=vcc| zxeEejkC`VNO)h$HnlL+OQgK3CZ5}7ta29#HuH4g+AjfxfrH0PbI`)yv17{H>>jet}65o{R<~_X|svqf-FCHOx*kUYyxo%&m zbKapX{9@9d%Y%ffrRj3S4QdH>vH4AV2Rv?S^I%$={O z6f2f6FGTRFgT4B;b-PpEuv1%eqX%Y6#Af+|1n1&EB-X?9J`~peJSA_5Mfljf>QjZ= zO=1o-JZmmJmNIftA35^X4>&a2^J#_9vT#kcP3QEn2G6J858?V*th`h*ox3fy<8p>w zK6^n;jPBKYzf`-eIkY-^ZNQi7{-@jD73Q2>Ki=Db#eXd*F3L*QeaK1Hy{E3#lL1|Z zwnMV+6+q_yot9pV%w*kTfI7k;m=0PTO?9=Q+DwMI8sa2<$4Rg&Dm^piUPtVVtC`7cuwISHNoKZY!Wo01;jfcl zG1AoL9%{Z!P`BTqd(>@H`9(u)AyJ)bhGWX zL&2lW%lDr=Wyvx8MMtOexap%)!5@|x7iP^a@XTk+%I1n<%$bwTR>Mp8Ucu-fuJSMCeN^uZfGNZS~BpxwRo~=#<2c zl;WrMr>i^3vJ^o;i*S*?c{J=j2J-PbFc^l#BZVmpG?F;|VvNKYzIyVjU5+e6@JDTUny^u`@5j z?1vddj1AUwnPuE|DsoEExqy~OIR*V^e%QY3d9M%bFAebpCR+rIT@L45{``$Ftmzn2 z%#Kd@l0W?I+_Td4A}y=KV)E@vJHeH>KzZ^rH__Aw9RnrkX|eU51H5M|TXkPdz5n~! z#if^=y~$oNWeF*HpC1%j=(utNcN=8zVtqojpZq2c&tK^3l0Qv6)-)#2&MK}`*yI=2 z*C^@gtie%wO(D>-L?Bw11~pxF1hbE zc{XGE&HGy+TzvUdZ7_K(q`lw3TZ64u9xLt(z<5nY?#vH;E@xpoJk0SY>+U>O?Gb%G1MsA zj0i;pSN?&CGE_l-^ZX|=M2^9U=!{07>*20&qwG9?M@U4%hPU~k1j4)Ev^ zG8gvn4djgJ8bQPjfT=qW1%%>Fi379NU|J?x+yJzg<_W;q1lu~=;vV^D0I%GG{17!X zRH*=2qYxfG0Iwq;j7r7eCU%vJh=0X(Tnq2Sjclt#)# zVT2R0Use!CSP*MvPr?W*_WZ|mAPBZFXqk)%CoCd*1CP=_4chCWK6yFN!t9v2maPZ3JE**)!z%OK=Q6>-pSMU^PLgOzK z%7iN8meDk>a7M6%LAJ0KfIKeH72Ti%T?H`Kxl2|Y0okaO{S`q(MlDfk<=&tzKM63F z?DPhOMuK)+7`TmIK>U*7tjBT&+8A^kVBGuIs}o-pAzWy=Ou%6+b70L*nbn15`L@am z=M$sdCjm})iM9sk%DRBgE3|Jqw)~YsVPaiKYN>u*`~gg5 zOHoX8>|i17e8VBSrM3er-Z#Ps+5vmq4-F;<%(GMGDa|?d2MQewK^sSCv}Qqm6(#y< zUy{6zeU7`HUBnElV$04%64nA;Q4lts^8$q;#<(hl7WbioY5TB~$;|o8WaNB=v4GE` z8+)uW>$-i34kD$6)YPb=qlkzi&jt&z zCn_%Tur3jLYz7`G(z>7#WY`Gx(vktL2DzC~SLOsVS4tyW2kX$%|mfbxA9h-j^ai(FPdoqLP@mnBd ztmTrla_omeP9G48*AzJW1es)W^wQ4CJfjE`+d@DYflpj@bpG;b z+Q)+9w9VB}6#JgZR!0#|0T8WDrg;vQj4gP(&un=s8?X|DWct2=@hEIwM*a0uVeGcXg?y0hF1FjriHw>|r zSiSAB?;WE{SOz>j0kSa^2JryKRdjtd%xc&p+b-8ZC=)8ru3(%NT5}C1++qTmhu{=m zR7ZL}X~YKL(Ul-Oxri{CRCE;z%|z(gG=VObM#X`k>nJ&h1x2!b_p5mf6VCcv5f z=*)F8`$CJF=fI?VMEfDrjwXx+0YIai!0IT(1er(_zoK`|Ft@tFula|6tdt0tqBDV> zf=X(34U)Gw1;|@n1LPV+@AAQfR(Z>qAbIP!AbH!E0Qu{20rE*ipYp{7ySyiE!zOUo zyw+l*o%|wLvxQ(!+TzKT9f~IO1QZLM#}&2tGCjJjv*>^l(2CgiHw?Ox9>QvXg!-Sr znU$oaLpi_U|0ful8lbc)b@a{}zEez?+ya?G;o877$swSr;d%!FCOKPS z?S!iUm*92s-zC_F>6E=jq~Q|W18`3XR$^YJMUFM2%au}7T!T84RmBokeP94$**NOA zWW-{^M6d>nfv?kOSc^8&zU9FFG2Dbiipp0whmuP_pau6dm|R34XS^Q{cXkncD%fnN z`?w5fZmV_e`h3Q;9Bp78w(gfIu0zhW!p;1IS zog|Dqj|o9oR=O$%fIAI1Ya_tz_{NKkE&`m_&TmSN0504Z4B7dO7Y2Vi8i_{X&*J$q z0Zp6-)?sBD_)ukWIP3!fk3G^{Ln}%E7zycpD4gRN0q>=TTp?{RzT>%@=zRd3*T86^ zthjPzdE33yob_JhZUF3aW%SfemW_85km|R^irN1Rfh22 zl@aotOk5cZfO{%q3_ep`C6ux->^&uE ze&0OQN0t-^Uv)mR({b>P?Q`)?9I=AdkOdkJZIVrlCsu1F>!s1N_TtTWBEHvuex)r} zlbHwz5u?pQwqHQF=$RTLlxd7urN)Sv4iC5cF8(PXKBSCjbEO|^^Z(;x?Ops>yUPdv znMhidTFC~m7`9q%u6G&f#NFOPqD>aeV(joT?N9#(jfCHy_|3NGH)+qC?cIO8+3r%& z_q^GMK1ju>(O^%$*va;_3tdV{hnE{hq@M+ zUq7<9cIyShMQ=~&=^jbFbvftYL(dU=C-mB3sdvBi@uuTq&n(s+Tk>q(%TLC?mvmQByzy4vYR@iL8XbUMY2yjsUtS$V-i4^{p3-=1xq{{3uAEIt3E=AO_s z|IJZ-g;Q_!yQOa)&v1A%XYUK&q`iNhv`{|V{#PP+wzcq@;mC1V5Ibd&_rg)G@sYtJ zfA*g|e&x?R*MvaQpmDUozBc#DPnn!YrvsCIN$s=`4s3s}Haq-K5o1Ee!Q7djxYhm% zvsXm$QXk(P6X16G@ar9pMfW6nV|H%ou>E~%=`i{D_deNNGFGeIF8%Z$*9N#2C<>%@ zoka^W`)x`a(3ISF&z!)?XE(l{_&DqS!AkutZ5P+i(VuZ|cV2yWLTh_Ti{MRtp8ux{ z4;|Wh8@PMhmz#{5F?HDM>eH3G+4*rTCWabM+RP@D#dM!o=G}&VO?$I@=i!B8p1*Ip zx+djTslCK=QEl3;<5dcIy?Mc}T))+FzwjG1N4J*WtxvFT>r;1h$8uKlOP|R@GHTfN zJ4yTXt&3)bNSi}XSe~}qzIt8f@7{t_`Ty_VZHI3ev6RJ2diU7SbGB3QhQrPm%f2|u z4w(*GKdt|l>g0)HhQ`?EBQ2LDWpDV$yDgN8>fQE`L!Xh)bk$n^_uck?-);XtzS}}U z{`1|o%Wl#x=6f@}f=A6Rg|$4xaI)F{|K{Dcd3EsI!?`9+$+8FMV>+uoc$`0IH|;1Y zeY-%g%tdcrQuD^Q6&rrKxux#t)x;~JxRF%Go|fB!c30Oe3ftf~;H3M8?lTT!`~MF`tI6sB delta 11181 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 NgVH@df3Q0CzW~0VO1S_4 delta 30278 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 Date: Wed, 26 Apr 2023 12:14:25 +0800 Subject: [PATCH 33/42] fix: Exception: java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String. --- .../iast/agent/monitor/impl/AgentStateMonitor.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dongtai-agent/src/main/java/io/dongtai/iast/agent/monitor/impl/AgentStateMonitor.java b/dongtai-agent/src/main/java/io/dongtai/iast/agent/monitor/impl/AgentStateMonitor.java index db0514677..d68382a66 100644 --- a/dongtai-agent/src/main/java/io/dongtai/iast/agent/monitor/impl/AgentStateMonitor.java +++ b/dongtai-agent/src/main/java/io/dongtai/iast/agent/monitor/impl/AgentStateMonitor.java @@ -50,15 +50,15 @@ public void check() { return; } - Map stringStringMap = checkExpectState(); + Map stringStringMap = checkExpectState(); // 默认值 String expectState = "other"; boolean allowReport = true; if (stringStringMap != null) { - expectState = stringStringMap.get("exceptRunningStatus"); + expectState = stringStringMap.get("exceptRunningStatus").toString(); if (null != stringStringMap.get("isAllowDateReport")) { - allowReport = !"0".equals(stringStringMap.get("isAllowDateReport")); + allowReport = !"0".equals(stringStringMap.get("isAllowDateReport").toString()); } } @@ -88,7 +88,7 @@ public void check() { } } - private Map checkExpectState() { + private Map checkExpectState() { try { Map parameters = new HashMap<>(); parameters.put("agentId", String.valueOf(AgentRegisterReport.getAgentId())); @@ -96,7 +96,7 @@ private Map checkExpectState() { if (!respRaw.isEmpty()) { JSONObject resp = JSON.parseObject(respRaw); JSONObject data = (JSONObject) resp.get("data"); - Map objectObjectHashMap = new HashMap<>(2); + Map objectObjectHashMap = new HashMap<>(2); String s = data.toJSONString(); objectObjectHashMap = JSON.parseObject(s, Map.class); return objectObjectHashMap; From 37425fc30446d36f0c066376de92f43bb83a335f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98niuerzhuang=E2=80=99?= <‘niuerzhuang@huoxian.cn’> Date: Thu, 27 Apr 2023 14:40:47 +0800 Subject: [PATCH 34/42] fix: jsr/ret exception. --- .../enhance/plugin/core/DispatchClassPlugin.java | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/core/DispatchClassPlugin.java b/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/core/DispatchClassPlugin.java index e31b811f9..f378892fe 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/core/DispatchClassPlugin.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/core/DispatchClassPlugin.java @@ -36,17 +36,12 @@ public ClassVisitor dispatch(ClassVisitor classVisitor, ClassContext classContex } classContext.setMatchedClassName(matchedClassName); - ClassVisit cv = new ClassVisit(classVisitor, classContext, policy); - if (cv.isNeedTransform()) { - return cv; - } - return classVisitor; + return new ClassVisit(classVisitor, classContext, policy); } public class ClassVisit extends AbstractClassVisitor { private int classVersion; private final MethodAdapter[] methodAdapters; - private boolean needTransform; ClassVisit(ClassVisitor classVisitor, ClassContext classContext, Policy policy) { super(classVisitor, classContext, policy); @@ -57,10 +52,6 @@ public class ClassVisit extends AbstractClassVisitor { }; } - public boolean isNeedTransform() { - return this.needTransform; - } - @Override public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { @@ -97,7 +88,6 @@ public MethodVisitor visitMethod(final int access, final String name, final Stri } if (methodIsTransformed) { - this.needTransform = true; DongTaiLog.trace("rewrite method {} for listener[class={}]", matchedSignature, context.getClassName()); } From 6143994eb3604c87f6f887b5c6b08d344572d52f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98niuerzhuang=E2=80=99?= <‘niuerzhuang@huoxian.cn’> Date: Fri, 28 Apr 2023 14:13:31 +0800 Subject: [PATCH 35/42] fix: jsr/ret exception. --- .../bytecode/enhance/plugin/core/DispatchClassPlugin.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/core/DispatchClassPlugin.java b/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/core/DispatchClassPlugin.java index f378892fe..9ac713c46 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/core/DispatchClassPlugin.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/core/DispatchClassPlugin.java @@ -64,12 +64,18 @@ public MethodVisitor visitMethod(final int access, final String name, final Stri final String signature, final String[] exceptions) { MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); if (Modifier.isInterface(access) || Modifier.isAbstract(access) || "".equals(name)) { + if (this.classVersion <= Opcodes.V1_6) { + mv = new JSRInlinerAdapter(mv, access, name, descriptor, signature, exceptions); + } return mv; } if (this.policy.isBlacklistHooks(this.context.getClassName()) && !this.policy.isIgnoreBlacklistHooks(this.context.getClassName()) && !this.policy.isIgnoreInternalHooks(this.context.getClassName())) { + if (this.classVersion <= Opcodes.V1_6) { + mv = new JSRInlinerAdapter(mv, access, name, descriptor, signature, exceptions); + } return mv; } From da9c0f3b3234af3871e2e40628f91a95e13d6254 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98niuerzhuang=E2=80=99?= <‘niuerzhuang@huoxian.cn’> Date: Thu, 4 May 2023 13:51:21 +0800 Subject: [PATCH 36/42] fix: Change dongtai.server.package default value to true. --- .../src/main/java/io/dongtai/iast/agent/IastProperties.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dongtai-agent/src/main/java/io/dongtai/iast/agent/IastProperties.java b/dongtai-agent/src/main/java/io/dongtai/iast/agent/IastProperties.java index 6e3a223fb..43ceab17b 100644 --- a/dongtai-agent/src/main/java/io/dongtai/iast/agent/IastProperties.java +++ b/dongtai-agent/src/main/java/io/dongtai/iast/agent/IastProperties.java @@ -223,7 +223,7 @@ public String getServerToken() { public String getIsDownloadPackage() { if (null == isDownloadPackage) { isDownloadPackage = System.getProperty(PropertyConstant.PROPERTY_SERVER_PACKAGE, - cfg.getProperty(PropertyConstant.PROPERTY_SERVER_PACKAGE, "true")); + cfg.getProperty(PropertyConstant.PROPERTY_SERVER_PACKAGE, "false")); } return isDownloadPackage; } From d57492ab38a0d4a88933afac8ec45909312e3222 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98niuerzhuang=E2=80=99?= <‘niuerzhuang@huoxian.cn’> Date: Thu, 4 May 2023 18:39:21 +0800 Subject: [PATCH 37/42] fix: allow data report api fixed. --- .../io/dongtai/iast/agent/monitor/impl/AgentStateMonitor.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dongtai-agent/src/main/java/io/dongtai/iast/agent/monitor/impl/AgentStateMonitor.java b/dongtai-agent/src/main/java/io/dongtai/iast/agent/monitor/impl/AgentStateMonitor.java index d68382a66..6ef9e5197 100644 --- a/dongtai-agent/src/main/java/io/dongtai/iast/agent/monitor/impl/AgentStateMonitor.java +++ b/dongtai-agent/src/main/java/io/dongtai/iast/agent/monitor/impl/AgentStateMonitor.java @@ -57,8 +57,8 @@ public void check() { if (stringStringMap != null) { expectState = stringStringMap.get("exceptRunningStatus").toString(); - if (null != stringStringMap.get("isAllowDateReport")) { - allowReport = !"0".equals(stringStringMap.get("isAllowDateReport").toString()); + if (null != stringStringMap.get("allowReport")) { + allowReport = !"0".equals(stringStringMap.get("allowReport").toString()); } } From f1eb0f0e7e48b54f6ee7b11117d2fe5069d47f88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98niuerzhuang=E2=80=99?= <‘niuerzhuang@huoxian.cn’> Date: Fri, 5 May 2023 19:15:12 +0800 Subject: [PATCH 38/42] fix: kafka exception. --- .../enhance/plugin/PluginRegister.java | 21 +++++++++++++------ .../KafkaAbstractConfigInitAdviceAdapter.java | 14 +++++++++++++ 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/PluginRegister.java b/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/PluginRegister.java index 63d60da6b..40abdb27f 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/PluginRegister.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/PluginRegister.java @@ -29,14 +29,23 @@ public class PluginRegister { public PluginRegister() { this.plugins = new ArrayList(); - this.plugins.add(new DispatchSpringApplication()); + if(!"false".equals(System.getProperty("dongtai.plugin.api"))){ + this.plugins.add(new DispatchSpringApplication()); + } this.plugins.add(new DispatchJ2ee()); - this.plugins.add(new DispatchKafka()); + if(!"false".equals(System.getProperty("dongtai.plugin.kafka"))) { + this.plugins.add(new DispatchKafka()); + } this.plugins.add(new DispatchJdbc()); - this.plugins.add(new DispatchShiro()); - this.plugins.add(new DispatchFeign()); - this.plugins.add(new DispatchDubbo()); - + if(!"false".equals(System.getProperty("dongtai.plugin.shiro"))) { + this.plugins.add(new DispatchShiro()); + } + if(!"false".equals(System.getProperty("dongtai.plugin.feign"))) { + this.plugins.add(new DispatchFeign()); + } + if(!"false".equals(System.getProperty("dongtai.plugin.dubbo"))) { + this.plugins.add(new DispatchDubbo()); + } this.plugins.add(new DispatchClassPlugin()); } diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/service/kafka/KafkaAbstractConfigInitAdviceAdapter.java b/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/service/kafka/KafkaAbstractConfigInitAdviceAdapter.java index b1e82020f..4dd0f9649 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/service/kafka/KafkaAbstractConfigInitAdviceAdapter.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/service/kafka/KafkaAbstractConfigInitAdviceAdapter.java @@ -4,6 +4,7 @@ import io.dongtai.iast.core.bytecode.enhance.asm.AsmTypes; import io.dongtai.iast.core.handler.hookpoint.service.ServiceType; import io.dongtai.iast.core.utils.AsmUtils; +import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Type; import org.objectweb.asm.commons.AdviceAdapter; @@ -20,6 +21,12 @@ protected KafkaAbstractConfigInitAdviceAdapter(MethodVisitor mv, int access, Str @Override protected void onMethodExit(int opcode) { if (opcode != ATHROW) { + Label tryL = new Label(); + Label catchL = new Label(); + Label exHandlerL = new Label(); + visitTryCatchBlock(tryL, catchL, exHandlerL, ASM_TYPE_THROWABLE.getInternalName()); + visitLabel(tryL); + localServers = newLocal(Type.getType(List.class)); loadThis(); push("bootstrap.servers"); @@ -39,6 +46,13 @@ protected void onMethodExit(int opcode) { push(""); push("KafkaUrlHandler"); invokeInterface(ASM_TYPE_SPY_DISPATCHER, SPY$reportService); + + visitLabel(catchL); + Label endL = new Label(); + visitJumpInsn(GOTO, endL); + visitLabel(exHandlerL); + visitVarInsn(ASTORE, this.nextLocal); + visitLabel(endL); } } } From 5274ec0643408ff053585c4dce557f2c996e5c36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98niuerzhuang=E2=80=99?= <‘niuerzhuang@huoxian.cn’> Date: Sat, 6 May 2023 12:14:38 +0800 Subject: [PATCH 39/42] fix: add option disabled_plugins. --- dongtai-agent/module-info.java | 0 .../java/io/dongtai/iast/agent/Agent.java | 1 + .../io/dongtai/iast/agent/AgentLauncher.java | 1 - .../io/dongtai/iast/agent/IastProperties.java | 1 + .../common/constants/PropertyConstant.java | 1 + .../enhance/plugin/DispatchPlugin.java | 2 + .../enhance/plugin/PluginRegister.java | 44 +++++++++---------- .../authentication/shiro/DispatchShiro.java | 5 +++ .../plugin/core/DispatchClassPlugin.java | 5 +++ .../plugin/framework/dubbo/DispatchDubbo.java | 5 +++ .../plugin/framework/feign/DispatchFeign.java | 5 +++ .../framework/j2ee/dispatch/DispatchJ2ee.java | 5 +++ .../hardcoded/DispatchHardcodedPlugin.java | 5 +++ .../plugin/service/jdbc/DispatchJdbc.java | 5 +++ .../plugin/service/kafka/DispatchKafka.java | 5 +++ ...ication.java => DispatchApiCollector.java} | 7 ++- 16 files changed, 73 insertions(+), 24 deletions(-) delete mode 100644 dongtai-agent/module-info.java rename dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/spring/{DispatchSpringApplication.java => DispatchApiCollector.java} (84%) diff --git a/dongtai-agent/module-info.java b/dongtai-agent/module-info.java deleted file mode 100644 index e69de29bb..000000000 diff --git a/dongtai-agent/src/main/java/io/dongtai/iast/agent/Agent.java b/dongtai-agent/src/main/java/io/dongtai/iast/agent/Agent.java index 27d886bff..d38df004a 100644 --- a/dongtai-agent/src/main/java/io/dongtai/iast/agent/Agent.java +++ b/dongtai-agent/src/main/java/io/dongtai/iast/agent/Agent.java @@ -38,6 +38,7 @@ private static String[] parseAgentArgs(String[] args) throws ParseException { attachOptions.addOption(build("log_level", "log_level", "optional: DongTai agent log print level.")); attachOptions.addOption(build("log_path", "log_path", "optional: DongTai agent log print path.")); attachOptions.addOption(build("log_disable_collector", "log_disable_collector", "optional: DongTai agent disable log collector.")); + attachOptions.addOption(build("disabled_plugins", "disabled_plugins", "optional: DongTai agent disable plugins.")); CommandLineParser parser = new DefaultParser(); HelpFormatter formatter = new HelpFormatter(); diff --git a/dongtai-agent/src/main/java/io/dongtai/iast/agent/AgentLauncher.java b/dongtai-agent/src/main/java/io/dongtai/iast/agent/AgentLauncher.java index 7752663cb..15560cda4 100755 --- a/dongtai-agent/src/main/java/io/dongtai/iast/agent/AgentLauncher.java +++ b/dongtai-agent/src/main/java/io/dongtai/iast/agent/AgentLauncher.java @@ -2,7 +2,6 @@ import io.dongtai.iast.agent.manager.EngineManager; import io.dongtai.iast.agent.monitor.MonitorDaemonThread; -import io.dongtai.iast.agent.monitor.impl.AgentStateMonitor; import io.dongtai.iast.agent.report.AgentRegisterReport; import io.dongtai.iast.common.constants.AgentConstant; import io.dongtai.iast.common.scope.ScopeManager; diff --git a/dongtai-agent/src/main/java/io/dongtai/iast/agent/IastProperties.java b/dongtai-agent/src/main/java/io/dongtai/iast/agent/IastProperties.java index 43ceab17b..82e20d931 100644 --- a/dongtai-agent/src/main/java/io/dongtai/iast/agent/IastProperties.java +++ b/dongtai-agent/src/main/java/io/dongtai/iast/agent/IastProperties.java @@ -33,6 +33,7 @@ public class IastProperties { put("log_path", PropertyConstant.PROPERTY_LOG_PATH); put("log_disable_collector", PropertyConstant.PROPERTY_LOG_DISABLE_COLLECTOR); put("uuid_path", PropertyConstant.PROPERTY_UUID_PATH); + put("disabled_plugins", PropertyConstant.PROPERTY_DISABLED_PLUGINS); }}; private static IastProperties instance; diff --git a/dongtai-common/src/main/java/io/dongtai/iast/common/constants/PropertyConstant.java b/dongtai-common/src/main/java/io/dongtai/iast/common/constants/PropertyConstant.java index 89e36a22c..e6b936ff5 100644 --- a/dongtai-common/src/main/java/io/dongtai/iast/common/constants/PropertyConstant.java +++ b/dongtai-common/src/main/java/io/dongtai/iast/common/constants/PropertyConstant.java @@ -32,4 +32,5 @@ public class PropertyConstant { public static final String PROPERTY_RESPONSE_LENGTH = "dongtai.response.length"; public static final String PROPERTY_POLICY_PATH = "dongtai.policy.path"; public static final String PROPERTY_UUID_PATH = "dongtai.uuid.path"; + public static final String PROPERTY_DISABLED_PLUGINS = "dongtai.disabled.plugins"; } diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/DispatchPlugin.java b/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/DispatchPlugin.java index d5277f890..964d29100 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/DispatchPlugin.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/DispatchPlugin.java @@ -16,4 +16,6 @@ public interface DispatchPlugin { * @return ClassVisitor 命中的类访问起 */ ClassVisitor dispatch(ClassVisitor classVisitor, ClassContext context, Policy policy); + + String getName(); } diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/PluginRegister.java b/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/PluginRegister.java index 40abdb27f..9fae3be3f 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/PluginRegister.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/PluginRegister.java @@ -9,13 +9,12 @@ import io.dongtai.iast.core.bytecode.enhance.plugin.hardcoded.DispatchHardcodedPlugin; import io.dongtai.iast.core.bytecode.enhance.plugin.service.jdbc.DispatchJdbc; import io.dongtai.iast.core.bytecode.enhance.plugin.service.kafka.DispatchKafka; -import io.dongtai.iast.core.bytecode.enhance.plugin.spring.DispatchSpringApplication; +import io.dongtai.iast.core.bytecode.enhance.plugin.spring.DispatchApiCollector; import io.dongtai.iast.core.handler.hookpoint.models.policy.Policy; import io.dongtai.iast.core.handler.hookpoint.models.policy.PolicyManager; import org.objectweb.asm.ClassVisitor; -import java.util.ArrayList; -import java.util.List; +import java.util.*; /** * @author dongzhiyong@huoxian.cn @@ -28,25 +27,26 @@ public class PluginRegister { private final List plugins; public PluginRegister() { - this.plugins = new ArrayList(); - if(!"false".equals(System.getProperty("dongtai.plugin.api"))){ - this.plugins.add(new DispatchSpringApplication()); - } - this.plugins.add(new DispatchJ2ee()); - if(!"false".equals(System.getProperty("dongtai.plugin.kafka"))) { - this.plugins.add(new DispatchKafka()); - } - this.plugins.add(new DispatchJdbc()); - if(!"false".equals(System.getProperty("dongtai.plugin.shiro"))) { - this.plugins.add(new DispatchShiro()); - } - if(!"false".equals(System.getProperty("dongtai.plugin.feign"))) { - this.plugins.add(new DispatchFeign()); - } - if(!"false".equals(System.getProperty("dongtai.plugin.dubbo"))) { - this.plugins.add(new DispatchDubbo()); - } - this.plugins.add(new DispatchClassPlugin()); + this.plugins = new ArrayList<>(); + List disabledPlugins = getdisabledPlugins(); + List allPlugins = new ArrayList<>(Arrays.asList( + new DispatchApiCollector(), + new DispatchJ2ee(), + new DispatchKafka(), + new DispatchJdbc(), + new DispatchShiro(), + new DispatchFeign(), + new DispatchDubbo(), + new DispatchClassPlugin() + )); + allPlugins.removeIf(plugin -> disabledPlugins != null && disabledPlugins.contains(plugin.getName())); + this.plugins.addAll(allPlugins); + } + + private List getdisabledPlugins() { + return Optional.ofNullable(System.getProperty("dongtai.disabled.plugins")) + .map(s -> Arrays.asList(s.split(","))) + .orElse(null); } public ClassVisitor initial(ClassVisitor classVisitor, ClassContext context, PolicyManager policyManager) { diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/authentication/shiro/DispatchShiro.java b/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/authentication/shiro/DispatchShiro.java index a5ca1319c..5ae07dafb 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/authentication/shiro/DispatchShiro.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/authentication/shiro/DispatchShiro.java @@ -17,4 +17,9 @@ public ClassVisitor dispatch(ClassVisitor classVisitor, ClassContext context, Po } return classVisitor; } + + @Override + public String getName() { + return "shiro"; + } } diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/core/DispatchClassPlugin.java b/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/core/DispatchClassPlugin.java index 9ac713c46..8a9e40837 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/core/DispatchClassPlugin.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/core/DispatchClassPlugin.java @@ -39,6 +39,11 @@ public ClassVisitor dispatch(ClassVisitor classVisitor, ClassContext classContex return new ClassVisit(classVisitor, classContext, policy); } + @Override + public String getName() { + return "class"; + } + public class ClassVisit extends AbstractClassVisitor { private int classVersion; private final MethodAdapter[] methodAdapters; diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/framework/dubbo/DispatchDubbo.java b/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/framework/dubbo/DispatchDubbo.java index 5edba1d9f..4bddf9c4c 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/framework/dubbo/DispatchDubbo.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/framework/dubbo/DispatchDubbo.java @@ -36,4 +36,9 @@ public ClassVisitor dispatch(ClassVisitor classVisitor, ClassContext context, Po return classVisitor; } + + @Override + public String getName() { + return "dubbo"; + } } diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/framework/feign/DispatchFeign.java b/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/framework/feign/DispatchFeign.java index 35cae7a26..b5f6c8f3d 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/framework/feign/DispatchFeign.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/framework/feign/DispatchFeign.java @@ -18,4 +18,9 @@ public ClassVisitor dispatch(ClassVisitor classVisitor, ClassContext context, Po return classVisitor; } + + @Override + public String getName() { + return "feign"; + } } diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/framework/j2ee/dispatch/DispatchJ2ee.java b/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/framework/j2ee/dispatch/DispatchJ2ee.java index ef80e87c7..f96e914c9 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/framework/j2ee/dispatch/DispatchJ2ee.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/framework/j2ee/dispatch/DispatchJ2ee.java @@ -48,6 +48,11 @@ public ClassVisitor dispatch(ClassVisitor classVisitor, ClassContext context, Po return classVisitor; } + @Override + public String getName() { + return "j2ee"; + } + private boolean isJavaxServlet(String className, Set diagram) { return JAVAX_FACES_SERVLET.equals(className) || JAVAX_HTTP_SERVLET.equals(className) || diagram.contains(JAVAX_HTTP_SERVLET) || diagram.contains(JAVAX_FILTER); diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/hardcoded/DispatchHardcodedPlugin.java b/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/hardcoded/DispatchHardcodedPlugin.java index f6fee0034..e1ae81af9 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/hardcoded/DispatchHardcodedPlugin.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/hardcoded/DispatchHardcodedPlugin.java @@ -33,6 +33,11 @@ public ClassVisitor dispatch(ClassVisitor classVisitor, ClassContext context, Po return classVisitor; } + @Override + public String getName() { + return "hardcode"; + } + private class ExtractClassContent extends AbstractClassVisitor { private String source; diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/service/jdbc/DispatchJdbc.java b/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/service/jdbc/DispatchJdbc.java index a9f474143..c729dda7c 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/service/jdbc/DispatchJdbc.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/service/jdbc/DispatchJdbc.java @@ -27,4 +27,9 @@ public ClassVisitor dispatch(ClassVisitor classVisitor, ClassContext context, Po return classVisitor; } + + @Override + public String getName() { + return "jdbc"; + } } diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/service/kafka/DispatchKafka.java b/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/service/kafka/DispatchKafka.java index 9219f0353..dca0958a6 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/service/kafka/DispatchKafka.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/service/kafka/DispatchKafka.java @@ -18,4 +18,9 @@ public ClassVisitor dispatch(ClassVisitor classVisitor, ClassContext context, Po return classVisitor; } + + @Override + public String getName() { + return "kafka"; + } } diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/spring/DispatchSpringApplication.java b/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/spring/DispatchApiCollector.java similarity index 84% rename from dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/spring/DispatchSpringApplication.java rename to dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/spring/DispatchApiCollector.java index c0d8ce97d..f9ccc1677 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/spring/DispatchSpringApplication.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/spring/DispatchApiCollector.java @@ -5,7 +5,7 @@ import io.dongtai.iast.core.handler.hookpoint.models.policy.Policy; import org.objectweb.asm.ClassVisitor; -public class DispatchSpringApplication implements DispatchPlugin { +public class DispatchApiCollector implements DispatchPlugin { private static final String FRAMEWORK_SERVLET = " org.springframework.web.servlet.FrameworkServlet".substring(1); @@ -17,4 +17,9 @@ public ClassVisitor dispatch(ClassVisitor classVisitor, ClassContext context, Po } return classVisitor; } + + @Override + public String getName() { + return "api"; + } } From 387c5eacbc12109b74d1b3caecdb7ecb58f4b1d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98niuerzhuang=E2=80=99?= <‘niuerzhuang@huoxian.cn’> Date: Sat, 6 May 2023 12:28:24 +0800 Subject: [PATCH 40/42] fix: add option disabled_plugins. --- .../iast/core/bytecode/enhance/plugin/PluginRegister.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/PluginRegister.java b/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/PluginRegister.java index 9fae3be3f..775fadc5a 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/PluginRegister.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/PluginRegister.java @@ -36,11 +36,11 @@ public PluginRegister() { new DispatchJdbc(), new DispatchShiro(), new DispatchFeign(), - new DispatchDubbo(), - new DispatchClassPlugin() + new DispatchDubbo() )); allPlugins.removeIf(plugin -> disabledPlugins != null && disabledPlugins.contains(plugin.getName())); this.plugins.addAll(allPlugins); + this.plugins.add(new DispatchClassPlugin()); } private List getdisabledPlugins() { From b338f1fa2a41f28085abf107ec5be5def7852f3f Mon Sep 17 00:00:00 2001 From: lostsnow Date: Wed, 10 May 2023 16:22:32 +0800 Subject: [PATCH 41/42] fixes unvalidated forward detect by remove hook blacklist --- .../io/dongtai/iast/core/utils/matcher/ConfigMatcher.java | 7 ++++++- .../resources/com.secnium.iast.resources/blacklist.txt | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/dongtai-core/src/main/java/io/dongtai/iast/core/utils/matcher/ConfigMatcher.java b/dongtai-core/src/main/java/io/dongtai/iast/core/utils/matcher/ConfigMatcher.java index 9f3542348..e8b801701 100644 --- a/dongtai-core/src/main/java/io/dongtai/iast/core/utils/matcher/ConfigMatcher.java +++ b/dongtai-core/src/main/java/io/dongtai/iast/core/utils/matcher/ConfigMatcher.java @@ -7,7 +7,9 @@ import org.apache.commons.lang3.StringUtils; import java.lang.instrument.Instrumentation; -import java.util.*; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; /** * 各种匹配方法(通过配置文件匹配) @@ -168,6 +170,9 @@ public boolean canHook(String className, PolicyManager policyManager) { String realClassName = className.replace('/', '.'); boolean isBlack = inHookBlacklist(className); if (isBlack) { + if (policyManager.getPolicy() == null) { + return false; + } policyManager.getPolicy().addBlacklistHooks(realClassName); if (!policyManager.getPolicy().isIgnoreBlacklistHooks(realClassName) && !policyManager.getPolicy().isIgnoreInternalHooks(realClassName)) { diff --git a/dongtai-core/src/main/resources/com.secnium.iast.resources/blacklist.txt b/dongtai-core/src/main/resources/com.secnium.iast.resources/blacklist.txt index 0cc7049b6..c975dc315 100644 --- a/dongtai-core/src/main/resources/com.secnium.iast.resources/blacklist.txt +++ b/dongtai-core/src/main/resources/com.secnium.iast.resources/blacklist.txt @@ -29998,7 +29998,7 @@ org/apache/catalina/connector/Request$SpecialAttributeAdapter org/apache/catalina/connector/ResponseFacade org/apache/catalina/connector/SessionTracker org/apache/catalina/core/AccessLogAdapter -org/apache/catalina/core/ApplicationContext +#org/apache/catalina/core/ApplicationContext org/apache/catalina/core/ApplicationContext$DispatchData org/apache/catalina/core/ApplicationContextFacade org/apache/catalina/core/ApplicationDispatcher From 78be5f5de2397158ffd73dd86a006553e72b85f9 Mon Sep 17 00:00:00 2001 From: lostsnow Date: Tue, 16 May 2023 19:17:38 +0800 Subject: [PATCH 42/42] bump version to v1.10.0 --- .../java/io/dongtai/iast/common/constants/AgentConstant.java | 2 +- pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dongtai-common/src/main/java/io/dongtai/iast/common/constants/AgentConstant.java b/dongtai-common/src/main/java/io/dongtai/iast/common/constants/AgentConstant.java index d33cfa2b4..13e333d8a 100644 --- a/dongtai-common/src/main/java/io/dongtai/iast/common/constants/AgentConstant.java +++ b/dongtai-common/src/main/java/io/dongtai/iast/common/constants/AgentConstant.java @@ -1,7 +1,7 @@ package io.dongtai.iast.common.constants; public class AgentConstant { - public static final String VERSION_VALUE = "v1.9.0"; + public static final String VERSION_VALUE = "v1.10.0"; public static final String LANGUAGE = "JAVA"; public static final String THREAD_NAME_PREFIX = "DongTai-IAST-"; public static final String THREAD_NAME_PREFIX_CORE = "DongTai-IAST-Core-"; diff --git a/pom.xml b/pom.xml index 4f4d68691..c53f727b4 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 - 1.9.0 + 1.10.0 UTF-8 io.dongtai.iast.thirdparty