Skip to content

Commit

Permalink
Add XSS support for JSP
Browse files Browse the repository at this point in the history
  • Loading branch information
jandro996 committed May 8, 2024
1 parent 6666f39 commit ae313e3
Show file tree
Hide file tree
Showing 21 changed files with 532 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ dependencies {
implementation files(relocatedJavaxJar.outputs.files)
compileOnly group: 'jakarta.servlet', name: 'jakarta.servlet-api', version: '5.0.0'
testImplementation group: 'jakarta.servlet', name: 'jakarta.servlet-api', version: '5.0.0'
testImplementation group: 'jakarta.servlet.jsp', name: 'jakarta.servlet.jsp-api', version: '3.0.0'
testRuntimeOnly project(':dd-java-agent:instrumentation:iast-instrumenter')

javaxClassesToRelocate project(':dd-java-agent:instrumentation:servlet-common'), {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package datadog.trace.instrumentation.servlet5.jsp;

import datadog.trace.agent.tooling.csi.CallSite;
import datadog.trace.api.iast.IastCallSites;
import datadog.trace.api.iast.InstrumentationBridge;
import datadog.trace.api.iast.Sink;
import datadog.trace.api.iast.VulnerabilityTypes;
import datadog.trace.api.iast.sink.XssModule;
import javax.annotation.Nonnull;

@Sink(VulnerabilityTypes.XSS)
@CallSite(spi = IastCallSites.class)
public class JakartaJspWriterCallSite {

@CallSite.Before("void jakarta.servlet.jsp.JspWriter.print(java.lang.String)")
@CallSite.Before("void jakarta.servlet.jsp.JspWriter.println(java.lang.String)")
@CallSite.Before("void jakarta.servlet.jsp.JspWriter.write(java.lang.String)")
@CallSite.Before("void jakarta.servlet.jsp.JspWriter.write(java.lang.String, int, int)")
public static void beforeStringParam(@CallSite.Argument(0) @Nonnull final String s) {
final XssModule module = InstrumentationBridge.XSS;
if (module != null) {
try {
module.onXss(s);
} catch (final Throwable e) {
module.onUnexpectedException("beforeStringParam threw", e);
}
}
}

@CallSite.Before("void jakarta.servlet.jsp.JspWriter.print(char[])")
@CallSite.Before("void jakarta.servlet.jsp.JspWriter.println(char[])")
@CallSite.Before("void jakarta.servlet.jsp.JspWriter.write(char[])")
@CallSite.Before("void jakarta.servlet.jsp.JspWriter.write(char[], int, int)")
public static void beforeCharArrayParam(@CallSite.Argument(0) @Nonnull final char[] buf) {
final XssModule module = InstrumentationBridge.XSS;
if (module != null) {
try {
module.onXss(buf);
} catch (final Throwable e) {
module.onUnexpectedException("beforeCharArrayParam threw", e);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import datadog.trace.agent.test.AgentTestRunner
import datadog.trace.api.iast.InstrumentationBridge
import datadog.trace.api.iast.sink.XssModule
import foo.bar.smoketest.TestJspWriterSuite

import jakarta.servlet.jsp.JspWriter

class JakartaJspWriterCallsiteTest extends AgentTestRunner{

static final STRING = "test"
static final CHAR_ARRAY = STRING.toCharArray()

@Override
protected void configurePreAgent() {
injectSysConfig("dd.iast.enabled", "true")
}

void 'test JspWriter'() {
setup:
final iastModule = Mock(XssModule)
InstrumentationBridge.registerIastModule(iastModule)
final writer = Mock(JspWriter)
final suite = new TestJspWriterSuite(writer)

when:
suite.&"$method".call(args)

then:
1 * iastModule.onXss(args[0])
0 * iastModule._

where:
method | args
"printTest" | [STRING]
"printlnTest" | [STRING]
"write" | [STRING]
"write" | [STRING, 0, 0]
"printTest" | [CHAR_ARRAY]
"printlnTest" | [CHAR_ARRAY]
"write" | [CHAR_ARRAY]
"write" | [CHAR_ARRAY, 0, 0]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package foo.bar.smoketest;

import jakarta.servlet.jsp.JspWriter;
import java.io.IOException;

public class TestJspWriterSuite {

JspWriter writer;

public TestJspWriterSuite(final JspWriter writer) {
this.writer = writer;
}

public void printlnTest(char x[]) throws IOException {
writer.println(x);
}

public void printlnTest(String x) throws IOException {
writer.println(x);
}

public void printTest(char s[]) throws IOException {
writer.print(s);
}

public void printTest(String s) throws IOException {
writer.print(s);
}

public void write(char s[]) throws IOException {
writer.write(s);
}

public void write(String s) throws IOException {
writer.write(s);
}

public void write(String s, int i, int j) throws IOException {
writer.write(s, i, j);
}

public void write(char s[], int i, int j) throws IOException {
writer.write(s, i, j);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package datadog.trace.instrumentation.servlet.jsp;

import datadog.trace.agent.tooling.csi.CallSite;
import datadog.trace.api.iast.IastCallSites;
import datadog.trace.api.iast.InstrumentationBridge;
import datadog.trace.api.iast.Sink;
import datadog.trace.api.iast.VulnerabilityTypes;
import datadog.trace.api.iast.sink.XssModule;
import javax.annotation.Nonnull;

@Sink(VulnerabilityTypes.XSS)
@CallSite(spi = IastCallSites.class)
public class JspWriterCallSite {

@CallSite.Before("void javax.servlet.jsp.JspWriter.print(java.lang.String)")
@CallSite.Before("void javax.servlet.jsp.JspWriter.println(java.lang.String)")
@CallSite.Before("void javax.servlet.jsp.JspWriter.write(java.lang.String)")
@CallSite.Before("void javax.servlet.jsp.JspWriter.write(java.lang.String, int, int)")
public static void beforeStringParam(@CallSite.Argument(0) @Nonnull final String s) {
final XssModule module = InstrumentationBridge.XSS;
if (module != null) {
try {
module.onXss(s);
} catch (final Throwable e) {
module.onUnexpectedException("beforeStringParam threw", e);
}
}
}

@CallSite.Before("void javax.servlet.jsp.JspWriter.print(char[])")
@CallSite.Before("void javax.servlet.jsp.JspWriter.println(char[])")
@CallSite.Before("void javax.servlet.jsp.JspWriter.write(char[])")
@CallSite.Before("void javax.servlet.jsp.JspWriter.write(char[], int, int)")
public static void beforeCharArrayParam(@CallSite.Argument(0) @Nonnull final char[] buf) {
final XssModule module = InstrumentationBridge.XSS;
if (module != null) {
try {
module.onXss(buf);
} catch (final Throwable e) {
module.onUnexpectedException("beforeCharArrayParam threw", e);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import datadog.trace.agent.test.AgentTestRunner
import datadog.trace.api.iast.InstrumentationBridge
import datadog.trace.api.iast.sink.XssModule
import foo.bar.TestJspWriterSuite

import javax.servlet.jsp.JspWriter

class JspWriterInstrumentationTest extends AgentTestRunner{

static final STRING = "test"
static final CHAR_ARRAY = STRING.toCharArray()

@Override
protected void configurePreAgent() {
injectSysConfig("dd.iast.enabled", "true")
}

void 'test JspWriter'() {
setup:
final iastModule = Mock(XssModule)
InstrumentationBridge.registerIastModule(iastModule)
final writer = Mock(JspWriter)
final suite = new TestJspWriterSuite(writer)

when:
suite.&"$method".call(args)

then:
1 * iastModule.onXss(args[0])
0 * iastModule._

where:
method | args
"printTest" | [STRING]
"printlnTest" | [STRING]
"write" | [STRING]
"write" | [STRING, 0, 0]
"printTest" | [CHAR_ARRAY]
"printlnTest" | [CHAR_ARRAY]
"write" | [CHAR_ARRAY]
"write" | [CHAR_ARRAY, 0, 0]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package foo.bar;

import java.io.IOException;
import javax.servlet.jsp.JspWriter;

public class TestJspWriterSuite {

JspWriter writer;

public TestJspWriterSuite(final JspWriter writer) {
this.writer = writer;
}

public void printlnTest(char x[]) throws IOException {
writer.println(x);
}

public void printlnTest(String x) throws IOException {
writer.println(x);
}

public void printTest(char s[]) throws IOException {
writer.print(s);
}

public void printTest(String s) throws IOException {
writer.print(s);
}

public void write(char s[]) throws IOException {
writer.write(s);
}

public void write(String s) throws IOException {
writer.write(s);
}

public void write(String s, int i, int j) throws IOException {
writer.write(s, i, j);
}

public void write(char s[], int i, int j) throws IOException {
writer.write(s, i, j);
}
}
41 changes: 41 additions & 0 deletions dd-smoke-tests/springboot-jetty-jsp/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
plugins {
id 'java'
id 'war'
id 'org.springframework.boot' version '2.7.15'
id 'io.spring.dependency-management' version '1.0.15.RELEASE'
id 'java-test-fixtures'
}

apply from: "$rootDir/gradle/java.gradle"
description = 'SpringBoot Jetty JSP Smoke Tests.'

java {
sourceCompatibility = '1.8'
}

repositories {
mavenCentral()
}

sourceSets {
main {
resources.srcDir("src/main/webapp")
}
}

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'

runtimeOnly("javax.servlet:jstl")
runtimeOnly("org.apache.tomcat.embed:tomcat-embed-jasper")

providedRuntime("org.springframework.boot:spring-boot-starter-jetty")

testImplementation project(':dd-smoke-tests')
testImplementation(testFixtures(project(":dd-smoke-tests:iast-util")))
}

tasks.withType(Test).configureEach {
dependsOn "war", "bootWar"
jvmArgs "-Ddatadog.smoketest.springboot.war.path=${tasks.bootWar.archiveFile.get().getAsFile()}"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package datadog.smoketest.springboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringbootApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootApplication.class, args);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package datadog.smoketest.springboot;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class ViewController {

@GetMapping("/test_xss_in_jsp")
public String test() {
return "test_xss";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
logging.level.root=WARN
spring.application.name=sp
spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<%@ page contentType="text/html;charset=UTF-8" %>
<html>
<head>
<title>Test XSS</title>
</head>
<body>
<% String test = request.getParameter("test");%>
<h1>Test Page</h1>
<p>Test parameter: <%=test%></p>
</body>
</html>
Loading

0 comments on commit ae313e3

Please sign in to comment.