Exemple #1
0
    def onClipboardData(self, pdu: PlayerPDU):
        parser = ClipboardParser()
        pdu = parser.parse(pdu.payload)

        if not isinstance(pdu, FormatDataResponsePDU):
            return

        clipboardData = decodeUTF16LE(pdu.requestedFormatData)

        self.writeSeparator()
        self.writeText(f"CLIPBOARD DATA: {clipboardData}")
        self.writeSeparator()
Exemple #2
0
    def parse(self, data: bytes) -> ClientInfoPDU:
        """
        Decode a Client Info PDU from bytes.
        :param data: the Client Info PDU bytes.
        """
        stream = BytesIO(data)
        codePage = Uint32LE.unpack(stream)
        flags = Uint32LE.unpack(stream)

        isUnicode = flags & ClientInfoFlags.INFO_UNICODE != 0
        hasNullBytes = codePage == 1252 or isUnicode
        nullByteCount = 1 if hasNullBytes else 0
        unicodeMultiplier = 2 if isUnicode else 0

        domainLength = Uint16LE.unpack(
            stream) + nullByteCount * unicodeMultiplier
        usernameLength = Uint16LE.unpack(
            stream) + nullByteCount * unicodeMultiplier
        passwordLength = Uint16LE.unpack(
            stream) + nullByteCount * unicodeMultiplier
        alternateShellLength = Uint16LE.unpack(
            stream) + nullByteCount * unicodeMultiplier
        workingDirLength = Uint16LE.unpack(
            stream) + nullByteCount * unicodeMultiplier

        domain = decodeUTF16LE(stream.read(domainLength))
        username = decodeUTF16LE(stream.read(usernameLength))
        password = decodeUTF16LE(stream.read(passwordLength))
        alternateShell = decodeUTF16LE(stream.read(alternateShellLength))
        workingDir = decodeUTF16LE(stream.read(workingDirLength))

        extraInfoBytes = stream.read()

        if extraInfoBytes != b"":
            extraInfo = self.parseExtraInfo(extraInfoBytes)
        else:
            extraInfo = None

        return ClientInfoPDU(codePage, flags, domain, username, password,
                             alternateShell, workingDir, extraInfo)
Exemple #3
0
    def parseFileBothDirectoryInformation(
            self, data: bytes) -> List[FileBothDirectoryInformation]:
        stream = BytesIO(data)
        information: [FileBothDirectoryInformation] = []

        while stream.tell() < len(data):
            nextEntryOffset = Uint32LE.unpack(stream)
            fileIndex = Uint32LE.unpack(stream)
            creationTime = Uint64LE.unpack(stream)
            lastAccessTime = Uint64LE.unpack(stream)
            lastWriteTime = Uint64LE.unpack(stream)
            lastChangeTime = Uint64LE.unpack(stream)
            endOfFilePosition = Uint64LE.unpack(stream)
            allocationSize = Uint64LE.unpack(stream)
            fileAttributes = FileAttributes(Uint32LE.unpack(stream))
            fileNameLength = Uint32LE.unpack(stream)
            eaSize = Uint32LE.unpack(stream)
            shortNameLength = Uint8.unpack(stream)
            # stream.read(1) # reserved (not actually used, WTF Microsoft ????)
            shortName = stream.read(24)[:min(24, shortNameLength)]
            fileName = stream.read(fileNameLength)

            if nextEntryOffset != 0:
                stream.read(8 - stream.tell() % 8)  # alignment
                break

            shortName = decodeUTF16LE(shortName)
            fileName = decodeUTF16LE(fileName)

            info = FileBothDirectoryInformation(fileIndex, creationTime,
                                                lastAccessTime, lastWriteTime,
                                                lastChangeTime,
                                                endOfFilePosition,
                                                allocationSize, fileAttributes,
                                                eaSize, shortName, fileName)

            information.append(info)

        return information
 def dealWithCreateResponse(self, pdu: DeviceIOResponsePDU,
                            requestPDU: DeviceCreateRequestPDU):
     """
     If its been created for reading, add the file to the list of opened files.
     """
     createResponse = self.deviceRedirectionParser.parseDeviceCreateResponse(
         pdu)
     self.pduToSend = createResponse
     if requestPDU.desiredAccess & (FileAccess.GENERIC_READ | FileAccess.FILE_READ_DATA) and \
        requestPDU.createOptions & CreateOption.FILE_NON_DIRECTORY_FILE != 0:
         self.mitm_log.info(
             "Opening file %(path)s as number %(number)d", {
                 "path": decodeUTF16LE(requestPDU.path),
                 "number": createResponse.fileId
             })
         self.openedFiles[createResponse.fileId] = requestPDU.path
Exemple #5
0
    def parseDirectoryControlRequest(self, deviceID: int, fileID: int, completionID: int, minorFunction: int, stream: BytesIO) -> DeviceIORequestPDU:
        self.minorFunctionsForParsingResponse[completionID] = MinorFunction(minorFunction)

        if minorFunction == MinorFunction.IRP_MN_NOTIFY_CHANGE_DIRECTORY:
            return DeviceIORequestPDU(deviceID, fileID, completionID, MajorFunction.IRP_MJ_DIRECTORY_CONTROL, minorFunction, stream.read())
        else:
            informationClass = FileSystemInformationClass(Uint32LE.unpack(stream))
            initialQuery = Uint8.unpack(stream)
            pathLength = Uint32LE.unpack(stream)
            stream.read(23)

            path = stream.read(pathLength)
            path = decodeUTF16LE(path)[: -1]

            self.informationClassForParsingResponse[completionID] = informationClass
            return DeviceQueryDirectoryRequestPDU(deviceID, fileID, completionID, informationClass, initialQuery, path)
Exemple #6
0
    def onClipboardData(self, pdu: PlayerPDU):
        parser = ClipboardParser()
        pdu = parser.parse(pdu.payload)

        if not isinstance(pdu, FormatDataResponsePDU):
            # TODO: Handle file PDUs.
            return

        data = decodeUTF16LE(pdu.requestedFormatData)
        self.json[JSON_KEY_EVENTS].append({
            "timestamp": self.timestamp,
            "type": "clipboard",
            "data": {
                "mime": "text/plain",
                "content": data
            },
        })
Exemple #7
0
    def parseDeviceCreateRequest(self, deviceID: int, fileID: int,
                                 completionID: int, minorFunction: int,
                                 stream: BytesIO) -> DeviceCreateRequestPDU:
        desiredAccess = Uint32LE.unpack(stream)
        allocationSize = Uint64LE.unpack(stream)
        fileAttributes = FileAttributes(Uint32LE.unpack(stream))
        sharedAccess = FileShareAccess(Uint32LE.unpack(stream))
        createDisposition = FileCreateDisposition(Uint32LE.unpack(stream))
        createOptions = FileCreateOptions(Uint32LE.unpack(stream))
        pathLength = Uint32LE.unpack(stream)
        path = stream.read(pathLength)

        path = decodeUTF16LE(path)[:-1]

        return DeviceCreateRequestPDU(deviceID, fileID, completionID,
                                      minorFunction, desiredAccess,
                                      allocationSize, fileAttributes,
                                      sharedAccess, createDisposition,
                                      createOptions, path)
Exemple #8
0
    def parseFileNamesInformation(self, data: bytes) -> List[FileNamesInformation]:
        stream = BytesIO(data)
        information: [FileNamesInformation] = []

        while stream.tell() < len(data):
            nextEntryOffset = Uint32LE.unpack(stream)
            fileIndex = Uint32LE.unpack(stream)
            fileNameLength = Uint32LE.unpack(stream)
            fileName = stream.read(fileNameLength)

            if nextEntryOffset != 0:
                stream.read(8 - stream.tell() % 8) # alignment
                break

            fileName = decodeUTF16LE(fileName)

            info = FileNamesInformation(fileIndex, fileName)
            information.append(info)

        return information
Exemple #9
0
    def parseFileFullDirectoryInformation(self, data: bytes) -> List[FileFullDirectoryInformation]:
        stream = BytesIO(data)
        information: [FileFullDirectoryInformation] = []

        while stream.tell() < len(data):
            nextEntryOffset = Uint32LE.unpack(stream)
            fileIndex = Uint32LE.unpack(stream)
            creationTime = Uint64LE.unpack(stream)
            lastAccessTime = Uint64LE.unpack(stream)
            lastWriteTime = Uint64LE.unpack(stream)
            lastChangeTime = Uint64LE.unpack(stream)
            endOfFilePosition = Uint64LE.unpack(stream)
            allocationSize = Uint64LE.unpack(stream)
            fileAttributes = FileAttributes(Uint32LE.unpack(stream))
            fileNameLength = Uint32LE.unpack(stream)
            eaSize = Uint32LE.unpack(stream)
            fileName = stream.read(fileNameLength)

            if nextEntryOffset != 0:
                stream.read(8 - stream.tell() % 8) # alignment
                break

            fileName = decodeUTF16LE(fileName)

            info = FileFullDirectoryInformation(
                fileIndex,
                creationTime,
                lastAccessTime,
                lastWriteTime,
                lastChangeTime,
                endOfFilePosition,
                allocationSize,
                fileAttributes,
                eaSize,
                fileName
            )

            information.append(info)

        return information
Exemple #10
0
    def onClientInfo(self, data: bytes):
        """
        Log the client connection information and replace the username and password if applicable.
        :param data: the client info data
        """
        pdu = ClientInfoParser().parse(data)

        clientAddress = None

        if pdu.extraInfo:
            clientAddress = decodeUTF16LE(pdu.extraInfo.clientAddress)

        self.log.info(
            "Client Info: username = %(username)r, password = %(password)r, domain = %(domain)r, clientAddress = %(clientAddress)r",
            {
                "username": pdu.username,
                "password": pdu.password,
                "domain": pdu.domain,
                "clientAddress": clientAddress
            })

        self.recorder.record(pdu, PlayerPDUType.CLIENT_INFO)

        # If set, replace the provided username and password to connect the user regardless of
        # the credentials they entered.
        if self.config.replacementUsername is not None:
            pdu.username = self.config.replacementUsername
        if self.config.replacementPassword is not None:
            pdu.password = self.config.replacementPassword

        if self.config.replacementUsername is not None and self.config.replacementPassword is not None:
            pdu.flags |= ClientInfoFlags.INFO_AUTOLOGON

        # Tell the server we don't want compression (unsure of the effectiveness of these flags)
        pdu.flags &= ~ClientInfoFlags.INFO_COMPRESSION
        pdu.flags &= ~ClientInfoFlags.INFO_CompressionTypeMask

        self.log.debug("Sending %(pdu)s", {"pdu": pdu})
        self.server.sendClientInfo(pdu)
Exemple #11
0
    def handleCreateResponse(self, request: DeviceCreateRequestPDU,
                             response: DeviceIOResponsePDU):
        """
        Prepare to intercept a file: create a FileProxy object, which will only create the file when we actually write
        to it. When listing a directory, Windows sends a lot of create requests without actually reading the files. We
        use a FileProxy object to avoid creating a lot of empty files whenever a directory is listed.
        :param request: the device create request
        :param response: the device IO response to the request
        """

        response = DeviceRedirectionParser().parseDeviceCreateResponse(
            response)

        isFileRead = request.desiredAccess & (FileAccess.GENERIC_READ
                                              | FileAccess.FILE_READ_DATA) != 0
        isNotDirectory = request.createOptions & CreateOption.FILE_NON_DIRECTORY_FILE != 0

        if isFileRead and isNotDirectory:
            remotePath = Path(decodeUTF16LE(request.path).rstrip("\x00"))
            mapping = FileMapping.generate(remotePath, self.config.fileDir)

            localPath = mapping.localPath
            self.openedFiles[response.fileID] = FileProxy(
                localPath, "wb", mapping, self.log)
Exemple #12
0
 def decodeClipboardData(self, data: bytes) -> str:
     """
     Decode clipboard bytes to a string.
     :param data: clipboard content bytes
     """
     return decodeUTF16LE(data)
Exemple #13
0
 def bytesToPath(self, pathAsBytes: bytes):
     """
     Converts a windows-encoded path to a beautiful, python-ready path.
     """
     return decodeUTF16LE(pathAsBytes).strip("\x00")