Skip to content

Commit

Permalink
fix(#2615): reduce ssti vectors for thymeleaf
Browse files Browse the repository at this point in the history
* fix: thymeleaf ssti

* feat(ci): add semgrep scan

* chore: formatting

* chore: remove redundant vulnerable file
  • Loading branch information
SteKoe committed Jul 14, 2023
1 parent 9ae408d commit f1f6ac6
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 4 deletions.
25 changes: 25 additions & 0 deletions .github/workflows/vulnerability-scan.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: Vulnerability Scan

on:
pull_request: {}
workflow_dispatch: {}
push:
branches: ["master"]
schedule:
- cron: '0 7 * * *'

jobs:
semgrep:
name: semgrep/ci
runs-on: ubuntu-latest

container:
image: returntocorp/semgrep

if: (github.actor != 'renovate')

steps:
- uses: actions/checkout@v3
- run: semgrep ci
env:
SEMGREP_RULES: p/default
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@
import org.springframework.web.client.RestTemplate;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.spring6.SpringTemplateEngine;
import org.thymeleaf.spring6.templateresolver.SpringResourceTemplateResolver;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;

import de.codecentric.boot.admin.server.domain.entities.InstanceRepository;
import de.codecentric.boot.admin.server.domain.events.InstanceEvent;
Expand Down Expand Up @@ -179,13 +179,12 @@ public MailNotifier mailNotifier(JavaMailSender mailSender, InstanceRepository r

@Bean
public TemplateEngine mailNotifierTemplateEngine() {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setApplicationContext(this.applicationContext);
ClassLoaderTemplateResolver resolver = new ClassLoaderTemplateResolver();
resolver.setTemplateMode(TemplateMode.HTML);
resolver.setCharacterEncoding(StandardCharsets.UTF_8.name());

SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.addTemplateResolver(resolver);
templateEngine.setTemplateResolver(resolver);
return templateEngine;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* Copyright 2014-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package de.codecentric.boot.admin.server.notify;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;

import org.assertj.core.api.WithAssertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.thymeleaf.context.Context;

import de.codecentric.boot.admin.server.config.EnableAdminServer;

@SpringBootTest(properties = { "spring.mail.host=localhost", "spring.boot.admin.notify.mail=true" })
class MailNotifierIntegrationTest implements WithAssertions {

@Autowired
MailNotifier mailNotifier;

@Test
void fileProtocolIsNotAllowed() {
assertThatThrownBy(() -> {
URL resource = getClass().getClassLoader().getResource(".");
mailNotifier.setTemplate("file://" + resource.getFile()
+ "de/codecentric/boot/admin/server/notify/vulnerable-file.html");
mailNotifier.getBody(new Context());
}).hasCauseInstanceOf(FileNotFoundException.class);
}

@Test
void httpProtocolIsNotAllowed() {
assertThatThrownBy(() -> {
URL resource = getClass().getClassLoader().getResource(".");
mailNotifier.setTemplate(
"https://raw.githubusercontent.com/codecentric/spring-boot-admin/gh-pages/vulnerable-file.html");
mailNotifier.getBody(new Context());
}).hasCauseInstanceOf(FileNotFoundException.class);
}

@Test
void classpathProtocolIsAllowed() throws IOException {
assertThatThrownBy(() -> {
mailNotifier.setTemplate("/de/codecentric/boot/admin/server/notify/vulnerable-file.html");
String body = mailNotifier.getBody(new Context());
}).rootCause().hasMessageContaining("error=2, No such file or directory");
}

@EnableAdminServer
@EnableAutoConfiguration
@SpringBootConfiguration
public static class TestAdminApplication {

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/>
</head>
<body>

<tr
th:with="getRuntimeMethod=${T(org.springframework.util.ReflectionUtils).findMethod(T(org.springframework.util.ClassUtils).forName('java.lang.Runtime',T(org.springframework.util.ClassUtils).getDefaultClassLoader()), 'getRuntime' )}"
>
<td>
<a
th:with="runtimeObj=${T(org.springframework.util.ReflectionUtils).invokeMethod(getRuntimeMethod, null)}"
>
<a
th:with="exeMethod=${T(org.springframework.util.ReflectionUtils).findMethod(T(org.springframework.util.ClassUtils).forName('java.lang.Runtime',T(org.springframework.util.ClassUtils).getDefaultClassLoader()), 'exec', ''.getClass() )}"
>
<a
th:href="${param2}"
th:with="param2=${T(org.springframework.util.ReflectionUtils).invokeMethod(exeMethod, runtimeObj, 'evilSoftwareThatShouldNotRun' )
}"
></a>
</a>

</a>
</td>
</tr>

</body>
</html>

0 comments on commit f1f6ac6

Please sign in to comment.