def message(self): # type: () -> str error_details = [] for detail in self.error_details: if isinstance(detail, SMB2SymbolicLinkErrorResponse): flag = str(detail['flags']) print_name = detail.get_print_name() sub_name = detail.get_substitute_name() error_details.append("Flag: %s, Print Name: %s, Substitute Name: %s" % (flag, print_name, sub_name)) elif isinstance(detail, SMB2ShareRedirectErrorContext): ip_addresses = [] for ip_addr in detail['ip_addr_move_list'].get_value(): ip_addresses.append(ip_addr.get_ipaddress()) resource_name = to_text(detail['resource_name'].get_value(), encoding='utf-16-le') error_details.append("IP Addresses: '%s', Resource Name: %s" % ("', '".join(ip_addresses), resource_name)) else: # unknown error details in response, output raw bytes error_details.append("Raw: %s" % to_text(binascii.hexlify(detail))) error_msg = '%s %s: 0x%s' % (self._BASE_MESSAGE, str(self.header['status']), format(self.status, 'x').zfill(8)) if error_details: error_msg += " - %s" % ", ".join(error_details) return to_native("Received unexpected status from the server: %s" % error_msg)
def set_name(self, substitute_name, print_name): b_substitute_name = to_bytes(to_text(substitute_name), encoding='utf-16-le') b_print_name = to_bytes(to_text(print_name), encoding='utf-16-le') self['substitute_name_offset'] = 0 self['substitute_name_length'] = len(b_substitute_name) self['print_name_offset'] = len(b_substitute_name) self['print_name_length'] = len(b_print_name) self['buffer'] = b_substitute_name + b_print_name
def test_native_to_unicode(): if PY3: expected = u"a\x00b\x00c\x00" else: expected = u"abc" actual = to_text("a\x00b\x00c\x00", encoding='utf-16-le') assert actual == expected
def set_name(self, print_name, substitute_name): """ Set's the path_buffer and print/substitute name length of the message with the values passed in. These values should be a string and not a byte string as it is encoded in this function. :param print_name: The print name string to set :param substitute_name: The substitute name string to set """ # Ensure that the to_bytes input is an actual text string for py2 compat with native strings. print_bytes = to_bytes(to_text(print_name), encoding='utf-16-le') sub_bytes = to_bytes(to_text(substitute_name), encoding='utf-16-le') path_buffer = print_bytes + sub_bytes self['print_name_offset'].set_value(0) self['print_name_length'].set_value(len(print_bytes)) self['substitute_name_offset'].set_value(len(print_bytes)) self['substitute_name_length'].set_value(len(sub_bytes)) self['path_buffer'].set_value(path_buffer)
def resolve_path(self, link_path): """ [MS-SMB2] 2.2.2.2.1.1 Handling the Symbolic Link Error Response https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/a8da655c-8b0b-415a-b726-16dc33fa5827 Attempts to resolve the link target path. Will fail if the link is pointing to a local path or a UNC path on another host or share. :param link_path: The original path to the symbolic link to resolve relative paths from. :return: The resolved link target path. """ substitute_name = self.get_substitute_name() print_name = self.get_print_name() unparsed_path_length = self['unparsed_path_length'].get_value() b_link_path = to_bytes(to_text(link_path), encoding='utf-16-le') unparsed_idx = len(b_link_path) - unparsed_path_length base_link_path = to_text(b_link_path[:unparsed_idx], encoding='utf-16-le') unparsed_path = to_text(b_link_path[unparsed_idx:], encoding='utf-16-le') # Use the common code in SymbolicLinkReparseDataBuffer() to resolve the link target. symlink_buffer = SymbolicLinkReparseDataBuffer() symlink_buffer['flags'] = self['flags'].get_value() symlink_buffer.set_name(substitute_name, print_name) target_path = symlink_buffer.resolve_link( base_link_path) + unparsed_path if not target_path.startswith('\\\\'): raise SMBLinkRedirectionError( "Cannot resolve link targets that point to a local path", link_path, print_name) link_share = ntpath.splitdrive(link_path)[0] target_share = ntpath.splitdrive(target_path)[0] if link_share != target_share: raise SMBLinkRedirectionError( "Cannot resolve link targets that point to a different host/share", link_path, print_name) return target_path
def _parse_value(self, value): if value is None: text_value = u"" elif isinstance(value, binary_type): text_value = to_text(value, encoding=self.encoding) elif isinstance(value, text_type): text_value = value elif isinstance(value, types.LambdaType): text_value = value else: raise TypeError("Cannot parse value for field %s of type %s to a " "text string" % (self.name, type(value).__name__)) return text_value
def _bytes_to_hex(bytes, pretty=False, hex_per_line=8): hex = to_text(hexlify(bytes)) if pretty: if hex_per_line == 0: # show hex on 1 line hex_list = [hex] else: idx = hex_per_line * 2 hex_list = list(hex[i:i + idx] for i in range(0, len(hex), idx)) hexes = [] for h in hex_list: hexes.append(' '.join(h[i:i + 2] for i in range(0, len(h), 2)).upper()) hex = "\n".join(hexes) return hex
def dfs_request(tree, path): # type: (TreeConnect, str) -> DFSReferralResponse """ Send a DFS Referral request to the IPC tree and return the referrals. """ dfs_referral = DFSReferralRequest() dfs_referral['request_file_name'] = to_text(path) ioctl_req = SMB2IOCTLRequest() ioctl_req['ctl_code'] = CtlCode.FSCTL_DFS_GET_REFERRALS ioctl_req['file_id'] = b"\xFF" * 16 ioctl_req['max_output_response'] = 56 * 1024 ioctl_req['flags'] = IOCTLFlags.SMB2_0_IOCTL_IS_FSCTL ioctl_req['buffer'] = dfs_referral request = tree.session.connection.send(ioctl_req, sid=tree.session.session_id, tid=tree.tree_connect_id) response = tree.session.connection.receive(request) ioctl_resp = SMB2IOCTLResponse() ioctl_resp.unpack(response['data'].get_value()) dfs_response = DFSReferralResponse() dfs_response.unpack(ioctl_resp['buffer'].get_value()) return dfs_response
def get_substitute_name(self): offset = self['substitute_name_offset'].get_value() length = self['substitute_name_length'].get_value() name_bytes = self['path_buffer'].get_value()[offset:offset + length] return to_text(name_bytes, encoding='utf-16-le')
DFSReferralRequestFlags, DFSReferralResponse, DFSTarget, DomainEntry, ReferralEntry, ) from .conftest import ( DC_REFERRAL, DOMAIN_REFERRAL, TARGET_REFERRAL, ROOT_REFERRAL, ) # 'MUSICAL SYMBOL G CLEF' https://www.fileformat.info/info/unicode/char/1d11e/index.htm UNICODE_TEXT = u'ÜseӜ' + to_text(b"\xF0\x9D\x84\x9E") class TestDomainEntry(object): def test_domain_entry(self): domain_entry = DomainEntry( DOMAIN_REFERRAL['referral_entries'].get_value()[0]) assert domain_entry.domain_list == [] assert domain_entry.domain_name == u'\\DOMAIN' assert not domain_entry.is_expired assert not domain_entry.is_valid domain_entry._start_time = time.time() - 700 assert domain_entry.is_expired def test_process_dc_referral(self):
def test_byte_to_text_diff_encoding(): expected = u"abc" actual = to_text(b"\x61\x00\x62\x00\x63\x00", encoding='utf-16-le') assert actual == expected
def test_byte_to_text(): expected = u"abc" actual = to_text(b"\x61\x62\x63") assert actual == expected
def test_text_to_text(): expected = u"abc" actual = to_text(u"abc") assert actual == expected
def _get_name(self, prefix): offset = self['%s_name_offset' % prefix].get_value() length = self['%s_name_length' % prefix].get_value() b_name = self['buffer'].get_value()[offset:offset + length] return to_text(b_name, encoding='utf-16-le')