Gradle Wrapper Attack Report
Table of Contents
Introduction
On January 11th 2023, we were contacted by MinecraftOnline about two unusual and suspicious Gradle wrapper JARs found in some of their repositories. The wrappers were updated by a new contributor to MinecraftOnline.
We’ve performed an analysis of the JARs and will describe our findings below. We have determined that one exploit was especially crafted as an attack against the MinecraftOnline project.
If you are not interested in all of the details, jump immediately to our companion blog covering how to protect your project or you, as a developer, against similar attacks.
Analysis #
Our analysis started by confirming that the SHA256 checksums for both JARs did not match any of the known good Gradle Wrapper checksums:
- First JAR:
8449b6955690ec956c8ecfe1ae01e10a2aa76ddf18969985c070e345605acce1
- Second JAR:
8e129181710bdc045423ddde59244586d7acbc0b2c5e2ddfc098559da559cf85
After decompiling the two JARs, we discovered two exploits had been patched into the wrapper JAR.
Discord credentials stealing #
The first exploit, present in both JARs, attempts to steal Discord credentials by looking into specific files on the host computer.
The code is very similar to Discord token logging found online.
The exploit hides in different Gradle Wrapper classes and obfuscates String
constants through a character array lookup.
Using a regular expression, lines from certain files are uploaded to a Discord Webhook using a hardcoded token found in the code.
Downloading and running code locally #
The second JAR contains an additional exploit. On certain Gradle invocations, it will attempt to download another malicious JAR and then run it.
For this code path to trigger, the Gradle invocation needed to start with publish
or magic
.
publish
is a Gradle task for pushing all project artifacts to a repository.
Builds that publish artifacts typically have access to higher privileged credentials.
We think that magic
was used as a way to test the exploit.
Running that JAR resulted in the following actions:
- Edit the
build.gradle
file to modify the software being built by adding additional dependencies- Add two repositories, first in the list: a file-based one and
mavenCentral()
- Add dependencies to the
shadow
configuration: the downloaded JAR itself and two third party libraries - Relocate the injected code to be in the
org.mariadb.jdbc.internal.cachevalidator
package as part of the Shadow plugin configuration
- Add two repositories, first in the list: a file-based one and
- Modify a project specific source file so that the software would execute the malicious code
- Add initialization of the code from the injected dependency
In addition to the above, the exploit would modify any Gradle invocation that started with wrapper
to invoke cleanEclipse
instead.
We think this was an attempt to make it harder for the malicious wrapper JAR to be removed.
Modified files in the wrapper JARs #
For completeness, here are the modified files found in the infected wrapper JARs:
- First infected wrapper
org/gradle/cli/SystemPropertiesCommandLineConverter.class
- File on VirusTotal
org/gradle/wrapper/Download.class
- File on VirusTotal
org/gradle/wrapper/PathAssembler.class
- File on VirusTotal
- Second infected wrapper
org/gradle/cli/CommandLineParser.class
- File on VirusTotal
org/gradle/cli/SystemPropertiesCommandLineConverter.class
- Same as in the first wrapper
org/gradle/wrapper/Download.class
- File on VirusTotal
org/gradle/wrapper/PathAssembler.class
- Same as in the first wrapper
Conclusion #
While the Gradle team is aware of the potential attack vector of injecting a malicious wrapper JAR, this is the first report we received of it being actively exploited as a supply chain attack.
In general, we advise caution when integrating any changes from untrusted sources that may affect your build process. Please report any suspicious projects, wrappers, or distributions to us. See the companion blog post about how to protect your project or you, as a developer, against similar attacks.
Let us know if you have any questions on our forums or Gradle Community Slack, or start a discussion below.