Gradle Wrapper Attack Report

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:

  1. Edit the build.gradle file to modify the software being built by adding additional dependencies
    1. Add two repositories, first in the list: a file-based one and mavenCentral()
    2. Add dependencies to the shadow configuration: the downloaded JAR itself and two third party libraries
    3. Relocate the injected code to be in the org.mariadb.jdbc.internal.cachevalidator package as part of the Shadow plugin configuration
  2. Modify a project specific source file so that the software would execute the malicious code
    1. 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
    • org/gradle/wrapper/Download.class
    • org/gradle/wrapper/PathAssembler.class
  • Second infected wrapper
    • org/gradle/cli/CommandLineParser.class
    • org/gradle/cli/SystemPropertiesCommandLineConverter.class
      • Same as in the first wrapper
    • org/gradle/wrapper/Download.class
    • 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.