From b0e6c61e35c3f2c78b9c84607bfdcfa0339bd702 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Gonz=C3=A1lez=20Garc=C3=ADa?= Date: Mon, 30 Sep 2024 11:10:36 +0200 Subject: [PATCH] Send IAST vulnerability secure marks to backend (#7645) What Does This Do Added the ability for ranges to return the types of vulnerabilities they are marked for. A closed list of vulnerability types with assigned marks has been created. The encoding and redaction of vulnerability evidence were updated to include a new secure_marks field in the IAST JSON, which holds an array of vulnerability types for which the evidence is marked. Motivation Send vulnerability secure marks to allow backend to recalculate vulnerability score --- .../java/com/datadog/iast/model/Range.java | 16 ++ .../datadog/iast/model/VulnerabilityType.java | 16 ++ .../iast/model/json/AdapterFactory.java | 11 + .../iast/model/json/EvidenceAdapter.java | 34 +++- .../com/datadog/iast/model/RangeTest.groovy | 33 ++- .../iast/model/VulnerabilityTypeTest.groovy | 8 + .../model/json/EvidenceEncodingTest.groovy | 8 +- .../model/json/EvidenceRedactionTest.groovy | 73 ++++++- .../evidence-redaction-suite-with-marks.yml | 192 ++++++++++++++++++ 9 files changed, 383 insertions(+), 8 deletions(-) create mode 100644 dd-java-agent/agent-iast/src/test/resources/redaction/evidence-redaction-suite-with-marks.yml diff --git a/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/model/Range.java b/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/model/Range.java index ce570588da8..25b0dbab667 100644 --- a/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/model/Range.java +++ b/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/model/Range.java @@ -4,10 +4,13 @@ import com.datadog.iast.model.json.SourceIndex; import com.datadog.iast.util.Ranged; +import java.util.HashSet; import java.util.Objects; +import java.util.Set; import java.util.StringJoiner; import javax.annotation.Nonnegative; import javax.annotation.Nonnull; +import javax.annotation.Nullable; public final class Range implements Ranged { @@ -91,4 +94,17 @@ public Range consolidate() { return new Range( start, length, new Source(source.getOrigin(), source.getName(), source.getValue()), marks); } + + public @Nullable Set getMarkedVulnerabilities() { + if (marks == NOT_MARKED) { + return null; + } + Set vulnerabilities = new HashSet<>(); + for (VulnerabilityType type : VulnerabilityType.MARKED_VULNERABILITIES) { + if ((marks & type.mark()) != 0) { + vulnerabilities.add(type); + } + } + return vulnerabilities; + } } diff --git a/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/model/VulnerabilityType.java b/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/model/VulnerabilityType.java index 88c0a117e3c..f9a05fec280 100644 --- a/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/model/VulnerabilityType.java +++ b/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/model/VulnerabilityType.java @@ -109,6 +109,22 @@ public interface VulnerabilityType { .mark(UNTRUSTED_DESERIALIZATION_MARK) .build(); + /* All vulnerability types that have a mark. Should be updated if new vulnerabilityType with mark is added */ + VulnerabilityType[] MARKED_VULNERABILITIES = { + SQL_INJECTION, + COMMAND_INJECTION, + PATH_TRAVERSAL, + LDAP_INJECTION, + SSRF, + UNVALIDATED_REDIRECT, + XPATH_INJECTION, + TRUST_BOUNDARY_VIOLATION, + XSS, + HEADER_INJECTION, + REFLECTION_INJECTION, + UNTRUSTED_DESERIALIZATION + }; + String name(); /** A bit flag to ignore tainted ranges for this vulnerability. Set to 0 if none. */ diff --git a/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/model/json/AdapterFactory.java b/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/model/json/AdapterFactory.java index b62e74388ae..30bfca64bc5 100644 --- a/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/model/json/AdapterFactory.java +++ b/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/model/json/AdapterFactory.java @@ -184,6 +184,7 @@ public static class RedactionContext { private final boolean sensitive; private boolean sensitiveRanges; @Nullable private String redactedValue; + @Nullable private Set markedTypes; public RedactionContext(final Source source) { this.source = source; @@ -192,6 +193,7 @@ public RedactionContext(final Source source) { if (this.sensitive) { this.redactedValue = handler.redactSource(source); } + this.markedTypes = null; } public Source getSource() { @@ -217,5 +219,14 @@ public void markWithSensitiveRanges() { redactedValue = SensitiveHandler.get().redactSource(source); } } + + public void setMarkedTypes(@Nullable Set markedTypes) { + this.markedTypes = markedTypes; + } + + @Nullable + public Set getMarkedTypes() { + return markedTypes; + } } } diff --git a/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/model/json/EvidenceAdapter.java b/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/model/json/EvidenceAdapter.java index 9c78f11ed81..9aa13db2e56 100644 --- a/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/model/json/EvidenceAdapter.java +++ b/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/model/json/EvidenceAdapter.java @@ -28,6 +28,7 @@ import java.util.Map; import java.util.NoSuchElementException; import java.util.Queue; +import java.util.Set; import java.util.stream.Collectors; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -71,6 +72,20 @@ private String substring(final String value, final Ranged range) { return value.substring(range.getStart(), end); } + private static void writeSecureMarks( + final JsonWriter writer, final @Nullable Set markedVulnerabilities) + throws IOException { + if (markedVulnerabilities == null || markedVulnerabilities.isEmpty()) { + return; + } + writer.name("secure_marks"); + writer.beginArray(); + for (VulnerabilityType type : markedVulnerabilities) { + writer.value(type.name()); + } + writer.endArray(); + } + private class DefaultEvidenceAdapter extends FormattingAdapter { @Override @@ -128,6 +143,7 @@ private void writeValuePart( if (range != null) { writer.name("source"); sourceAdapter.toJson(writer, range.getSource()); + writeSecureMarks(writer, range.getMarkedVulnerabilities()); } writer.endObject(); } @@ -389,6 +405,8 @@ static class RedactableTaintedValuePart implements ValuePart { private final List sensitiveRanges; + @Nullable private final Set markedTypes; + private RedactableTaintedValuePart( final JsonAdapter adapter, final Range range, @@ -403,11 +421,14 @@ private RedactableTaintedValuePart( .map(it -> shift(it, -range.getStart())) .sorted(Comparator.comparing(Ranged::getStart)) .collect(Collectors.toList()); + + this.markedTypes = range.getMarkedVulnerabilities(); } @Override public void write(final Context ctx, final JsonWriter writer) throws IOException { final RedactionContext redaction = ctx.getRedaction(source); + redaction.setMarkedTypes(markedTypes); if (redaction.shouldRedact()) { for (final ValuePart part : split(redaction)) { part.write(ctx, writer); @@ -418,6 +439,7 @@ public void write(final Context ctx, final JsonWriter writer) throws IOException writeTruncableValue(writer, value); writer.name("source"); adapter.toJson(writer, source); + writeSecureMarks(writer, markedTypes); writer.endObject(); } } @@ -454,9 +476,10 @@ private void addValuePart( if (start < end) { final Source source = ctx.getSource(); final String chunk = value.substring(start, end); + final Set markedTypes = ctx.getMarkedTypes(); if (!redact) { // append the value - valueParts.add(new TaintedValuePart(adapter, source, chunk, false)); + valueParts.add(new TaintedValuePart(adapter, source, chunk, false, markedTypes)); } else { final int length = chunk.length(); final String sourceValue = source.getValue(); @@ -470,7 +493,7 @@ private void addValuePart( // otherwise redact the string pattern = SensitiveHandler.get().redactString(chunk); } - valueParts.add(new TaintedValuePart(adapter, source, pattern, true)); + valueParts.add(new TaintedValuePart(adapter, source, pattern, true, markedTypes)); } } } @@ -489,15 +512,19 @@ static class TaintedValuePart implements ValuePart { private final boolean redacted; + @Nullable private final Set markedTypes; + private TaintedValuePart( final JsonAdapter adapter, final Source source, final String value, - final boolean redacted) { + final boolean redacted, + final @Nullable Set markedTypes) { this.adapter = adapter; this.source = source; this.value = value; this.redacted = redacted; + this.markedTypes = markedTypes; } @Override @@ -516,6 +543,7 @@ public void write(final Context ctx, final JsonWriter writer) throws IOException writer.name("value"); } writeTruncableValue(writer, value); + writeSecureMarks(writer, markedTypes); writer.endObject(); } } diff --git a/dd-java-agent/agent-iast/src/test/groovy/com/datadog/iast/model/RangeTest.groovy b/dd-java-agent/agent-iast/src/test/groovy/com/datadog/iast/model/RangeTest.groovy index c4992278756..baa55987c0f 100644 --- a/dd-java-agent/agent-iast/src/test/groovy/com/datadog/iast/model/RangeTest.groovy +++ b/dd-java-agent/agent-iast/src/test/groovy/com/datadog/iast/model/RangeTest.groovy @@ -1,15 +1,24 @@ package com.datadog.iast.model +import static com.datadog.iast.model.VulnerabilityType.SQL_INJECTION +import static com.datadog.iast.model.VulnerabilityType.XSS import datadog.trace.api.iast.SourceTypes import datadog.trace.api.iast.VulnerabilityMarks +import static datadog.trace.api.iast.VulnerabilityMarks.NOT_MARKED +import static datadog.trace.api.iast.VulnerabilityMarks.SQL_INJECTION_MARK +import static datadog.trace.api.iast.VulnerabilityMarks.XSS_MARK import datadog.trace.test.util.DDSpecification +import spock.lang.Shared class RangeTest extends DDSpecification { + @Shared + int multipleMarks = SQL_INJECTION_MARK | XSS_MARK + def 'shift'() { given: final source = new Source(SourceTypes.NONE, null, null) - final orig = new Range(start, length, source, VulnerabilityMarks.SQL_INJECTION_MARK) + final orig = new Range(start, length, source, SQL_INJECTION_MARK) when: final result = orig.shift(shift) @@ -19,7 +28,7 @@ class RangeTest extends DDSpecification { result.source == source result.start == startResult result.length == lengthResult - result.marks == VulnerabilityMarks.SQL_INJECTION_MARK + result.marks == SQL_INJECTION_MARK result.isValid() == valid where: @@ -43,4 +52,24 @@ class RangeTest extends DDSpecification { then: result.is(orig) } + + + + void 'test getMarkedVulnerabilities'() { + given: + final source = new Source(SourceTypes.NONE, null, null) + final range = new Range(0, 1, source, marks) + + when: + final vulnerabilities = range.getMarkedVulnerabilities() + + then: + vulnerabilities == expected + + where: + marks | expected + NOT_MARKED | null + SQL_INJECTION_MARK | [SQL_INJECTION] as Set + multipleMarks | [SQL_INJECTION, XSS] as Set + } } diff --git a/dd-java-agent/agent-iast/src/test/groovy/com/datadog/iast/model/VulnerabilityTypeTest.groovy b/dd-java-agent/agent-iast/src/test/groovy/com/datadog/iast/model/VulnerabilityTypeTest.groovy index 553715acb1d..7a0e64fa86c 100644 --- a/dd-java-agent/agent-iast/src/test/groovy/com/datadog/iast/model/VulnerabilityTypeTest.groovy +++ b/dd-java-agent/agent-iast/src/test/groovy/com/datadog/iast/model/VulnerabilityTypeTest.groovy @@ -1,5 +1,6 @@ package com.datadog.iast.model +import datadog.trace.api.iast.VulnerabilityMarks import datadog.trace.bootstrap.instrumentation.api.AgentSpan import datadog.trace.test.util.DDSpecification @@ -52,6 +53,13 @@ class VulnerabilityTypeTest extends DDSpecification { INSECURE_AUTH_PROTOCOL | getSpanAndStackLocation(123) | new Evidence("Authorization : Digest") | 871205334 } + void 'test marked vulnerabilities are not NOT_MARKED'() { + expect: + for (VulnerabilityType type : VulnerabilityType.MARKED_VULNERABILITIES) { + assert type.mark() != VulnerabilityMarks.NOT_MARKED + } + } + private Location getSpanAndStackLocation(final long spanId) { final span = Stub(AgentSpan) span.getSpanId() >> spanId diff --git a/dd-java-agent/agent-iast/src/test/groovy/com/datadog/iast/model/json/EvidenceEncodingTest.groovy b/dd-java-agent/agent-iast/src/test/groovy/com/datadog/iast/model/json/EvidenceEncodingTest.groovy index 9b3d67e9339..713596bd728 100644 --- a/dd-java-agent/agent-iast/src/test/groovy/com/datadog/iast/model/json/EvidenceEncodingTest.groovy +++ b/dd-java-agent/agent-iast/src/test/groovy/com/datadog/iast/model/json/EvidenceEncodingTest.groovy @@ -6,6 +6,7 @@ import com.datadog.iast.model.Source import com.squareup.moshi.JsonAdapter import com.squareup.moshi.Moshi import datadog.trace.api.config.IastConfig +import static datadog.trace.api.iast.VulnerabilityMarks.XSS_MARK import datadog.trace.test.util.DDSpecification import org.skyscreamer.jsonassert.JSONAssert import spock.lang.Shared @@ -64,10 +65,15 @@ class EvidenceEncodingTest extends DDSpecification { 'Hello World' | [range(0, 11, source(0))] | '{"valueParts": [{"value": "Hello World", "source": 0}]}' 'Hello World' | [range(5, 1, source(0))] | '{"valueParts": [{"value": "Hello"}, {"value": " ", "source": 0}, {"value": "World"}]}' 'java.lang.Object@1cb991da' | [range(0, Integer.MAX_VALUE, source(0))] | '{"valueParts": [{"value": "java.lang.Object@1cb991da", "source": 0}]}' + 'Hello World' | [range(6, 5, source(0), XSS_MARK)] | '{"valueParts": [{"value": "Hello "}, {"value": "World", "source": 0, "secure_marks": [XSS]}]}' } private static Range range(final int start, final int length, final Source source) { - return new Range(start, length, source, NOT_MARKED) + return range(start, length, source, NOT_MARKED) + } + + private static Range range(final int start, final int length, final Source source, final int mark) { + return new Range(start, length, source, mark) } private static Source source(final int index) { diff --git a/dd-java-agent/agent-iast/src/test/groovy/com/datadog/iast/model/json/EvidenceRedactionTest.groovy b/dd-java-agent/agent-iast/src/test/groovy/com/datadog/iast/model/json/EvidenceRedactionTest.groovy index 26b5a8408d6..4b05d56c4e0 100644 --- a/dd-java-agent/agent-iast/src/test/groovy/com/datadog/iast/model/json/EvidenceRedactionTest.groovy +++ b/dd-java-agent/agent-iast/src/test/groovy/com/datadog/iast/model/json/EvidenceRedactionTest.groovy @@ -1,5 +1,6 @@ package com.datadog.iast.model.json +import com.datadog.iast.model.Range import com.datadog.iast.model.Source import com.datadog.iast.model.Vulnerability import com.datadog.iast.model.VulnerabilityBatch @@ -7,6 +8,7 @@ import com.datadog.iast.model.VulnerabilityType import com.squareup.moshi.* import datadog.trace.api.config.IastConfig import datadog.trace.api.iast.SourceTypes +import static datadog.trace.api.iast.VulnerabilityMarks.NOT_MARKED import datadog.trace.test.util.DDSpecification import groovy.json.JsonOutput import groovy.json.JsonSlurper @@ -50,6 +52,7 @@ class EvidenceRedactionTest extends DDSpecification { .add(new TestVulnerabilityAdapter()) .add(new TestSourceIndexAdapter()) .add(new TestSourceTypeStringAdapter()) + .add(new TestRangeAdapter()) .build() sourcesParser = moshi.adapter(Types.newParameterizedType(List, Source)) vulnerabilitiesParser = moshi.adapter(Types.newParameterizedType(List, Vulnerability)) @@ -71,8 +74,8 @@ class EvidenceRedactionTest extends DDSpecification { new StringValuePart(null) | _ new StringValuePart('') | _ new RedactedValuePart(null) | _ - new TaintedValuePart(Stub(JsonAdapter), null, null, true) | _ - new TaintedValuePart(Stub(JsonAdapter), null, null, false) | _ + new TaintedValuePart(Stub(JsonAdapter), null, null, true, null) | _ + new TaintedValuePart(Stub(JsonAdapter), null, null, false, null) | _ } void 'test #suite'() { @@ -94,6 +97,25 @@ class EvidenceRedactionTest extends DDSpecification { suite << readTestSuite('redaction/evidence-redaction-suite.yml') } + void 'test secure_marks #suite'() { + given: + Assume.assumeFalse("Ignored test", suite.ignored) + final type = VulnerabilityBatch + final adapter = VulnerabilityEncoding.MOSHI.adapter(type) + + when: + final redacted = adapter.toJson(suite.input) + + then: + final received = JsonOutput.prettyPrint(redacted) + final description = suite.description + final expected = suite.expected + JSONAssert.assertEquals(description, expected, received, JSONCompareMode.NON_EXTENSIBLE) + + where: + suite << readTestSuite('redaction/evidence-redaction-suite-with-marks.yml') + } + private Iterable readTestSuite(final String fileName) { final file = ClassLoader.getSystemResource(fileName) final tests = yaml.parse(file.openStream()) @@ -260,4 +282,51 @@ class EvidenceRedactionTest extends DDSpecification { throw new UnsupportedOperationException() } } + + static class TestRangeAdapter { + @FromJson + Range fromJson(JsonReader reader, final JsonAdapter adapter) throws IOException { + reader.beginObject() + int start = -1 + int length = -1 + Source source = null + int mark = NOT_MARKED + while (reader.hasNext()) { + switch (reader.nextName()) { + case "start": + start = reader.nextInt() + break + case "length": + length = reader.nextInt() + break + case "source": + source = adapter.fromJson(reader) + break + case "secure_marks": + List secureMarks = new Moshi.Builder().build().adapter(Types.newParameterizedType(List, String)).fromJson(reader) as List + mark = calculateMarks(secureMarks) + break + default: + reader.skipValue() + break + } + } + reader.endObject() + final range = new Range(start, length, source, mark) + return range.isValid() ? range : null + } + + static int calculateMarks(List secureMarks) { + int marks = 0 + for (String type : secureMarks) { + marks |= VulnerabilityType."$type".mark + } + return marks + } + + @ToJson + void toJson(@Nonnull final JsonWriter writer, @Nonnull final Range range) throws IOException { + throw new UnsupportedOperationException() + } + } } diff --git a/dd-java-agent/agent-iast/src/test/resources/redaction/evidence-redaction-suite-with-marks.yml b/dd-java-agent/agent-iast/src/test/resources/redaction/evidence-redaction-suite-with-marks.yml new file mode 100644 index 00000000000..8ddf5e7a373 --- /dev/null +++ b/dd-java-agent/agent-iast/src/test/resources/redaction/evidence-redaction-suite-with-marks.yml @@ -0,0 +1,192 @@ +version: 1.1 +suite: + - type: 'VULNERABILITIES' + description: 'Sensitive tainted range (source matches)' + input: > + [ + { + "type": "SQL_INJECTION", + "evidence": { + "value": "select * from users where username = 'john'", + "ranges": [ + { "start" : 26, "length" : 17, "source": { "origin": "http.request.parameter", "name": "clause", "value": "username = 'john'" } , "secure_marks": ["XSS"]} + ] + } + } + ] + expected: > + { + "sources": [ + { "origin": "http.request.parameter", "name": "clause", "redacted": true, "pattern": "abcdefghijklmnopq" } + ], + "vulnerabilities": [ + { + "type": "SQL_INJECTION", + "hash": 0, + "evidence": { + "valueParts": [ + { "value": "select * from users where " }, + { "source": 0, "value": "username = '" , "secure_marks": ["XSS"] }, + { "source": 0, "redacted": true, "pattern": "mnop", "secure_marks": ["XSS"] }, + { "source": 0, "value": "'" , "secure_marks": ["XSS"] } + ] + } + } + ] + } + - type: 'VULNERABILITIES' + description: 'Query without sensitive data' + input: > + [ + { + "type": "SQL_INJECTION", + "evidence": { + "value": "select * from users", + "ranges": [ + { "start" : 14, "length" : 5, "source": { "origin": "http.request.parameter", "name": "table", "value": "users" }, "secure_marks": ["XSS"] } + ] + } + } + ] + expected: > + { + "sources": [ + { "origin": "http.request.parameter", "name": "table", "value": "users" } + ], + "vulnerabilities": [ + { + "type": "SQL_INJECTION", + "hash": 0, + "evidence": { + "valueParts": [ + { "value": "select * from " }, + { "source": 0, "value": "users", "secure_marks": ["XSS"] } + ] + } + } + ] + } + - type: 'VULNERABILITIES' + description: 'Query with sensitive source' + input: > + [ + { + "type": "SQL_INJECTION", + "evidence": { + "value": "select * from users", + "ranges": [ + { "start" : 14, "length" : 5, "source": { "origin": "http.request.parameter", "name": "secret", "value": "users" }, "secure_marks": ["XSS"] } + ] + } + } + ] + expected: > + { + "sources": [ + { "origin": "http.request.parameter", "name": "secret", "redacted": true, "pattern": "abcde" } + ], + "vulnerabilities": [ + { + "type": "SQL_INJECTION", + "hash": 0, + "evidence": { + "valueParts": [ + { "value": "select * from " }, + { "source": 0, "redacted": true, "pattern": "abcde" , "secure_marks": ["XSS"] } + ] + } + } + ] + } + - type: 'VULNERABILITIES' + description: 'Query with multiple ranges and literals' + input: > + [ + { + "type": "SQL_INJECTION", + "evidence": { + "value": "select id as \"super user id\"\n\tfrom users\n\twhere username = 'john:doe' and password LIKE 'super_secure%' and user_id_123 > 00000", + "ranges": [ + { "start" : 60, "length" : 4, "source": { "origin": "http.request.parameter", "name": "first_name", "value": "john" } }, + { "start" : 65, "length" : 3, "source": { "origin": "http.request.parameter", "name": "last_name", "value": "doe" } , "secure_marks": ["XSS"]}, + { "start" : 89, "length" : 12, "source": { "origin": "http.request.parameter", "name": "password", "value": "super_secure" }, "secure_marks": ["XSS", "HEADER_INJECTION"] } + ] + } + } + ] + expected: > + { + "sources": [ + { "origin": "http.request.parameter", "name": "first_name", "redacted": true, "pattern": "abcd" }, + { "origin": "http.request.parameter", "name": "last_name", "redacted": true, "pattern": "abc" }, + { "origin": "http.request.parameter", "name": "password", "redacted": true, "pattern": "abcdefghijkl" } + ], + "vulnerabilities": [ + { + "type": "SQL_INJECTION", + "hash": 0, + "evidence": { + "valueParts": [ + { "value": "select id as \"super user id\"\n\tfrom users\n\twhere username = '" }, + { "source": 0, "redacted": true, "pattern": "abcd" }, + { "redacted": true }, + { "source": 1, "redacted": true, "pattern": "abc" , "secure_marks": ["XSS"] }, + { "value": "' and password LIKE '" }, + { "source": 2, "redacted": true, "pattern": "abcdefghijkl" , "secure_marks": ["XSS", "HEADER_INJECTION"] }, + { "redacted": true }, + { "value": "' and user_id_123 > " }, + { "redacted": true } + ] + } + } + ] + } + - type: 'VULNERABILITIES' + description: 'Ldap complex search' + input: > + [ + { + "type": "LDAP_INJECTION", + "evidence": { + "value": "(cn=Babs Jensen)\n(!(cn=Tim Howes))\n(&(objectClass=Person)(|(sn=Jensen)(cn=Babs J*)))\n(o=univ*of*mich*)\n(seeAlso=)", + "ranges": [ + { "start" : 4, "length" : 11, "source": { "origin": "http.request.parameter", "name": "cn", "value": "Babs Jensen" } , "secure_marks": ["XSS"]}, + { "start" : 63, "length" : 6, "source": { "origin": "http.request.parameter", "name": "cn", "value": "Babs Jensen" } }, + { "start" : 74, "length" : 6, "source": { "origin": "http.request.parameter", "name": "cn", "value": "Babs Jensen" } , "secure_marks": ["HEADER_INJECTION"] } + ] + } + } + ] + expected: > + { + "sources": [ + { "origin": "http.request.parameter", "name": "cn", "redacted": true, "pattern": "abcdefghijk" } + ], + "vulnerabilities": [ + { + "type": "LDAP_INJECTION", + "hash": 0, + "evidence": { + "valueParts": [ + { "value": "(cn=" }, + { "source": 0, "redacted": true, "pattern": "abcdefghijk", "secure_marks": ["XSS"] }, + { "value": ")\n(!(cn=" }, + { "redacted": true }, + { "value": "))\n(&(objectClass=" }, + { "redacted": true }, + { "value": ")(|(sn=" }, + { "source": 0, "redacted": true, "pattern": "fghijk" }, + { "value": ")(cn=" }, + { "source": 0, "redacted": true, "pattern": "abcdef" , "secure_marks": ["HEADER_INJECTION"] }, + { "redacted": true }, + { "value": ")))\n(o=" }, + { "redacted": true }, + { "value": ")\n(seeAlso=)" } + ] + } + } + ] + } + + +