-
Notifications
You must be signed in to change notification settings - Fork 293
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Email HTML Injection detection in IAST #8205
Open
sezen-datadog
wants to merge
72
commits into
master
Choose a base branch
from
sezen.leblay/APPSEC-56330-email-injection
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+885
−16
Open
Changes from all commits
Commits
Show all changes
72 commits
Select commit
Hold shift + click to select a range
508a671
Email Injection detection in IAST
sezen-datadog a0f62f4
email injection checks
sezen-datadog 59ea624
instrumentation class put in place
sezen-datadog 14df382
EMAIL_HTML_INJECTION
sezen-datadog 700dd63
pr comments easy ones
sezen-datadog b4225d2
only focus on transport send
sezen-datadog 34ac9fb
pr comments
sezen-datadog bcca415
first attempt at instrumentation
sezen-datadog 4b9c23c
correction on argument
sezen-datadog 14458ed
Update dd-java-agent/instrumentation/javax-mail/src/main/java/datadog…
sezen-datadog b548721
Update dd-java-agent/instrumentation/javax-mail/src/main/java/datadog…
sezen-datadog 4182134
advice class added for easier debugging
sezen-datadog 791a5fa
html escapes with vulnerability mark
sezen-datadog cd9f249
instrumentation skeleton
sezen-datadog 74cebb5
instrumentation of body elements
sezen-datadog ea76961
instrumentation of body elements
sezen-datadog e98038d
test start
sezen-datadog 2111e77
test continue
sezen-datadog b814fd0
test continue
sezen-datadog 460737d
test continue
sezen-datadog be50dc3
test OK
sezen-datadog fba4788
define the tests I want
sezen-datadog 5fb78f1
content test OK
sezen-datadog a1ab334
content test OK
sezen-datadog d64327a
content test OK
sezen-datadog 6f8e74f
content test OK
sezen-datadog 49291c1
smoke test controller
sezen-datadog bbf5486
smoke test controller
sezen-datadog ee69fd5
smoke test
sezen-datadog ac708fe
smoke test
sezen-datadog ba2da19
Merge branch 'master' into sezen.leblay/APPSEC-56330-email-injection
sezen-datadog 553c7d8
Update dd-java-agent/instrumentation/javax-mail/src/main/java/datadog…
sezen-datadog e3eaf20
Update dd-java-agent/instrumentation/javax-mail/src/main/java/datadog…
sezen-datadog 95248a2
pr
sezen-datadog 4993aec
pr
sezen-datadog 4883918
pr
sezen-datadog 56b3521
build correction
sezen-datadog cb9a54f
Update dd-java-agent/agent-iast/src/main/java/com/datadog/iast/model/…
sezen-datadog 482a231
build correction
sezen-datadog 69044c0
Merge branch 'master' into sezen.leblay/APPSEC-56330-email-injection
sezen-datadog bccb5ae
build correction
sezen-datadog 990bbb7
Merge branch 'master' into sezen.leblay/APPSEC-56330-email-injection
sezen-datadog 6727eff
pr
sezen-datadog 6337ba5
pr
sezen-datadog b8595c7
pr
sezen-datadog 3384382
build
sezen-datadog c9895be
build
sezen-datadog 3f78b54
build
sezen-datadog 7950096
unit tests pass
sezen-datadog f6da333
de sally no more
sezen-datadog f9b7617
de sally no more
sezen-datadog 2ff2278
smoke tests
sezen-datadog a8b13ca
smoke tests
sezen-datadog c54f206
smoke tests
sezen-datadog 4fdb7f7
Merge branch 'master' into sezen.leblay/APPSEC-56330-email-injection
sezen-datadog 28a67ba
muzzle
sezen-datadog 2e7468c
manu's suggestions
sezen-datadog 59e42e0
beautify
sezen-datadog 845b2d0
EMAIL_HTML_INJECTION instead of EMAIL_INJECTION
sezen-datadog 34796da
EMAIL_HTML_INJECTION instead of EMAIL_INJECTION
sezen-datadog 631b775
pr
sezen-datadog 86321f6
Merge branch 'master' into sezen.leblay/APPSEC-56330-email-injection
sezen-datadog 42b355d
unit test correction - propagation fails though
sezen-datadog aedcb1e
activation dependencies added
sezen-datadog f0aa378
test
sezen-datadog 457e9f6
tests
sezen-datadog aac7112
Merge branch 'master' into sezen.leblay/APPSEC-56330-email-injection
sezen-datadog 8b17208
javax removed from smoke tests (cant have both javax + jakarta)
sezen-datadog 3f9815d
oops
sezen-datadog 73b3cb1
oops
sezen-datadog bc708c5
PR
sezen-datadog 943227d
Merge branch 'master' into sezen.leblay/APPSEC-56330-email-injection
sezen-datadog File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
20 changes: 20 additions & 0 deletions
20
dd-java-agent/agent-iast/src/main/java/com/datadog/iast/sink/EmailInjectionModuleImpl.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package com.datadog.iast.sink; | ||
|
||
import com.datadog.iast.Dependencies; | ||
import com.datadog.iast.model.VulnerabilityType; | ||
import datadog.trace.api.iast.sink.EmailInjectionModule; | ||
import javax.annotation.Nullable; | ||
|
||
public class EmailInjectionModuleImpl extends SinkModuleBase implements EmailInjectionModule { | ||
public EmailInjectionModuleImpl(final Dependencies dependencies) { | ||
super(dependencies); | ||
} | ||
|
||
@Override | ||
public void onSendEmail(@Nullable final Object messageContent) { | ||
if (messageContent == null) { | ||
return; | ||
} | ||
checkInjection(VulnerabilityType.EMAIL_HTML_INJECTION, messageContent); | ||
} | ||
} |
47 changes: 47 additions & 0 deletions
47
...va-agent/agent-iast/src/test/groovy/com/datadog/iast/sink/EmailInjectionModuleTest.groovy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package com.datadog.iast.sink | ||
|
||
import com.datadog.iast.IastModuleImplTestBase | ||
import com.datadog.iast.Reporter | ||
import com.datadog.iast.model.Vulnerability | ||
import com.datadog.iast.model.VulnerabilityType | ||
import com.datadog.iast.propagation.PropagationModuleImpl | ||
import datadog.trace.api.iast.SourceTypes | ||
|
||
class EmailInjectionModuleTest extends IastModuleImplTestBase{ | ||
|
||
private EmailInjectionModuleImpl module | ||
|
||
def setup() { | ||
module = new EmailInjectionModuleImpl(dependencies) | ||
} | ||
|
||
@Override | ||
protected Reporter buildReporter() { | ||
return Mock(Reporter) | ||
} | ||
|
||
def "test onSendEmail with null messageContent"() { | ||
when: | ||
module.onSendEmail(null) | ||
|
||
then: | ||
noExceptionThrown() | ||
} | ||
|
||
def "test onSendEmail with non-null messageContent"() { | ||
given: | ||
def messageContent = "test message" | ||
def propagationModule = new PropagationModuleImpl() | ||
propagationModule.taintObject(messageContent, SourceTypes.NONE) | ||
|
||
when: | ||
module.onSendEmail(messageContent) | ||
|
||
then: | ||
1 * reporter.report(_, _) >> { args -> | ||
def vulnerability = args[1] as Vulnerability | ||
vulnerability.type == VulnerabilityType.EMAIL_HTML_INJECTION && | ||
vulnerability.evidence == messageContent | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
muzzle { | ||
pass { | ||
group = 'jakarta.mail' | ||
module = 'jakarta.mail-api' | ||
versions = '[2.0.1, ]' | ||
} | ||
} | ||
|
||
apply from: "$rootDir/gradle/java.gradle" | ||
|
||
addTestSuiteForDir('latestDepTest', 'test') | ||
|
||
dependencies { | ||
testRuntimeOnly project(':dd-java-agent:instrumentation:iast-instrumenter') | ||
compileOnly 'jakarta.mail:jakarta.mail-api:2.0.1' | ||
testImplementation 'jakarta.mail:jakarta.mail-api:2.0.1' | ||
compileOnly 'com.sun.mail:jakarta.mail:2.0.1' | ||
testImplementation 'com.sun.mail:jakarta.mail:2.0.1' | ||
compileOnly 'jakarta.activation:jakarta.activation-api:2.0.1' | ||
testImplementation 'jakarta.activation:jakarta.activation-api:2.0.1' | ||
} |
69 changes: 69 additions & 0 deletions
69
.../src/main/java/datadog/trace/instrumentation/jakarta/mail/JakartaMailInstrumentation.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
package datadog.trace.instrumentation.jakarta.mail; | ||
|
||
import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.named; | ||
import static net.bytebuddy.matcher.ElementMatchers.takesArgument; | ||
|
||
import com.google.auto.service.AutoService; | ||
import datadog.trace.agent.tooling.Instrumenter; | ||
import datadog.trace.agent.tooling.InstrumenterModule; | ||
import datadog.trace.api.iast.InstrumentationBridge; | ||
import datadog.trace.api.iast.Sink; | ||
import datadog.trace.api.iast.VulnerabilityTypes; | ||
import datadog.trace.api.iast.sink.EmailInjectionModule; | ||
import jakarta.mail.Message; | ||
import jakarta.mail.MessagingException; | ||
import jakarta.mail.Multipart; | ||
import jakarta.mail.Part; | ||
import java.io.IOException; | ||
import net.bytebuddy.asm.Advice; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
@AutoService(InstrumenterModule.class) | ||
public class JakartaMailInstrumentation extends InstrumenterModule.Iast | ||
implements Instrumenter.ForSingleType, Instrumenter.HasMethodAdvice { | ||
|
||
private static Logger LOGGER = LoggerFactory.getLogger(JakartaMailInstrumentation.class); | ||
|
||
public JakartaMailInstrumentation() { | ||
super("jakarta-mail", "jakarta-mail-transport"); | ||
} | ||
|
||
@Override | ||
public void methodAdvice(MethodTransformer transformer) { | ||
transformer.applyAdvice( | ||
named("send0").and(takesArgument(0, named("jakarta.mail.Message"))), | ||
JakartaMailInstrumentation.class.getName() + "$MailInjectionAdvice"); | ||
} | ||
|
||
@Override | ||
public String instrumentedType() { | ||
return "jakarta.mail.Transport"; | ||
} | ||
|
||
public static class MailInjectionAdvice { | ||
@Sink(VulnerabilityTypes.EMAIL_HTML_INJECTION) | ||
@Advice.OnMethodEnter(suppress = Throwable.class) | ||
public static void onSend(@Advice.Argument(0) final Message message) | ||
throws MessagingException, IOException { | ||
EmailInjectionModule emailInjectionModule = InstrumentationBridge.EMAIL_INJECTION; | ||
if (emailInjectionModule == null) { | ||
return; | ||
} | ||
if (message == null || message.getContent() == null) { | ||
return; | ||
} | ||
if (message.isMimeType("text/html")) { | ||
emailInjectionModule.onSendEmail(message.getContent()); | ||
} else if (message.isMimeType("multipart/*")) { | ||
Multipart parts = (Multipart) message.getContent(); | ||
for (int i = 0; i < parts.getCount(); i++) { | ||
final Part part = parts.getBodyPart(i); | ||
if (part != null && part.isMimeType("text/html")) { | ||
emailInjectionModule.onSendEmail(part.getContent()); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
68 changes: 68 additions & 0 deletions
68
.../main/java/datadog/trace/instrumentation/jakarta/mail/JakartaMailPartInstrumentation.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
package datadog.trace.instrumentation.jakarta.mail; | ||
|
||
import static datadog.trace.agent.tooling.bytebuddy.matcher.HierarchyMatchers.implementsInterface; | ||
import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.named; | ||
import static net.bytebuddy.matcher.ElementMatchers.takesArgument; | ||
|
||
import com.google.auto.service.AutoService; | ||
import datadog.trace.agent.tooling.Instrumenter; | ||
import datadog.trace.agent.tooling.InstrumenterModule; | ||
import datadog.trace.api.iast.InstrumentationBridge; | ||
import datadog.trace.api.iast.Propagation; | ||
import datadog.trace.api.iast.propagation.PropagationModule; | ||
import jakarta.mail.Part; | ||
import net.bytebuddy.asm.Advice; | ||
import net.bytebuddy.description.type.TypeDescription; | ||
import net.bytebuddy.matcher.ElementMatcher; | ||
|
||
@AutoService(InstrumenterModule.class) | ||
public class JakartaMailPartInstrumentation extends InstrumenterModule.Iast | ||
implements Instrumenter.ForTypeHierarchy, Instrumenter.HasMethodAdvice { | ||
|
||
public JakartaMailPartInstrumentation() { | ||
super("jakarta-mail", "jakarta-mail-body"); | ||
} | ||
|
||
@Override | ||
public void methodAdvice(MethodTransformer transformer) { | ||
transformer.applyAdvice( | ||
named("setContent").and(takesArgument(0, Object.class)), | ||
JakartaMailPartInstrumentation.class.getName() + "$ContentInjectionAdvice"); | ||
transformer.applyAdvice( | ||
named("setText").and(takesArgument(0, String.class)), | ||
JakartaMailPartInstrumentation.class.getName() + "$TextInjectionAdvice"); | ||
} | ||
|
||
@Override | ||
public String hierarchyMarkerType() { | ||
return "jakarta.mail.Part"; | ||
} | ||
|
||
@Override | ||
public ElementMatcher<TypeDescription> hierarchyMatcher() { | ||
return implementsInterface(named(hierarchyMarkerType())); | ||
} | ||
|
||
public static class ContentInjectionAdvice { | ||
@Propagation | ||
@Advice.OnMethodEnter(suppress = Throwable.class) | ||
private static void onSetContent( | ||
@Advice.This Part part, @Advice.Argument(0) final Object content) { | ||
PropagationModule propagationModule = InstrumentationBridge.PROPAGATION; | ||
if (propagationModule != null && content != null) { | ||
propagationModule.taintObjectIfTainted(part, content); | ||
} | ||
} | ||
} | ||
|
||
public static class TextInjectionAdvice { | ||
@Propagation | ||
@Advice.OnMethodEnter(suppress = Throwable.class) | ||
private static void onSetText(@Advice.This Part part, @Advice.Argument(0) final String text) { | ||
PropagationModule propagationModule = InstrumentationBridge.PROPAGATION; | ||
if (propagationModule != null && text != null) { | ||
propagationModule.taintObjectIfTainted(part, text); | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why we cannot reuse the previous test and just add a new mark?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
because the mark being tested is EMAIL | XSS and I could not figure out how to escape the pipe character for the test lol
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can do a workaround with this:
As we want to do a bitwise operation we can pass an array and do the bitwise operation inside the test. In my opinion in this way the tests are easier to follow than having them splitted. Nonetheless, if you disagree, you can leave it as it is as it is not a real issue :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
might as well do separate tests for separate marks, i think