From 7ab510c16169c2ac3bfec5911d3d7f2b2dedaa71 Mon Sep 17 00:00:00 2001 From: Olivier Bilodeau Date: Wed, 2 Nov 2022 00:11:50 -0400 Subject: [PATCH 1/6] Typed ioStatus to NTSTATUS Per Microsoft's own RDP specification but without a lot of values populated just yet --- pyrdp/core/event.py | 6 +++--- pyrdp/enum/__init__.py | 1 + pyrdp/enum/windows.py | 20 +++++++++++++++++++ pyrdp/mitm/DeviceRedirectionMITM.py | 2 +- .../rdp/virtual_channel/device_redirection.py | 13 ++++++------ .../rdp/virtual_channel/device_redirection.py | 14 ++++++------- 6 files changed, 39 insertions(+), 17 deletions(-) create mode 100644 pyrdp/enum/windows.py diff --git a/pyrdp/core/event.py b/pyrdp/core/event.py index b40e2709e..548313f56 100644 --- a/pyrdp/core/event.py +++ b/pyrdp/core/event.py @@ -1,12 +1,12 @@ # # This file is part of the PyRDP project. -# Copyright (C) 2019 GoSecure Inc. +# Copyright (C) 2019, 2022 GoSecure Inc. # Licensed under the GPLv3 or later. # import asyncio import operator -from typing import Callable, Dict +from typing import Callable, Dict, List class Event: @@ -118,7 +118,7 @@ def __init__(self): """ Create a new (empty) event engine. """ - self.events: [Event] = [] + self.events: List[Event] = [] def processObject(self, obj): """ diff --git a/pyrdp/enum/__init__.py b/pyrdp/enum/__init__.py index 99aaebf6e..2d7950452 100644 --- a/pyrdp/enum/__init__.py +++ b/pyrdp/enum/__init__.py @@ -22,4 +22,5 @@ FileCreateDisposition, FileCreateOptions, FileShareAccess, FileSystemInformationClass, GeneralCapabilityVersion, \ IOOperationSeverity, MajorFunction, MinorFunction, RDPDRCapabilityType from pyrdp.enum.virtual_channel.virtual_channel import VirtualChannelPDUFlag +from pyrdp.enum.windows import NTSTATUS from pyrdp.enum.x224 import X224PDUType diff --git a/pyrdp/enum/windows.py b/pyrdp/enum/windows.py new file mode 100644 index 000000000..ca37e8ed6 --- /dev/null +++ b/pyrdp/enum/windows.py @@ -0,0 +1,20 @@ +# +# This file is part of the PyRDP project. +# Copyright (C) 2022 GoSecure Inc. +# Licensed under the GPLv3 or later. +# + +# Disable line-too-long lints. +# flake8: noqa + +from enum import IntEnum + + +class NTSTATUS(IntEnum): + """ + [MS-ERREF]: Windows Error Codes + https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/87fba13e-bf06-450e-83b1-9241dc81e781 + """ + STATUS_SUCCESS = 0x00000000 + STATUS_NO_MORE_FILES = 0x80000006 + STATUS_NO_SUCH_FILE = 0xC000000F \ No newline at end of file diff --git a/pyrdp/mitm/DeviceRedirectionMITM.py b/pyrdp/mitm/DeviceRedirectionMITM.py index ad5df29b1..489eebc9b 100644 --- a/pyrdp/mitm/DeviceRedirectionMITM.py +++ b/pyrdp/mitm/DeviceRedirectionMITM.py @@ -11,7 +11,7 @@ from pyrdp.enum import CreateOption, DeviceRedirectionPacketID, DeviceType, DirectoryAccessMask, FileAccessMask, \ FileAttributes, \ FileCreateDisposition, FileCreateOptions, FileShareAccess, FileSystemInformationClass, IOOperationSeverity, \ - MajorFunction, MinorFunction + MajorFunction, MinorFunction, NTSTATUS from pyrdp.layer import DeviceRedirectionLayer from pyrdp.logging.StatCounter import StatCounter, STAT from pyrdp.mitm.FileMapping import FileMapping diff --git a/pyrdp/parser/rdp/virtual_channel/device_redirection.py b/pyrdp/parser/rdp/virtual_channel/device_redirection.py index 37fe8adcf..ef9193405 100644 --- a/pyrdp/parser/rdp/virtual_channel/device_redirection.py +++ b/pyrdp/parser/rdp/virtual_channel/device_redirection.py @@ -11,7 +11,8 @@ from pyrdp.enum import DeviceRedirectionComponent, DeviceRedirectionPacketID, \ DeviceType, FileAccessMask, FileAttributes, FileCreateDisposition, \ FileCreateOptions, FileShareAccess, FileSystemInformationClass, \ - GeneralCapabilityVersion, MajorFunction, MinorFunction, RDPDRCapabilityType + GeneralCapabilityVersion, MajorFunction, MinorFunction, \ + RDPDRCapabilityType, NTSTATUS from pyrdp.parser import Parser from pyrdp.pdu import DeviceAnnounce, DeviceCloseRequestPDU, DeviceCloseResponsePDU, DeviceCreateRequestPDU, \ DeviceCreateResponsePDU, DeviceDirectoryControlResponsePDU, DeviceIORequestPDU, DeviceIOResponsePDU, \ @@ -296,7 +297,7 @@ def writeDeviceIORequest(self, pdu: DeviceIORequestPDU, stream: BytesIO): def parseDeviceIOResponse(self, stream: BytesIO) -> DeviceIOResponsePDU: deviceID = Uint32LE.unpack(stream) completionID = Uint32LE.unpack(stream) - ioStatus = Uint32LE.unpack(stream) + ioStatus = NTSTATUS(Uint32LE.unpack(stream)) majorFunction = self.majorFunctionsForParsingResponse.pop(completionID, None) @@ -361,7 +362,7 @@ def writeDeviceCreateRequest(self, pdu: DeviceCreateRequestPDU, stream: BytesIO) stream.write(path) - def parseDeviceCreateResponse(self, deviceID: int, completionID: int, ioStatus: int, stream: BytesIO) -> DeviceCreateResponsePDU: + def parseDeviceCreateResponse(self, deviceID: int, completionID: int, ioStatus: NTSTATUS, stream: BytesIO) -> DeviceCreateResponsePDU: """ The information field is not yet parsed (it's optional). This one is a bit special since we need to look at previous packet before parsing it as @@ -396,7 +397,7 @@ def writeDeviceReadRequest(self, pdu: DeviceReadRequestPDU, stream: BytesIO): stream.write(b"\x00" * 20) # Padding - def parseDeviceReadResponse(self, deviceID: int, completionID: int, ioStatus: int, stream: BytesIO) -> DeviceReadResponsePDU: + def parseDeviceReadResponse(self, deviceID: int, completionID: int, ioStatus: NTSTATUS, stream: BytesIO) -> DeviceReadResponsePDU: length = Uint32LE.unpack(stream) payload = stream.read(length) @@ -415,7 +416,7 @@ def writeDeviceCloseRequest(self, _: DeviceCloseRequestPDU, stream: BytesIO): stream.write(b"\x00" * 32) # Padding - def parseDeviceCloseResponse(self, deviceID: int, completionID: int, ioStatus: int, stream: BytesIO) -> DeviceCloseResponsePDU: + def parseDeviceCloseResponse(self, deviceID: int, completionID: int, ioStatus: NTSTATUS, stream: BytesIO) -> DeviceCloseResponsePDU: stream.read(4) # Padding return DeviceCloseResponsePDU(deviceID, completionID, ioStatus) @@ -461,7 +462,7 @@ def writeDirectoryControlRequest(self, pdu: Union[DeviceIORequestPDU, DeviceQuer stream.write(b"\x00" * 23) # protocol required padding stream.write(path) - def parseDirectoryControlResponse(self, deviceID: int, completionID: int, ioStatus: int, stream: BytesIO) -> DeviceIOResponsePDU: + def parseDirectoryControlResponse(self, deviceID: int, completionID: int, ioStatus: NTSTATUS, stream: BytesIO) -> DeviceIOResponsePDU: minorFunction = self.minorFunctionsForParsingResponse.pop(completionID, None) if minorFunction is None: diff --git a/pyrdp/pdu/rdp/virtual_channel/device_redirection.py b/pyrdp/pdu/rdp/virtual_channel/device_redirection.py index 409942809..fcfba3930 100644 --- a/pyrdp/pdu/rdp/virtual_channel/device_redirection.py +++ b/pyrdp/pdu/rdp/virtual_channel/device_redirection.py @@ -9,7 +9,7 @@ from pyrdp.enum import DeviceRedirectionComponent, DeviceRedirectionPacketID, \ DeviceType, FileAccessMask, FileAttributes, FileCreateDisposition, \ FileCreateOptions, FileShareAccess, FileSystemInformationClass, \ - MajorFunction, MinorFunction, RDPDRCapabilityType + MajorFunction, MinorFunction, RDPDRCapabilityType, NTSTATUS from pyrdp.pdu import PDU @@ -43,7 +43,7 @@ class DeviceIOResponsePDU(DeviceRedirectionPDU): https://msdn.microsoft.com/en-us/library/cc241334.aspx """ - def __init__(self, majorFunction: Optional[MajorFunction], deviceID: int, completionID: int, ioStatus: int, payload=b""): + def __init__(self, majorFunction: Optional[MajorFunction], deviceID: int, completionID: int, ioStatus: NTSTATUS, payload=b""): super().__init__(DeviceRedirectionComponent.RDPDR_CTYP_CORE, DeviceRedirectionPacketID.PAKID_CORE_DEVICE_IOCOMPLETION) self.majorFunction = majorFunction self.deviceID = deviceID @@ -75,7 +75,7 @@ class DeviceCreateResponsePDU(DeviceIOResponsePDU): https://msdn.microsoft.com/en-us/library/cc241335.aspx """ - def __init__(self, deviceID: int, completionID: int, ioStatus: int, fileID: int, information: int): + def __init__(self, deviceID: int, completionID: int, ioStatus: NTSTATUS, fileID: int, information: int): super().__init__(MajorFunction.IRP_MJ_CREATE, deviceID, completionID, ioStatus) self.fileID = fileID self.information = information @@ -98,7 +98,7 @@ class DeviceReadResponsePDU(DeviceIOResponsePDU): https://msdn.microsoft.com/en-us/library/cc241337.aspx """ - def __init__(self, deviceID: int, completionID: int, ioStatus: int, readData: bytes): + def __init__(self, deviceID: int, completionID: int, ioStatus: NTSTATUS, readData: bytes): super().__init__(MajorFunction.IRP_MJ_READ, deviceID, completionID, ioStatus, readData) @@ -116,7 +116,7 @@ class DeviceCloseResponsePDU(DeviceIOResponsePDU): https://msdn.microsoft.com/en-us/library/cc241336.aspx """ - def __init__(self, deviceID: int, completionID: int, ioStatus: int): + def __init__(self, deviceID: int, completionID: int, ioStatus: NTSTATUS): super().__init__(MajorFunction.IRP_MJ_CLOSE, deviceID, completionID, ioStatus) @@ -184,13 +184,13 @@ def __init__(self, deviceID: int, fileID: int, completionID: int, informationCla class DeviceDirectoryControlResponsePDU(DeviceIOResponsePDU): - def __init__(self, minorFunction: MinorFunction, deviceID: int, completionID: int, ioStatus: int, payload: bytes = b""): + def __init__(self, minorFunction: MinorFunction, deviceID: int, completionID: int, ioStatus: NTSTATUS, payload: bytes = b""): super().__init__(MajorFunction.IRP_MJ_DIRECTORY_CONTROL, deviceID, completionID, ioStatus, payload) self.minorFunction = minorFunction class DeviceQueryDirectoryResponsePDU(DeviceDirectoryControlResponsePDU): - def __init__(self, deviceID: int, completionID: int, ioStatus: int, informationClass: FileSystemInformationClass, fileInformation: List[FileInformationBase], endByte: bytes): + def __init__(self, deviceID: int, completionID: int, ioStatus: NTSTATUS, informationClass: FileSystemInformationClass, fileInformation: List[FileInformationBase], endByte: bytes): super().__init__(MinorFunction.IRP_MN_QUERY_DIRECTORY, deviceID, completionID, ioStatus) self.informationClass = informationClass self.fileInformation = fileInformation From a2637ec26ec6f770c90bb3258e85539f7746882c Mon Sep 17 00:00:00 2001 From: Olivier Bilodeau Date: Tue, 15 Nov 2022 11:24:17 -0500 Subject: [PATCH 2/6] refactoring: NtStatusSeverity into Windows enums --- pyrdp/enum/__init__.py | 4 ++-- pyrdp/enum/virtual_channel/device_redirection.py | 10 ---------- pyrdp/enum/windows.py | 13 +++++++++++++ pyrdp/mitm/DeviceRedirectionMITM.py | 6 +++--- test/test_DeviceRedirectionMITM.py | 6 +++--- 5 files changed, 21 insertions(+), 18 deletions(-) diff --git a/pyrdp/enum/__init__.py b/pyrdp/enum/__init__.py index 2d7950452..19484e020 100644 --- a/pyrdp/enum/__init__.py +++ b/pyrdp/enum/__init__.py @@ -20,7 +20,7 @@ from pyrdp.enum.virtual_channel.device_redirection import CreateOption, DeviceRedirectionComponent, \ DeviceRedirectionPacketID, DeviceType, DirectoryAccessMask, FileAccessMask, FileAttributes, \ FileCreateDisposition, FileCreateOptions, FileShareAccess, FileSystemInformationClass, GeneralCapabilityVersion, \ - IOOperationSeverity, MajorFunction, MinorFunction, RDPDRCapabilityType + MajorFunction, MinorFunction, RDPDRCapabilityType from pyrdp.enum.virtual_channel.virtual_channel import VirtualChannelPDUFlag -from pyrdp.enum.windows import NTSTATUS +from pyrdp.enum.windows import NTSTATUS, NtStatusSeverity from pyrdp.enum.x224 import X224PDUType diff --git a/pyrdp/enum/virtual_channel/device_redirection.py b/pyrdp/enum/virtual_channel/device_redirection.py index a1c64f8a0..069a44a5c 100644 --- a/pyrdp/enum/virtual_channel/device_redirection.py +++ b/pyrdp/enum/virtual_channel/device_redirection.py @@ -60,16 +60,6 @@ class MinorFunction(IntEnum): IRP_MN_NOTIFY_CHANGE_DIRECTORY = 0x00000002 -class IOOperationSeverity(IntEnum): - """ - https://msdn.microsoft.com/en-us/library/cc231200.aspx - """ - STATUS_SEVERITY_SUCCESS = 0x0 - STATUS_SEVERITY_INFORMATIONAL = 0x1 - STATUS_SEVERITY_WARNING = 0x2 - STATUS_SEVERITY_ERROR = 0x3 - - class CreateOption(IntEnum): FILE_DIRECTORY_FILE = 0x00000001 FILE_WRITE_THROUGH = 0x00000002 diff --git a/pyrdp/enum/windows.py b/pyrdp/enum/windows.py index ca37e8ed6..c29ae91a4 100644 --- a/pyrdp/enum/windows.py +++ b/pyrdp/enum/windows.py @@ -10,6 +10,19 @@ from enum import IntEnum +class NtStatusSeverity(IntEnum): + """ + [MS-ERREF]: Windows Error Codes + https://msdn.microsoft.com/en-us/library/cc231199.aspx + [MS-ERREF]: NTSTATUS + https://msdn.microsoft.com/en-us/library/cc231200.aspx + """ + STATUS_SEVERITY_SUCCESS = 0x0 + STATUS_SEVERITY_INFORMATIONAL = 0x1 + STATUS_SEVERITY_WARNING = 0x2 + STATUS_SEVERITY_ERROR = 0x3 + + class NTSTATUS(IntEnum): """ [MS-ERREF]: Windows Error Codes diff --git a/pyrdp/mitm/DeviceRedirectionMITM.py b/pyrdp/mitm/DeviceRedirectionMITM.py index 489eebc9b..270a4289e 100644 --- a/pyrdp/mitm/DeviceRedirectionMITM.py +++ b/pyrdp/mitm/DeviceRedirectionMITM.py @@ -10,8 +10,8 @@ from pyrdp.core import ObservedBy, Observer, Subject from pyrdp.enum import CreateOption, DeviceRedirectionPacketID, DeviceType, DirectoryAccessMask, FileAccessMask, \ FileAttributes, \ - FileCreateDisposition, FileCreateOptions, FileShareAccess, FileSystemInformationClass, IOOperationSeverity, \ - MajorFunction, MinorFunction, NTSTATUS + FileCreateDisposition, FileCreateOptions, FileShareAccess, FileSystemInformationClass, \ + MajorFunction, MinorFunction, NTSTATUS, NtStatusSeverity from pyrdp.layer import DeviceRedirectionLayer from pyrdp.logging.StatCounter import StatCounter, STAT from pyrdp.mitm.FileMapping import FileMapping @@ -177,7 +177,7 @@ def handleIOResponse(self, pdu: DeviceIOResponsePDU): elif key in self.currentIORequests: requestPDU = self.currentIORequests.pop(key) - if pdu.ioStatus >> 30 == IOOperationSeverity.STATUS_SEVERITY_ERROR: + if pdu.ioStatus >> 30 == NtStatusSeverity.STATUS_SEVERITY_ERROR: self.statCounter.increment(STAT.DEVICE_REDIRECTION_IOERROR) self.log.warning("Received an IO Response with an error IO status: %(responsePDU)s for request %(requestPDU)s", {"responsePDU": repr(pdu), "requestPDU": repr(requestPDU)}) diff --git a/test/test_DeviceRedirectionMITM.py b/test/test_DeviceRedirectionMITM.py index 5d0672f2e..d0777808c 100644 --- a/test/test_DeviceRedirectionMITM.py +++ b/test/test_DeviceRedirectionMITM.py @@ -8,15 +8,15 @@ from pathlib import Path from unittest.mock import Mock, MagicMock, patch -from pyrdp.enum import CreateOption, FileAccessMask, IOOperationSeverity, DeviceRedirectionPacketID, MajorFunction, \ - MinorFunction +from pyrdp.enum import CreateOption, FileAccessMask, DeviceRedirectionPacketID, MajorFunction, \ + MinorFunction, NtStatusSeverity from pyrdp.logging.StatCounter import StatCounter, STAT from pyrdp.mitm.DeviceRedirectionMITM import DeviceRedirectionMITM from pyrdp.pdu import DeviceIOResponsePDU, DeviceRedirectionPDU def MockIOError(): - ioError = Mock(deviceID = 0, completionID = 0, ioStatus = IOOperationSeverity.STATUS_SEVERITY_ERROR << 30) + ioError = Mock(deviceID = 0, completionID = 0, ioStatus = NtStatusSeverity.STATUS_SEVERITY_ERROR << 30) return ioError From 034f0b82eb9c789a10fd47ba9f423f2ea2762b29 Mon Sep 17 00:00:00 2001 From: Olivier Bilodeau Date: Tue, 15 Nov 2022 11:27:58 -0500 Subject: [PATCH 3/6] copyright bump --- pyrdp/enum/__init__.py | 2 +- pyrdp/enum/virtual_channel/device_redirection.py | 2 +- pyrdp/mitm/DeviceRedirectionMITM.py | 2 +- test/test_DeviceRedirectionMITM.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pyrdp/enum/__init__.py b/pyrdp/enum/__init__.py index 19484e020..f6ababd94 100644 --- a/pyrdp/enum/__init__.py +++ b/pyrdp/enum/__init__.py @@ -1,6 +1,6 @@ # # This file is part of the PyRDP project. -# Copyright (C) 2018-2021 GoSecure Inc. +# Copyright (C) 2018-2022 GoSecure Inc. # Licensed under the GPLv3 or later. # # flake8: noqa diff --git a/pyrdp/enum/virtual_channel/device_redirection.py b/pyrdp/enum/virtual_channel/device_redirection.py index 069a44a5c..7fbb54273 100644 --- a/pyrdp/enum/virtual_channel/device_redirection.py +++ b/pyrdp/enum/virtual_channel/device_redirection.py @@ -1,6 +1,6 @@ # # This file is part of the PyRDP project. -# Copyright (C) 2018 GoSecure Inc. +# Copyright (C) 2018, 2022 GoSecure Inc. # Licensed under the GPLv3 or later. # diff --git a/pyrdp/mitm/DeviceRedirectionMITM.py b/pyrdp/mitm/DeviceRedirectionMITM.py index 270a4289e..c17ad3e2e 100644 --- a/pyrdp/mitm/DeviceRedirectionMITM.py +++ b/pyrdp/mitm/DeviceRedirectionMITM.py @@ -1,6 +1,6 @@ # # This file is part of the PyRDP project. -# Copyright (C) 2019-2021 GoSecure Inc. +# Copyright (C) 2019-2022 GoSecure Inc. # Licensed under the GPLv3 or later. # diff --git a/test/test_DeviceRedirectionMITM.py b/test/test_DeviceRedirectionMITM.py index d0777808c..b6c074235 100644 --- a/test/test_DeviceRedirectionMITM.py +++ b/test/test_DeviceRedirectionMITM.py @@ -1,6 +1,6 @@ # # This file is part of the PyRDP project. -# Copyright (C) 2020-2021 GoSecure Inc. +# Copyright (C) 2020-2022 GoSecure Inc. # Licensed under the GPLv3 or later. # From dbc015aeb91888ca6e48615256bb31f1a1e449a9 Mon Sep 17 00:00:00 2001 From: Olivier Bilodeau Date: Tue, 15 Nov 2022 11:43:09 -0500 Subject: [PATCH 4/6] reduced warning logging in IO Response handling --- pyrdp/mitm/DeviceRedirectionMITM.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/pyrdp/mitm/DeviceRedirectionMITM.py b/pyrdp/mitm/DeviceRedirectionMITM.py index c17ad3e2e..ea217914c 100644 --- a/pyrdp/mitm/DeviceRedirectionMITM.py +++ b/pyrdp/mitm/DeviceRedirectionMITM.py @@ -179,7 +179,14 @@ def handleIOResponse(self, pdu: DeviceIOResponsePDU): if pdu.ioStatus >> 30 == NtStatusSeverity.STATUS_SEVERITY_ERROR: self.statCounter.increment(STAT.DEVICE_REDIRECTION_IOERROR) - self.log.warning("Received an IO Response with an error IO status: %(responsePDU)s for request %(requestPDU)s", {"responsePDU": repr(pdu), "requestPDU": repr(requestPDU)}) + # log only for unexpected errors since "no such files" and "no more files" are frequent: + # "no such files" for all attempts at fetching .desktop.ini + # "no more files" when directory listings are finished + if pdu.ioStatus not in [NTSTATUS.STATUS_NO_SUCH_FILE, + NTSTATUS.STATUS_NO_MORE_FILES]: + self.log.warning("Received an IO Response with an error IO status: " + "%(responsePDU)s for request %(requestPDU)s", + {"responsePDU": repr(pdu), "requestPDU": repr(requestPDU)}) if pdu.majorFunction in self.responseHandlers: self.responseHandlers[pdu.majorFunction](requestPDU, pdu) From 73618598d58c985de172787f7ca70b28f4112f77 Mon Sep 17 00:00:00 2001 From: Olivier Bilodeau Date: Tue, 15 Nov 2022 11:43:55 -0500 Subject: [PATCH 5/6] debugging hint --- pyrdp/mitm/DeviceRedirectionMITM.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pyrdp/mitm/DeviceRedirectionMITM.py b/pyrdp/mitm/DeviceRedirectionMITM.py index ea217914c..28cde7bf8 100644 --- a/pyrdp/mitm/DeviceRedirectionMITM.py +++ b/pyrdp/mitm/DeviceRedirectionMITM.py @@ -190,6 +190,10 @@ def handleIOResponse(self, pdu: DeviceIOResponsePDU): if pdu.majorFunction in self.responseHandlers: self.responseHandlers[pdu.majorFunction](requestPDU, pdu) + # Good place to debug + #else: + # self.log.warning("No handler was triggered for this IO request: %(requestPDU)s. Response: %(responsePDU)s", {"responsePDU": repr(pdu), "requestPDU": repr(requestPDU)}) + else: self.log.error("Received IO response to unknown request #%(completionID)d", {"completionID": pdu.completionID}) From e7022cfa6386d1b279d210881be967dd863a002d Mon Sep 17 00:00:00 2001 From: Olivier Bilodeau Date: Tue, 15 Nov 2022 11:44:28 -0500 Subject: [PATCH 6/6] Do not attempt to intercept unexisting files --- pyrdp/mitm/DeviceRedirectionMITM.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyrdp/mitm/DeviceRedirectionMITM.py b/pyrdp/mitm/DeviceRedirectionMITM.py index 28cde7bf8..a4485c495 100644 --- a/pyrdp/mitm/DeviceRedirectionMITM.py +++ b/pyrdp/mitm/DeviceRedirectionMITM.py @@ -225,8 +225,9 @@ def handleCreateResponse(self, request: DeviceCreateRequestPDU, response: Device isFileRead = request.desiredAccess & (FileAccessMask.GENERIC_READ | FileAccessMask.FILE_READ_DATA) != 0 isDirectory = request.createOptions & CreateOption.FILE_NON_DIRECTORY_FILE == 0 + fileExists = (response.ioStatus != NTSTATUS.STATUS_NO_SUCH_FILE) - if isFileRead and not isDirectory: + if fileExists and isFileRead and not isDirectory: mapping = FileMapping.generate(request.path, self.config.fileDir, self.deviceRoot(response.deviceID), self.log) key = (response.deviceID, response.fileID) self.mappings[key] = mapping