Jenkins是一个开源软件项目,是基于java开发的一种持续集成工具,用于监控持续重复的工作。而在此过程中,Agent执行机就是其中关键的一部分,负责执行构建和部署任务。简单来说Agent 就是一个独立的进程或者节点,可以是独立的服务器、虚拟机或者是本地机器,用来执行构建和部署任务,当Jenkins主服务器连接到Agent的时候,就可以在该节点上运行相应的任务
而Jenkins Remoting远程代码执行漏洞(CVE-2024-43044)的产生原因就是获取到Agent节点机器的权限后,可以通过节点连接到Jenkins Remoting主服务器,获取服务器上的文件内容。
Jenkins weekly <= 2.470
Jenkins LTS <= 2.452.3
可以使用vulhub/CVE-2024-23897的环境
version: '2.2'
services:
jenkins:
image: vulhub/jenkins:2.441
ports:
- "50000:50000"
- "8080:8080"
- "5005:5005"
init: true
environment:
- DEBUG=1
启动之后访问http://127.0.0.1:8080 正常说明搭建成功,使用admin/vulhub可以登录到后台
导航Dashboard -> Manage Jenkins ->Nodes 处新建一个Agent节点
选项可以保持默认的,点击save,新建完成之后就可以看到新建成功的节点
导航Dashboard -> Manage Jenkins -> Plugins 安装插件 Websocket Notifier
安装完成之后在节点机器node1连接到Jenkins 主服务器
连接成功后在Jenkins主服务器上可以看到已连接的标识,成功连接之后就可以在Agent节点上部署任务了
当获取到node1机器的权限后,可以得到连接到Jenkins主服务器的secret和name,这时需要将连接使用的agent.jar替换成恶意的Agent连接Jar包,https://github.com/v9d0g/CVE-2024-43044-POC
使用恶意的Jar包重新连接到Jenkins主服务器,就可以读取文件
java -jar agent1.jar -url http://192.168.85.129:8080/ -secret xxxxxx -name xxxx
Agent节点连接到Jenkins主服务器使用的是JNLP协议,JNLP(Java Network Launch Protocol)是一个用于从网络启动 Java 应用程序的协议,通常用于在 Jenkins 等 CI/CD 工具中启动构建代理(也称为 "节点")
在agent.jar中可以看到修改的地方在hudson/remoting/RemoteClassLoader.class,利用JD反编译JAR包得到源代码文件后,在IDEA中下断点调试
// 使用下面的命令启动agent.jar
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005 -jar agent1.jar -url http://192.168.85.147:8080/ -secret xxxxx -name node1 -workDir ""
先启动agent.jar再开启调试,当输入文件path后程序会在断点处停下
在RemoteClassLoader()方法里,首先会初始化一个channel对象,该对象用于在主服务器和代理节点之间进行通信,它负责管理数据的传输和命令的发送
接着会执行到断点处this.proxy.fetchJar(),this.proxy是一个代理对象,fetchJar是proxy对象下的一个方法,当Jenkins主服务器在Agent节点上部署任务时,节点需要从主服务上下载一些必要的JAR包和文件,fetch()会处理与主服务器间的通信,并获取资源内容
程序会进入到hudson.remoting.RemoteInvocationHandler#invoke()下,会执行到req.call()
接着会进入到hudson.remoting.Request#call(),想Jenkins主服务器发送请求
this.response就是返回的资源内容,this.response.returnValue解码之后就是文件的内容
在修改版本中添加了一个判断函数,限制jarUrl只能为插件Jar包
https://github.com/jenkinsci/jenkins/commit/3f54c41b40db9e4ae7afa4209bc1ea91bb9175c0
在修复版本的jenkins.security.s2m#validate()中下断点,当使用原来的利用方式再次请求时,程序会自动调用到validate()
最终会进入到isPluginJar()中,在该方法里会判断jarUrl是否为合法的插件,不是的话会返回false抛出异常