Loading

CVE-2017-1000353分析

影响版本

Jenkins主版本<=2.56版本)
Jenkins LTS<=2.46.1版本)

漏洞分析

漏洞发生在jenkins cli采用http方式进行通信的时候,处理url为http://127.0.0.1:8080/cli,其处理逻辑在hudson.cli.CLIAction中
jenkins采用的是Stapler框架,CLIAction实现了两个接口,分别是UnprotectedRootAction, StaplerProxy
image.png

UnprotectedRootAction接口

在Stapler框架中,UnprotectedRootAction是一个标记接口,用于表示一个可以不通过Jenkins安全认证就能访问的动作(或页面)。实现了UnprotectedRootAction接口的类可以被匿名用户访问,即使Jenkins实例配置为安全模式。简单说就是这个action不需要通过Jenkins安全认证就能访问
实现UnprotectedRootAction的类通常需要提供以下方法:

  • getIconFileName():返回用于在Jenkins UI上显示的图标文件名,如果返回null,则不在UI上显示。
  • getDisplayName():返回动作的显示名称,如果返回null,则不在UI上显示。
  • getUrlName():返回动作的URL路径。这是动作可通过HTTP访问的入口点。

重点关注getUrlName(),这段代码表明如果CLI没有被禁用,可以直接通过访问<Jenkins服务器地址>/cli来与Jenkins的CLI功能交互。
image.png

StaplerProxy接口

StaplerProxy是Stapler框架中的一个接口,当一个对象实现了StaplerProxy接口,Stapler会调用该对象的getTarget()方法来获取实际处理请求的对象。
以下是hudson.cli.CLIAction#getTarget,92行判断当请求的路径是/cli,且使用的是POST方法时候,会进入94行的CliEndpointResponse内部类中
image.png

CliEndpointResponse内部类

CliEndpointResponse类继承了HttpResponseException,通过覆写的generateResponse方法来实现了自定义响应逻辑。当 CLI 请求通过 HTTP 到达 Jenkins 时,CliEndpointResponse 类中的 generateResponse 方法将响应这个请求
image.png
CliEndpointResponse 类的 generateResponse 方法实现了几个关键的逻辑点,主要用于处理Jenkins CLI通过HTTP方式的连接请求。这些关键逻辑包括:

  1. 会话标识处理:
  • UUID.fromString(req.getHeader("Session")) 从请求头中获取会话标识(Session ID),将其转换为 UUID 对象。这个UUID值在之后的逻辑中,用于区分不同的会话通道。

image.png

  1. 设置响应头:
  • rsp.setHeader("Hudson-Duplex", "") 设置响应头,告知客户端这是一个双向通信(full-duplex)通道。这个头部信息让客户端知道它可以通过这个通道进行双向通信。

image.png

  1. 通道管理:
  • 根据请求头中的 "Side" 值(download或upload)来区分是 download 还是 upload 操作。根据http头部中session里面的uuid的值来区分不同的会话通道。image.png

以下为download操作逻辑,会创建一个新的 FullDuplexHttpChannel 实例并将其存储在 duplexChannels 映射中,关联之前请求中提取的UUID。
image.png
而对于upload 上传请求,从 duplexChannels 中直接获取对应的通道实例并处理上传数据。
image.png

download操作逻辑

跟进download操作,在hudson.model.FullDuplexHttpChannel#download中,方法的整个逻辑大致如下:

  1. 设置响应状态和chunked 响应头:
  • 将HTTP响应状态设置为 200 OK。
  • 添加 Transfer-Encoding: chunked 响应头,启用HTTP分块传输编码,允许服务器发送一个尚未确定总大小的响应,通过将数据分为一系列的块(chunk)来传输。

image.png

  1. 发送初始数据:
  • 向客户端发送一些初始数据("Starting HTTP duplex channel"),表示HTTP全双工通道的建立过程已经开始

image.png

  1. 等待upload上传通道建立:
  • 进入循环,等待另一个通道(即上传通道)建立。如果在指定的超时时间内上传通道仍未建立,则抛出一个异常。

image.png

  1. 建立双向通道:
  • 一旦上传通道建立,就创建一个 Channel 实例,代表两个Java虚拟机之间的双向通信通道。upload参数就是客户端通过HTTP请求以upload为标记传入的数据流

image.png
首先跟入new Channel到hudson.remoting.Channel#Channel(hudson.remoting.ChannelBuilder, java.io.InputStream, java.io.OutputStream)中,调用构造函数,其中传入了settings.negotiate(is, os),输入流(is)就是客户端通过HTTP请求以upload为标记传入的数据流
image.png
跟入hudson.remoting.ChannelBuilder#negotiate的while逻辑,用于处理双向通信通道(Channel)的初始化过程,以下判断了前导码(preamble),通常以<=[JENKINS REMOTING CAPACITY]=>为开头
image.png
case 1中调用了makeTransport,用于协商传输机制
image.png
以下是makeTransport代码,通过cap确定是否支持分块传输(cap.supportsChunking()),返回ChunkedCommandTransport,或者ClassicCommandTransport对象image.png
回到之前的Channel对象,继续跟入直到hudson.remoting.Channel#Channel(hudson.remoting.ChannelBuilder, hudson.remoting.CommandTransport)
方法参数中transport的值为之前hudson.remoting.ChannelBuilder#makeTransport中返回的ChunkedCommandTransport或者ClassicCommandTransport对象
image.png
第520行的处理接收到的命令逻辑,调用transport.setup,传入了一个CommandReceiver对象
image.png
关于transport.setup,有两种处理方式

ChunkedCommandTransport#setup

首先来看ChunkedCommandTransport#setup的逻辑ChunkedCommandTransport的setup方法使用的是其父类hudson.remoting.SynchronousCommandTransport#setup,其中第39行调用了ReaderThread()
image.png
ReaderThread类为一个内部类,继承自Thread,启动线程后会执行run方法中的逻辑,在其59行又调用了read方法
image.png
ChunkedCommandTransport中的read方法使用的是其父类的hudson.remoting.AbstractSynchronousByteArrayCommandTransport#read
image.png
跟入Command.readFrom,看到了反序列化操作
image.png

ClassicCommandTransport#setup

跟入ClassicCommandTransport#setup中,ClassicCommandTransport#setup方法调用的也是其父类SynchronousCommandTransport的setup
image.png
和之前ChunkedCommandTransport中setup逻辑一样,都用的同一个父类的setup,启动线程后会执行run方法中的逻辑,在其59行又调用了read方法,image.png
这时候就是ClassicCommandTransport中的read方法了,以下为ClassicCommandTransport#read
image.png
跟入Command.readFrom(channel, ois),同样可以看到readObject反序列化操作
image.png

漏洞利用:

两种方式,利用分块传输,或者不分块传输都可以触发反序列化操作
这个漏洞也是基于上次补丁中黑名单的绕过,采用java.security.SignedObject类来二次反序列化,绕过黑名单中的CC链来触发漏洞
POC链接:https://github.com/vulhub/CVE-2017-1000353

posted @ 2024-02-29 15:18  Atomovo  阅读(174)  评论(0编辑  收藏  举报