예제 #1
0
 def test_dialect_3_1_1(self, smb_real):
     connection = Connection(uuid.uuid4(), smb_real[2], smb_real[3])
     connection.connect(Dialects.SMB_3_1_1)
     session = Session(connection, smb_real[0], smb_real[1])
     try:
         session.connect()
         assert len(session.application_key) == 16
         assert session.application_key != session.session_key
         assert len(session.decryption_key) == 16
         assert session.decryption_key != session.session_key
         assert session.encrypt_data
         assert len(session.encryption_key) == 16
         assert session.encryption_key != session.session_key
         assert len(session.connection.preauth_integrity_hash_value) == 2
         assert len(session.preauth_integrity_hash_value) == 3
         assert session.require_encryption
         assert session.session_id is not None
         assert len(session.session_key) == 16
         assert len(session.signing_key) == 16
         assert session.signing_key != session.session_key
         assert not session.signing_required
     finally:
         connection.disconnect(True)
         # test that disconnect can be run multiple times
         session.disconnect()
    def test_change_notify_underlying_close(self, smb_real):
        connection = Connection(uuid.uuid4(), smb_real[2], smb_real[3])
        connection.connect()
        session = Session(connection, smb_real[0], smb_real[1])
        tree = TreeConnect(session, smb_real[4])
        open = Open(tree, "directory-watch")
        try:
            session.connect()
            tree.connect()

            open.create(
                ImpersonationLevel.Impersonation,
                DirectoryAccessMask.MAXIMUM_ALLOWED,
                FileAttributes.FILE_ATTRIBUTE_DIRECTORY,
                ShareAccess.FILE_SHARE_READ | ShareAccess.FILE_SHARE_WRITE
                | ShareAccess.FILE_SHARE_DELETE,
                CreateDisposition.FILE_OPEN_IF,
                CreateOptions.FILE_DIRECTORY_FILE)

            watcher = FileSystemWatcher(open)
            watcher.start(CompletionFilter.FILE_NOTIFY_CHANGE_FILE_NAME)
            assert watcher.result is None
            assert watcher.response_event.is_set() is False

            open.close()

            expected = "Received unexpected status from the server: (267) STATUS_NOTIFY_CLEANUP"
            with pytest.raises(SMBResponseException,
                               match=re.escape(expected)):
                watcher.wait()
        finally:
            connection.disconnect(True)
    def test_change_notify_on_a_file(self, smb_real):
        connection = Connection(uuid.uuid4(), smb_real[2], smb_real[3])
        connection.connect()
        session = Session(connection, smb_real[0], smb_real[1])
        tree = TreeConnect(session, smb_real[4])
        open = Open(tree, "file-watch.txt")
        try:
            session.connect()
            tree.connect()

            open.create(
                ImpersonationLevel.Impersonation,
                FilePipePrinterAccessMask.MAXIMUM_ALLOWED,
                FileAttributes.FILE_ATTRIBUTE_NORMAL,
                ShareAccess.FILE_SHARE_READ | ShareAccess.FILE_SHARE_WRITE
                | ShareAccess.FILE_SHARE_DELETE,
                CreateDisposition.FILE_OPEN_IF,
                CreateOptions.FILE_NON_DIRECTORY_FILE)

            watcher = FileSystemWatcher(open)
            watcher.start(CompletionFilter.FILE_NOTIFY_CHANGE_FILE_NAME)
            expected = "Received unexpected status from the server: (3221225485) STATUS_INVALID_PARAMETER"
            with pytest.raises(SMBResponseException,
                               match=re.escape(expected)):
                watcher.wait()
        finally:
            connection.disconnect(True)
예제 #4
0
    def test_change_notify_on_a_file(self, smb_real):
        connection = Connection(uuid.uuid4(), smb_real[2], smb_real[3])
        connection.connect()
        session = Session(connection, smb_real[0], smb_real[1])
        tree = TreeConnect(session, smb_real[4])
        open = Open(tree, "file-watch.txt")
        try:
            session.connect()
            tree.connect()

            open.create(
                ImpersonationLevel.Impersonation,
                FilePipePrinterAccessMask.MAXIMUM_ALLOWED,
                FileAttributes.FILE_ATTRIBUTE_NORMAL,
                ShareAccess.FILE_SHARE_READ | ShareAccess.FILE_SHARE_WRITE
                | ShareAccess.FILE_SHARE_DELETE,
                CreateDisposition.FILE_OPEN_IF,
                CreateOptions.FILE_NON_DIRECTORY_FILE)

            watcher = FileSystemWatcher(open)
            watcher.start(CompletionFilter.FILE_NOTIFY_CHANGE_FILE_NAME)
            with pytest.raises(InvalidParameter):
                watcher.wait()
        finally:
            connection.disconnect(True)
예제 #5
0
    def check(self, ip_addr, port=445):
        """Checks whether a SMB server allows login without credentials"""

        try:
            # connect and attempt authentication
            connection = Connection(uuid.uuid4(),
                                    ip_addr,
                                    port,
                                    require_signing=False)
            connection.connect(Dialects.SMB_2_0_2, timeout=TIMEOUT)
            try:
                session = Session(
                    connection, "", "", require_encryption=False
                )  # dont require encryption or signing to support o2 HomeBox

                try:
                    session.connect()
                except SMBAuthenticationError:
                    return False

                return ("", "")
            finally:
                connection.disconnect()
        except Exception as e:
            print("SMB connection failed")
            print(e)

            return False
예제 #6
0
    def test_setup_session_with_ntlm_only(self, smb_real):
        connection = Connection(uuid.uuid4(), smb_real[2], smb_real[3])
        connection.connect()

        session = Session(connection,
                          smb_real[0],
                          smb_real[1],
                          False,
                          auth_protocol='ntlm')
        try:
            session.connect()
            assert len(session.application_key) == 16
            assert session.application_key != session.session_key
            assert len(session.decryption_key) == 16
            assert session.decryption_key != session.session_key
            assert not session.encrypt_data
            assert len(session.encryption_key) == 16
            assert session.encryption_key != session.session_key
            assert len(session.connection.preauth_integrity_hash_value) == 2
            assert len(session.preauth_integrity_hash_value) == 3
            assert not session.require_encryption
            assert session.session_id is not None
            assert len(session.session_key) == 16
            assert len(session.signing_key) == 16
            assert session.signing_key != session.session_key
            assert session.signing_required
        finally:
            connection.disconnect()
예제 #7
0
파일: _pool.py 프로젝트: segxi/smbprotocol
def register_session(server,
                     username=None,
                     password=None,
                     port=445,
                     encrypt=None,
                     connection_timeout=60,
                     connection_cache=None,
                     auth_protocol='negotiate'):
    """
    Creates an active connection and session to the server specified. This can be manually called to register the
    credentials of a specific server instead of defining it on the first function connecting to the server. The opened
    connection is registered in a pool and re-used if a connection is made to the same server with the same
    credentials.

    :param server: The server name to register.
    :param username: Optional username to connect with. Required if no session has been registered for the server and
        Kerberos auth is not being used.
    :param password: Optional password to connect with.
    :param port: The port to connect with.
    :param encrypt: Whether to force encryption or not, once this has been set to True the session cannot be changed
        back to False.
    :param connection_timeout: Override the timeout used for the initial connection.
    :param connection_cache: Connection cache to be used with
    :param auth_protocol: The protocol to use for authentication. Possible values are 'negotiate', 'ntlm' or
        'kerberos'. Defaults to 'negotiate'.
    :return: The Session that was registered or already existed in the pool.
    """
    connection_key = "%s:%s" % (server.lower(), port)

    if connection_cache is None:
        connection_cache = _SMB_CONNECTIONS
    connection = connection_cache.get(connection_key, None)

    # Make sure we ignore any connections that may have had a closed connection
    if not connection or not connection.transport.connected:
        connection = Connection(ClientConfig().client_guid, server, port)
        connection.connect(timeout=connection_timeout)
        connection_cache[connection_key] = connection

    # Find the first session in the connection session list that match the username specified, if not username then
    # just use the first session found or fall back to creating a new one with implicit auth/kerberos.
    session = next((s for s in connection.session_table.values()
                    if username is None or s.username == username), None)
    if not session:
        session = Session(connection,
                          username=username,
                          password=password,
                          require_encryption=(encrypt is True),
                          auth_protocol=auth_protocol)
        session.connect()
    elif encrypt is not None:
        # We cannot go from encryption to no encryption on an existing session but we can do the opposite.
        if session.encrypt_data and not encrypt:
            raise ValueError(
                "Cannot disable encryption on an already negotiated session.")
        elif not session.encrypt_data and encrypt:
            session.encrypt = True

    return session
예제 #8
0
    def fingerprint(self, ip_addr, port=445):
        try:
            # connect and attempt authentication
            connection = Connection(uuid.uuid4(),
                                    ip_addr,
                                    port,
                                    require_signing=False)
            connection.connect(Dialects.SMB_2_0_2, timeout=TIMEOUT)
            try:
                session = Session(
                    connection, "", "", require_encryption=False
                )  # dont require encryption or signing to support o2 HomeBox

                try:
                    session.connect()
                except SMBAuthenticationError:
                    # ignore authentication error
                    # the result doesn't matter as long as there was an attempt
                    pass

                for packet in session.preauth_integrity_hash_value:

                    # find a STATUS_MORE_PROCESSING_REQUIRED response
                    if not isinstance(packet, SMB2HeaderResponse) or not packet[
                            "status"].value == NtStatus.STATUS_MORE_PROCESSING_REQUIRED:
                        continue

                    sess_resp_bytes = packet["data"].value

                    # parse session setup response
                    sess_resp = SMB2SessionSetupResponse()
                    sess_resp.unpack(sess_resp_bytes)

                    chlg_mesg_bytes = sess_resp["buffer"].value

                    # skip if this is not a NTLMSSP challenge
                    # https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nlmp/801a4681-8809-4be9-ab0d-61dcfe762786
                    if not chlg_mesg_bytes.startswith(NTLMSSP_MAGIC_NUMBER):
                        continue

                    # parse NTLMSSP challenge
                    # (labelled "security blob" in wireshark)
                    chlg_mesg = ChallengeMessage(chlg_mesg_bytes)

                    # parse the version field
                    # https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nlmp/b1a6ceb2-f8ad-462b-b5af-f18527c48175
                    return struct.unpack(
                        NTLM_VERSION_STRUCT,
                        chlg_mesg.version.to_bytes(8, byteorder='little'))

                return (None, None, None, None)
            finally:
                connection.disconnect()
        except Exception as e:
            print("SMB connection failed")
            print(e)
            return (None, None, None, None)
예제 #9
0
 def test_connection_echo(self, smb_real):
     connection = Connection(uuid.uuid4(), smb_real[2], smb_real[3])
     connection.connect()
     session = Session(connection, smb_real[0], smb_real[1])
     session.connect()
     try:
         actual = connection.echo(sid=session.session_id, credit_request=2)
         assert actual == 2
     finally:
         connection.disconnect(True)
예제 #10
0
 def test_invalid_user(self, smb_real):
     connection = Connection(uuid.uuid4(), smb_real[2], smb_real[3])
     connection.connect()
     try:
         session = Session(connection, "fakeuser", "fakepass")
         with pytest.raises(SMBAuthenticationError) as exc:
             session.connect()
         assert "Failed to authenticate with server: " in str(exc.value)
     finally:
         connection.disconnect(True)
예제 #11
0
 def test_dialect_2_encrypted_share(self, smb_real):
     connection = Connection(uuid.uuid4(), smb_real[2], smb_real[3])
     connection.connect(Dialects.SMB_2_1_0)
     session = Session(connection, smb_real[0], smb_real[1], False)
     tree = TreeConnect(session, smb_real[5])
     try:
         session.connect()
         with pytest.raises(AccessDenied) as exc:
             tree.connect()
     finally:
         connection.disconnect(True)
예제 #12
0
 def test_require_encryption_not_supported(self, smb_real):
     connection = Connection(uuid.uuid4(), smb_real[2], smb_real[3])
     connection.connect(Dialects.SMB_2_1_0)
     try:
         session = Session(connection, smb_real[0], smb_real[1])
         with pytest.raises(SMBException) as exc:
             session.connect()
         assert str(exc.value) == "SMB encryption is required but the " \
                                  "connection does not support it"
     finally:
         connection.disconnect(True)
예제 #13
0
 def test_send_invalid_tree_id(self, smb_real):
     connection = Connection(uuid.uuid4(), smb_real[2], smb_real[3])
     session = Session(connection, smb_real[0], smb_real[1])
     connection.connect()
     try:
         session.connect()
         msg = SMB2IOCTLRequest()
         msg['file_id'] = b"\xff" * 16
         with pytest.raises(SMBException) as exc:
             connection.send(msg, session.session_id, 10)
         assert str(exc.value) == "Cannot find Tree with the ID 10 in " \
                                  "the session tree table"
     finally:
         connection.disconnect()
예제 #14
0
 def test_secure_negotiation_verification_failed(self, smb_real):
     connection = Connection(uuid.uuid4(), smb_real[2], smb_real[3])
     connection.connect(Dialects.SMB_3_0_2)
     session = Session(connection, smb_real[0], smb_real[1])
     connection.dialect = Dialects.SMB_3_0_0
     tree = TreeConnect(session, smb_real[4])
     try:
         session.connect()
         with pytest.raises(SMBException) as exc:
             tree.connect()
         assert "Secure negotiate failed to verify server dialect, " \
                "Actual: 770, Expected: 768" in str(exc.value)
     finally:
         connection.disconnect(True)
예제 #15
0
 def test_dialect_2_encrypted_share(self, smb_real):
     connection = Connection(uuid.uuid4(), smb_real[2], smb_real[3])
     connection.connect(Dialects.SMB_2_1_0)
     session = Session(connection, smb_real[0], smb_real[1], False)
     tree = TreeConnect(session, smb_real[5])
     try:
         session.connect()
         with pytest.raises(SMBResponseException) as exc:
             tree.connect()
         assert str(exc.value) == "Received unexpected status from the " \
                                  "server: (3221225506) " \
                                  "STATUS_ACCESS_DENIED: 0xc0000022"
     finally:
         connection.disconnect(True)
예제 #16
0
 def test_dialect_3_encrypted_share(self, smb_real):
     connection = Connection(uuid.uuid4(), smb_real[2], smb_real[3])
     connection.connect(Dialects.SMB_3_1_1)
     session = Session(connection, smb_real[0], smb_real[1])
     tree = TreeConnect(session, smb_real[5])
     try:
         session.connect()
         tree.connect()
         assert tree.encrypt_data
         assert not tree.is_ca_share
         assert not tree.is_dfs_share
         assert not tree.is_scaleout_share
         assert isinstance(tree.tree_connect_id, int)
     finally:
         connection.disconnect(True)
예제 #17
0
    def test_connect_fail(self, smb_real, monkeypatch, mocker):
        connection = Connection(uuid.uuid4(), smb_real[2], smb_real[3])
        connection.connect()
        try:
            monkeypatch.setattr(
                pyspnego, 'client',
                mocker.MagicMock(
                    side_effect=pyspnego.exceptions.NoCredentialError()))
            session = Session(connection, smb_real[0], smb_real[1])

            with pytest.raises(SMBAuthenticationError,
                               match="Failed to authenticate with server"):
                session.connect()

        finally:
            connection.disconnect(True)
예제 #18
0
 def test_decrypt_invalid_flag(self, smb_real):
     connection = Connection(uuid.uuid4(), smb_real[2], smb_real[3], True)
     session = Session(connection, smb_real[0], smb_real[1])
     connection.connect()
     try:
         session.connect()
         # just get some random message
         header = connection.preauth_integrity_hash_value[-1]
         enc_header = connection._encrypt(header.pack(), session)
         assert isinstance(enc_header, SMB2TransformHeader)
         enc_header['flags'] = 5
         with pytest.raises(SMBException) as exc:
             connection._decrypt(enc_header)
         assert str(exc.value) == "Expecting flag of 0x0001 but got 5 in " \
                                  "the SMB Transform Header Response"
     finally:
         connection.disconnect(True)
예제 #19
0
 def test_decrypt_invalid_session_id(self, smb_real):
     connection = Connection(uuid.uuid4(), smb_real[2], smb_real[3], True)
     session = Session(connection, smb_real[0], smb_real[1])
     connection.connect()
     try:
         session.connect()
         # just get some random message
         header = connection.preauth_integrity_hash_value[-1]
         enc_header = connection._encrypt(header.pack(), session)
         assert isinstance(enc_header, SMB2TransformHeader)
         enc_header['session_id'] = 100
         with pytest.raises(SMBException) as exc:
             connection._decrypt(enc_header)
         assert str(exc.value) == "Failed to find valid session 100 for " \
                                  "message decryption"
     finally:
         connection.disconnect(True)
예제 #20
0
 def test_secure_ignore_negotiation_verification_failed(self, smb_real):
     connection = Connection(uuid.uuid4(), smb_real[2], smb_real[3])
     connection.connect(Dialects.SMB_3_0_2)
     session = Session(connection, smb_real[0], smb_real[1])
     connection.dialect = Dialects.SMB_3_0_0
     tree = TreeConnect(session, smb_real[4])
     try:
         session.connect()
         tree.connect(False)
         assert not tree.encrypt_data
         assert not tree.is_ca_share
         assert not tree.is_dfs_share
         assert not tree.is_scaleout_share
         assert isinstance(tree.tree_connect_id, int)
     finally:
         connection.disconnect(True)
         tree.disconnect()  # test that disconnect can be run mutliple times
예제 #21
0
def bule_screen(IP, username=None, password=None, port=445, encode=None, connectionTimeout=10):
    _SMB_CONNECTIONS = {}
    connection_key = "%s:%s" %(IP, port)
    connection = _SMB_CONNECTIONS.get(connection_key, None)
    if not connection:
        connection = Connection(uuid.uuid4(), IP, port)
        connection.connect(timeout=connectionTimeout)
        _SMB_CONNECTIONS[connection_key] = connection
    session = next((s for s in connection.session_table.values() if username is None or s.username == username), None)
    if not session:
        session = Session(connection, username=username, password=password, require_encryption=(encode is True))
        session.connect()
    elif encode is not None:
        if session.encrypt_data and not encode:
            print("[\033[33m-\033[0m]Cannot disable encryption on an already negotiated session.")
        elif not session.encrypt_data and encode:
            session.encrypt = True
    return session
예제 #22
0
 def test_verify_mistmatch(self, smb_real):
     connection = Connection(uuid.uuid4(), smb_real[2], smb_real[3], True)
     session = Session(connection, smb_real[0], smb_real[1])
     connection.connect()
     try:
         session.connect()
         header = connection.preauth_integrity_hash_value[-2]
         # just set some random values for verifiation failure
         header['flags'].set_flag(Smb2Flags.SMB2_FLAGS_SIGNED)
         header['signature'] = b"\xff" * 16
         with pytest.raises(SMBException) as exc:
             connection._verify(header,
                                header['session_id'].get_value(),
                                verify_session=True)
         assert "Server message signature could not be verified:" in \
             str(exc.value)
     finally:
         connection.disconnect(True)
    def test_change_notify_cancel(self, smb_real):
        connection = Connection(uuid.uuid4(), smb_real[2], smb_real[3])
        connection.connect()
        session = Session(connection,
                          smb_real[0],
                          smb_real[1],
                          require_encryption=False)
        tree = TreeConnect(session, smb_real[4])
        open = Open(tree, "directory-watch")
        try:
            session.connect()
            tree.connect()

            open.create(
                ImpersonationLevel.Impersonation,
                DirectoryAccessMask.MAXIMUM_ALLOWED,
                FileAttributes.FILE_ATTRIBUTE_DIRECTORY,
                ShareAccess.FILE_SHARE_READ | ShareAccess.FILE_SHARE_WRITE
                | ShareAccess.FILE_SHARE_DELETE,
                CreateDisposition.FILE_OPEN_IF,
                CreateOptions.FILE_DIRECTORY_FILE)

            watcher = FileSystemWatcher(open)
            watcher.start(CompletionFilter.FILE_NOTIFY_CHANGE_FILE_NAME)
            assert watcher.result is None
            assert watcher.response_event.is_set() is False

            # Makes sure that we cancel after the async response has been returned from the server.
            while watcher._request.async_id is None:
                pass

            assert watcher.result is None

            watcher.cancel()

            watcher.wait()
            assert watcher.cancelled is True
            assert watcher.result is None

            # Make sure it doesn't cause any weird errors when calling it again
            watcher.cancel()
        finally:
            connection.disconnect(True)
예제 #24
0
 def test_dialect_2_1_0(self, smb_real):
     connection = Connection(uuid.uuid4(), smb_real[2], smb_real[3])
     connection.connect(Dialects.SMB_2_1_0)
     session = Session(connection, smb_real[0], smb_real[1],
                       require_encryption=False)
     try:
         session.connect()
         assert len(session.application_key) == 16
         assert session.decryption_key is None
         assert not session.encrypt_data
         assert session.encryption_key is None
         assert len(session.preauth_integrity_hash_value) == 5
         assert not session.require_encryption
         assert session.session_id is not None
         assert session.session_key == session.application_key
         assert session.signing_key == session.signing_key
         assert session.signing_required
     finally:
         connection.disconnect(True)
예제 #25
0
    def session(self):
        server = os.environ.get('PYPSEXEC_SERVER', None)
        username = os.environ.get('PYPSEXEC_USERNAME', None)
        password = os.environ.get('PYPSEXEC_PASSWORD', None)

        if server:
            connection = Connection(uuid.uuid4(), server, 445)
            session = Session(connection, username, password)
            tree = TreeConnect(session, r"\\%s\ADMIN$" % server)
            paexec_file = Open(tree, "PAExec.exe")

            connection.connect()
            try:

                session.connect()
                tree.connect()

                paexec_file.create(ImpersonationLevel.Impersonation,
                                   FilePipePrinterAccessMask.FILE_WRITE_DATA,
                                   FileAttributes.FILE_ATTRIBUTE_NORMAL,
                                   ShareAccess.FILE_SHARE_READ,
                                   CreateDisposition.FILE_OVERWRITE_IF,
                                   CreateOptions.FILE_NON_DIRECTORY_FILE)
                paexec_file.write(pkgutil.get_data('pypsexec', 'paexec.exe'),
                                  0)
                paexec_file.close(get_attributes=False)

                yield session
            finally:
                paexec_file.create(ImpersonationLevel.Impersonation,
                                   FilePipePrinterAccessMask.DELETE,
                                   FileAttributes.FILE_ATTRIBUTE_NORMAL,
                                   ShareAccess.FILE_SHARE_DELETE,
                                   CreateDisposition.FILE_OVERWRITE_IF,
                                   CreateOptions.FILE_DELETE_ON_CLOSE)
                paexec_file.close(get_attributes=False)
                connection.disconnect(True)

        else:
            pytest.skip("PYPSEXEC_SERVER, PYPSEXEC_USERNAME, PYPSEXEC_PASSWORD"
                        " environment variables were not set. Integration "
                        "tests will be skipped")
예제 #26
0
def register_session(server, username=None, password=None, port=445, encrypt=None, connection_timeout=60):
    """
    Creates an active connection and session to the server specified. This can be manually called to register the
    credentials of a specific server instead of defining it on the first function connecting to the server. The opened
    connection is registered in a pool and re-used if a connection is made to the same server with the same
    credentials.

    :param server: The server name to register.
    :param username: Optional username to connect with. Required if no session has been registered for the server and
        Kerberos auth is not being used.
    :param password: Optional password to connect with.
    :param port: The port to connect with.
    :param encrypt: Whether to force encryption or not, once this has been set to True the session cannot be changed
        back to False.
    :param connection_timeout: Override the timeout used for the initial connection.
    :return: The Session that was registered or already existed in the pool.
    """
    connection_key = "%s:%s" % (server, port)

    global _SMB_CONNECTIONS
    connection = _SMB_CONNECTIONS.get(connection_key, None)

    if not connection:
        connection = Connection(_CLIENT_GUID, server, port)
        connection.connect(timeout=connection_timeout)
        _SMB_CONNECTIONS[connection_key] = connection

    # Find the first session in the connection session list that match the username specified, if not username then
    # just use the first session found or fall back to creating a new one with implicit auth/kerberos.
    session = next((s for s in connection.session_table.values() if username is None or s.username == username), None)
    if not session:
        session = Session(connection, username=username, password=password, require_encryption=(encrypt is True))
        session.connect()
    elif encrypt is not None:
        # We cannot go from encryption to no encryption on an existing session but we can do the opposite.
        if session.encrypt_data and not encrypt:
            raise ValueError("Cannot disable encryption on an already negotiated session.")
        elif not session.encrypt_data and encrypt:
            session.encrypt = True

    return session
예제 #27
0
 def test_verify_mistmatch(self, smb_real):
     connection = Connection(uuid.uuid4(), smb_real[2], smb_real[3], True)
     session = Session(connection, smb_real[0], smb_real[1])
     connection.connect()
     try:
         session.connect()
         b_header = connection.preauth_integrity_hash_value[-2]
         header = SMB2HeaderResponse()
         header.unpack(b_header)
         # just set some random values for verification failure
         header['flags'].set_flag(Smb2Flags.SMB2_FLAGS_SIGNED)
         header['signature'] = b"\xff" * 16
         with pytest.raises(SMBException) as exc:
             connection.verify_signature(
                 header,
                 list(connection.session_table.keys())[0],
                 force=True)
         assert "Server message signature could not be verified:" in str(
             exc.value)
     finally:
         connection.disconnect(True)
예제 #28
0
 def test_setup_session_with_ms_gss_token(self, smb_real):
     connection = Connection(uuid.uuid4(), smb_real[2], smb_real[3])
     connection.connect()
     connection.gss_negotiate_token = b"\x60\x76\x06\x06\x2b\x06\x01\x05" \
                                      b"\x05\x02\xa0\x6c\x30\x6a\xa0\x3c" \
                                      b"\x30\x3a\x06\x0a\x2b\x06\x01\x04" \
                                      b"\x01\x82\x37\x02\x02\x1e\x06\x09" \
                                      b"\x2a\x86\x48\x82\xf7\x12\x01\x02" \
                                      b"\x02\x06\x09\x2a\x86\x48\x86\xf7" \
                                      b"\x12\x01\x02\x02\x06\x0a\x2a\x86" \
                                      b"\x48\x86\xf7\x12\x01\x02\x02\x03" \
                                      b"\x06\x0a\x2b\x06\x01\x04\x01\x82" \
                                      b"\x37\x02\x02\x0a\xa3\x2a\x30\x28" \
                                      b"\xa0\x26\x1b\x24\x6e\x6f\x74\x5f" \
                                      b"\x64\x65\x66\x69\x6e\x65\x64\x5f" \
                                      b"\x69\x6e\x5f\x52\x46\x43\x34\x31" \
                                      b"\x37\x38\x40\x70\x6c\x65\x61\x73" \
                                      b"\x65\x5f\x69\x67\x6e\x6f\x72\x65"
     session = Session(connection, smb_real[0], smb_real[1], False)
     try:
         session.connect()
         assert len(session.application_key) == 16
         assert session.application_key != session.session_key
         assert len(session.decryption_key) == 16
         assert session.decryption_key != session.session_key
         assert not session.encrypt_data
         assert len(session.encryption_key) == 16
         assert session.encryption_key != session.session_key
         assert len(session.connection.preauth_integrity_hash_value) == 2
         assert len(session.preauth_integrity_hash_value) == 3
         assert not session.require_encryption
         assert session.session_id is not None
         assert len(session.session_key) == 16
         assert len(session.signing_key) == 16
         assert session.signing_key != session.session_key
         assert session.signing_required
     finally:
         connection.disconnect(True)
    def test_change_notify_on_dir_compound(self, smb_real):
        connection = Connection(uuid.uuid4(), smb_real[2], smb_real[3])
        connection.connect()

        # Cannot use encryption as Samba has a bug where the transform response has the wrong Session Id. Also there's
        # a special edge case of testing the Session Id of the plaintext response with signatures so don't use
        # encryption.
        # https://bugzilla.samba.org/show_bug.cgi?id=14189
        session = Session(connection,
                          smb_real[0],
                          smb_real[1],
                          require_encryption=False)
        tree = TreeConnect(session, smb_real[4])
        open = Open(tree, "directory-watch")
        try:
            session.connect()
            tree.connect()

            # Ensure the dir is clean of files.
            open.create(
                ImpersonationLevel.Impersonation,
                DirectoryAccessMask.MAXIMUM_ALLOWED,
                FileAttributes.FILE_ATTRIBUTE_DIRECTORY,
                ShareAccess.FILE_SHARE_READ | ShareAccess.FILE_SHARE_WRITE
                | ShareAccess.FILE_SHARE_DELETE,
                CreateDisposition.FILE_OPEN_IF,
                CreateOptions.FILE_DIRECTORY_FILE)
            self._remove_file(tree, "directory-watch\\created file")
            open.close()

            watcher = FileSystemWatcher(open)
            messages = [
                open.create(ImpersonationLevel.Impersonation,
                            DirectoryAccessMask.MAXIMUM_ALLOWED,
                            FileAttributes.FILE_ATTRIBUTE_DIRECTORY,
                            ShareAccess.FILE_SHARE_READ
                            | ShareAccess.FILE_SHARE_WRITE
                            | ShareAccess.FILE_SHARE_DELETE,
                            CreateDisposition.FILE_OPEN_IF,
                            CreateOptions.FILE_DIRECTORY_FILE,
                            send=False),
                watcher.start(CompletionFilter.FILE_NOTIFY_CHANGE_FILE_NAME,
                              send=False)
            ]

            assert watcher.result is None
            assert watcher.response_event.is_set() is False

            requests = connection.send_compound([m[0] for m in messages],
                                                sid=session.session_id,
                                                tid=tree.tree_connect_id,
                                                related=True)
            [messages[i][1](req) for i, req in enumerate(requests)]

            # Run the wait in a separate thread so we can create the dir
            def watcher_wait():
                watcher.wait()

            watcher_wait_thread = threading.Thread(target=watcher_wait)
            watcher_wait_thread.daemon = True
            watcher_wait_thread.start()

            def watcher_event():
                watcher.response_event.wait()

            watcher_event_thread = threading.Thread(target=watcher_event)
            watcher_event_thread.daemon = True
            watcher_event_thread.start()

            # Create the new file
            file_open = Open(tree, "directory-watch\\created file")
            file_open.create(
                ImpersonationLevel.Impersonation,
                FilePipePrinterAccessMask.MAXIMUM_ALLOWED,
                FileAttributes.FILE_ATTRIBUTE_NORMAL,
                ShareAccess.FILE_SHARE_READ | ShareAccess.FILE_SHARE_WRITE
                | ShareAccess.FILE_SHARE_DELETE,
                CreateDisposition.FILE_OPEN_IF,
                CreateOptions.FILE_NON_DIRECTORY_FILE)
            file_open.close()

            watcher_wait_thread.join(timeout=2)
            watcher_event_thread.join(timeout=2)
            assert watcher_wait_thread.is_alive() is False
            assert watcher_event_thread.is_alive() is False

            assert watcher.response_event.is_set()
            assert len(watcher.result) == 1

            assert watcher.result[0]['file_name'].get_value(
            ) == u"created file"
            assert watcher.result[0]['action'].get_value(
            ) == FileAction.FILE_ACTION_ADDED

            open.close()
        finally:
            connection.disconnect(True)
    def test_change_notify_no_data(self, smb_real):
        connection = Connection(uuid.uuid4(), smb_real[2], smb_real[3])
        connection.connect()
        session = Session(connection, smb_real[0], smb_real[1])
        tree = TreeConnect(session, smb_real[4])
        open = Open(tree, "directory-watch")
        try:
            session.connect()
            tree.connect()

            open.create(
                ImpersonationLevel.Impersonation,
                DirectoryAccessMask.MAXIMUM_ALLOWED,
                FileAttributes.FILE_ATTRIBUTE_DIRECTORY,
                ShareAccess.FILE_SHARE_READ | ShareAccess.FILE_SHARE_WRITE
                | ShareAccess.FILE_SHARE_DELETE,
                CreateDisposition.FILE_OPEN_IF,
                CreateOptions.FILE_DIRECTORY_FILE)

            self._remove_file(tree, "directory-watch\\created file")

            watcher = FileSystemWatcher(open)
            watcher.start(CompletionFilter.FILE_NOTIFY_CHANGE_FILE_NAME,
                          output_buffer_length=0)
            assert watcher.result is None
            assert watcher.response_event.is_set() is False

            # Run the wait in a separate thread so we can create the dir
            def watcher_wait():
                watcher.wait()

            watcher_wait_thread = threading.Thread(target=watcher_wait)
            watcher_wait_thread.daemon = True
            watcher_wait_thread.start()

            def watcher_event():
                watcher.response_event.wait()

            watcher_event_thread = threading.Thread(target=watcher_event)
            watcher_event_thread.daemon = True
            watcher_event_thread.start()

            # Create the new file
            file_open = Open(tree, "directory-watch\\created file")
            file_open.create(
                ImpersonationLevel.Impersonation,
                FilePipePrinterAccessMask.MAXIMUM_ALLOWED,
                FileAttributes.FILE_ATTRIBUTE_NORMAL,
                ShareAccess.FILE_SHARE_READ | ShareAccess.FILE_SHARE_WRITE
                | ShareAccess.FILE_SHARE_DELETE,
                CreateDisposition.FILE_OPEN_IF,
                CreateOptions.FILE_NON_DIRECTORY_FILE)
            file_open.close()

            watcher_wait_thread.join(timeout=2)
            watcher_event_thread.join(timeout=2)
            assert watcher_wait_thread.is_alive() is False
            assert watcher_event_thread.is_alive() is False

            assert watcher.response_event.is_set()
            assert watcher.result == []

            open.close()
        finally:
            connection.disconnect(True)