Пример #1
0
    def test_login_screen(self):
        """Test (de)compression of a login screen packet. The result is
        compared with data obtained from SAP GUI."""
        from pysapcompress import compress, decompress, ALG_LZH
        login_screen_compressed = read_data_file('nw_703_login_screen_compressed.data')
        login_screen_decompressed = read_data_file('nw_703_login_screen_decompressed.data')

        status, out_length, decompressed = decompress(login_screen_compressed, len(login_screen_decompressed))

        self.assertTrue(status)
        self.assertEqual(out_length, len(login_screen_decompressed))
        self.assertEqual(decompressed, login_screen_decompressed)

        status, out_length, compressed = compress(decompressed, ALG_LZH)

        self.assertTrue(status)
        self.assertEqual(out_length, len(login_screen_compressed))

        # As we can't compare with the compressed data (LZH randomness),
        # decompress again and check with the plain text

        status, out_length, decompressed = decompress(compressed, len(login_screen_decompressed))

        self.assertTrue(status)
        self.assertEqual(out_length, len(login_screen_decompressed))
        self.assertEqual(decompressed, login_screen_decompressed)
Пример #2
0
    def test_login(self):
        """Test (de)compression of a login packet. The result is
        compared with data obtained from SAP GUI."""
        from pysapcompress import compress, decompress, ALG_LZH
        login_compressed = read_data_file('sapgui_730_login_compressed.data')
        login_decompressed = read_data_file(
            'sapgui_730_login_decompressed.data')

        status, out_length, decompressed = decompress(login_compressed,
                                                      len(login_decompressed))

        self.assertTrue(status)
        self.assertEqual(out_length, len(login_decompressed))
        self.assertEqual(decompressed, login_decompressed)

        status, out_length, compressed = compress(decompressed, ALG_LZH)

        self.assertTrue(status)
        self.assertEqual(out_length, len(login_compressed))

        # As we can't compare with the compressed data (LZH randomness),
        # decompress again and check with the plain text

        status, out_length, decompressed = decompress(compressed,
                                                      len(login_decompressed))

        self.assertTrue(status)
        self.assertEqual(out_length, len(login_decompressed))
        self.assertEqual(decompressed, login_decompressed)
Пример #3
0
    def test_invalid_write(self):
        """Test invalid write vulnerability in LZC code (CVE-2015-2282)"""
        from pysapcompress import decompress, DecompressError

        test_case = read_data_file('invalid_write_testcase.data', False)

        try:
            decompress(test_case, 6716)
        except Exception as e:
            self.assertIsInstance(e, DecompressError)
Пример #4
0
    def test_invalid_read(self):
        """Test invalid read vulnerability in LZH code (CVE-2015-2278)"""
        from pysapcompress import decompress, DecompressError

        test_case = read_data_file('invalid_read_testcase.data', False)

        try:
            decompress(test_case, 661)
        except Exception as e:
            self.assertIsInstance(e, DecompressError)
            self.assertIn("bad hufman tree", str(e))
Пример #5
0
    def test_invalid_read(self):
        "Test invalid read vulnerability in LZH code (CVE-2015-2278)"
        from pysapcompress import decompress, DecompressError

        test_case = read_data_file('invalid_read_testcase.data', False)

        try:
            decompress(test_case, 661)
        except Exception as e:
            self.assertIsInstance(e, DecompressError)
            self.assertEqual(str(e), "Decompression error (bad hufman tree)")
Пример #6
0
    def extract(self, fd):
        """Extracts the archive file and writes the extracted file to the provided file object. Returns the checksum
        obtained from the archive. If blocks are uncompressed, the file is directly extracted. If the blocks are
        compressed, each block is added to a buffer, skipping the length field, and decompression is performed after
        the block marked as last. Expected length and compression header is obtained from the first block and checksum
        from the last block.

        :param fd: file-like object to write the extracted file to
        :type fd: file

        :return: checksum
        :rtype: int

        :raise DecompressError: If there's a decompression error
        :raise SAPCARInvalidFileException: If the file is invalid
        """

        if self.file_length == 0:
            return 0

        compressed = ""
        checksum = 0
        exp_length = None

        remaining_length = self.file_length
        for block in self.blocks:
            # Process uncompressed block types
            if block.type in [
                    SAPCAR_BLOCK_TYPE_UNCOMPRESSED,
                    SAPCAR_BLOCK_TYPE_UNCOMPRESSED_LAST
            ]:
                fd.write(block.compressed)
                remaining_length -= len(block.compressed)
            # Store compressed block types for later decompression
            elif block.type in [
                    SAPCAR_BLOCK_TYPE_COMPRESSED,
                    SAPCAR_BLOCK_TYPE_COMPRESSED_LAST
            ]:
                # Add compressed block to a buffer, skipping the first 4 bytes of each block (uncompressed length)
                compressed += str(block.compressed)[4:]
                # If the expected length wasn't already set, do it
                if not exp_length:
                    exp_length = block.compressed.uncompress_length
            else:
                raise SAPCARInvalidFileException("Invalid block type found")

            # Check last block, performing decompression if needed
            if sapcar_is_last_block(block):
                checksum = block.checksum
                # If there was at least one compressed block that set the expected length, decompress it
                if exp_length:
                    (_, block_length,
                     block_buffer) = decompress(str(compressed), exp_length)
                    if block_length != exp_length or not block_buffer:
                        raise DecompressError("Error decompressing block")
                    fd.write(block_buffer)
                break

        return checksum
Пример #7
0
    def test_lzh_decompress(self):
        """Test decompression using LZH algorithm"""
        from pysapcompress import decompress
        status, out_length_decompressed, out_decompressed = decompress(self.test_string_compr_lzh, len(self.test_string_plain))

        self.assertTrue(status)
        self.assertEqual(out_length_decompressed, len(out_decompressed))
        self.assertEqual(out_length_decompressed, len(self.test_string_plain))
        self.assertEqual(out_decompressed, self.test_string_plain)
Пример #8
0
    def test_lzh_decompress(self):
        """Test decompression using LZH algorithm"""
        from pysapcompress import decompress
        status, out_length_decompressed, out_decompressed = decompress(self.test_string_compr_lzh, len(self.test_string_plain))

        self.assertTrue(status)
        self.assertEqual(out_length_decompressed, len(out_decompressed))
        self.assertEqual(out_length_decompressed, len(self.test_string_plain))
        self.assertEqual(out_decompressed, self.test_string_plain)
Пример #9
0
    def test_decompres_output_lzh(self):
        """ Test decompress function output using LZH algorithm.
        """
        from pysapcompress import decompress
        status, out_length, out = decompress(self.test_string_compr_lzh, len(self.test_string_plain))

        self.assertTrue(status)
        self.assertEqual(out_length, len(out))
        self.assertEqual(out_length, len(self.test_string_plain))
        self.assertEqual(out, self.test_string_plain)
Пример #10
0
    def extract(self, fd):
        """Extracts the archive file and writes the extracted file to the provided file object. Returns the checksum
        obtained from the archive. If blocks are uncompressed, the file is directly extracted. If the blocks are
        compressed, each block is added to a buffer, skipping the length field, and decompression is performed after
        the block marked as end of data. Expected length and compression header is obtained from the first block and
        checksum from the end of data block.

        :param fd: file-like object to write the extracted file to
        :type fd: file

        :return: checksum
        :rtype: int

        :raise DecompressError: If there's a decompression error
        :raise SAPCARInvalidFileException: If the file is invalid
        """

        if self.file_length == 0:
            return 0

        compressed = ""
        checksum = 0
        exp_length = None

        remaining_length = self.file_length
        for block in self.blocks:
            # Process uncompressed block types
            if block.type in [SAPCAR_BLOCK_TYPE_UNCOMPRESSED, SAPCAR_BLOCK_TYPE_UNCOMPRESSED_LAST]:
                fd.write(block.compressed)
                remaining_length -= len(block.compressed)
            # Store compressed block types for later decompression
            elif block.type in [SAPCAR_BLOCK_TYPE_COMPRESSED, SAPCAR_BLOCK_TYPE_COMPRESSED_LAST]:
                # Add compressed block to a buffer, skipping the first 4 bytes of each block (uncompressed length)
                compressed += str(block.compressed)[4:]
                # If the expected length wasn't already set, do it
                if not exp_length:
                    exp_length = block.compressed.uncompress_length
            else:
                raise SAPCARInvalidFileException("Invalid block type found")

            # Check end of data block, performing decompression if needed
            if sapcar_is_last_block(block):
                checksum = block.checksum
                # If there was at least one compressed block that set the expected length, decompress it
                if exp_length:
                    (_, block_length, block_buffer) = decompress(str(compressed), exp_length)
                    if block_length != exp_length or not block_buffer:
                        raise DecompressError("Error decompressing block")
                    fd.write(block_buffer)
                break

        return checksum
Пример #11
0
    def extract(self, fd):
        """Extracts the archive file and writes the extracted file to the provided file object. Returns the checksum
        obtained from the archive. If blocks are uncompressed, the file is directly extracted. If the blocks are
        compressed, each block is decompressed independently. Checksum is obtained from the last block.

        :param fd: file-like object to write the extracted file to
        :type fd: file

        :return: checksum
        :rtype: int

        :raise DecompressError: If there's a decompression error
        :raise SAPCARInvalidFileException: If the file is invalid
        """
        if self.file_length == 0:
            return 0

        checksum = 0

        remaining_length = self.file_length
        for block in self.blocks:
            # Process uncompressed block types
            if block.type in [
                    SAPCAR_BLOCK_TYPE_UNCOMPRESSED,
                    SAPCAR_BLOCK_TYPE_UNCOMPRESSED_LAST
            ]:
                fd.write(block.compressed)
                remaining_length -= len(block.compressed)
            # Process compressed block types
            elif block.type in [
                    SAPCAR_BLOCK_TYPE_COMPRESSED,
                    SAPCAR_BLOCK_TYPE_COMPRESSED_LAST
            ]:
                compressed = block.compressed
                exp_block_length = compressed.uncompress_length
                (_, block_length, block_buffer) = decompress(
                    str(compressed)[4:], exp_block_length)
                if block_length != exp_block_length or not block_buffer:
                    raise DecompressError("Error decompressing block")
                fd.write(block_buffer)
                remaining_length -= block_length
            else:
                raise SAPCARInvalidFileException("Invalid block type found")

            # Check last block
            if sapcar_is_last_block(block):
                checksum = block.checksum
                break

        return checksum
Пример #12
0
    def test_decompress_login(self):
        """ Test decompression of a login packet. The result is
        compared with decompressed data obtained from SAP GUI.

        """
        from pysapcompress import decompress
        login_compressed = read_data_file('sapgui_730_login_compressed.data')
        login_decompressed = read_data_file('sapgui_730_login_decompressed.data')

        status, out_length, decompressed = decompress(login_compressed, len(login_decompressed))

        self.assertTrue(status)
        self.assertEqual(out_length, len(login_decompressed))
        self.assertEqual(decompressed, login_decompressed)
Пример #13
0
    def test_lzc(self):
        """Test compression and decompression using LZC algorithm"""
        from pysapcompress import compress, decompress, ALG_LZC
        status, out_length_compressed, out_compressed = compress(self.test_string_plain, ALG_LZC)

        self.assertTrue(status)
        self.assertEqual(out_length_compressed, len(out_compressed))
        self.assertEqual(out_length_compressed, len(self.test_string_compr_lzc))
        self.assertEqual(out_compressed, self.test_string_compr_lzc)

        status, out_length_decompressed, out_decompressed = decompress(out_compressed, len(self.test_string_plain))

        self.assertTrue(status)
        self.assertEqual(out_length_decompressed, len(out_decompressed))
        self.assertEqual(out_length_decompressed, len(self.test_string_plain))
        self.assertEqual(out_decompressed, self.test_string_plain)
Пример #14
0
    def test_lzc(self):
        """Test compression and decompression using LZC algorithm"""
        from pysapcompress import compress, decompress, ALG_LZC
        status, out_length_compressed, out_compressed = compress(self.test_string_plain, ALG_LZC)

        self.assertTrue(status)
        self.assertEqual(out_length_compressed, len(out_compressed))
        self.assertEqual(out_length_compressed, len(self.test_string_compr_lzc))
        self.assertEqual(out_compressed, self.test_string_compr_lzc)

        status, out_length_decompressed, out_decompressed = decompress(out_compressed, len(self.test_string_plain))

        self.assertTrue(status)
        self.assertEqual(out_length_decompressed, len(out_decompressed))
        self.assertEqual(out_length_decompressed, len(self.test_string_plain))
        self.assertEqual(out_decompressed, self.test_string_plain)
Пример #15
0
    def test_lzh(self):
        """Test compression and decompression using LZH algorithm"""
        from pysapcompress import compress, decompress, ALG_LZH
        status, out_length_compressed, out_compressed = compress(self.test_string_plain, ALG_LZH)

        self.assertTrue(status)
        self.assertEqual(out_length_compressed, len(out_compressed))
        # LZH compression has a random component, so the only check here is
        # in regards to the length and to see if if decompress back to the
        # original string

        status, out_length_decompressed, out_decompressed = decompress(out_compressed, len(self.test_string_plain))

        self.assertTrue(status)
        self.assertEqual(out_length_decompressed, len(out_decompressed))
        self.assertEqual(out_length_decompressed, len(self.test_string_plain))
        self.assertEqual(out_decompressed, self.test_string_plain)
Пример #16
0
    def test_lzh(self):
        """Test compression and decompression using LZH algorithm"""
        from pysapcompress import compress, decompress, ALG_LZH
        status, out_length_compressed, out_compressed = compress(self.test_string_plain, ALG_LZH)

        self.assertTrue(status)
        self.assertEqual(out_length_compressed, len(out_compressed))
        # LZH compression has a random component, so the only check here is
        # in regards to the length and to see if if decompress back to the
        # original string

        status, out_length_decompressed, out_decompressed = decompress(out_compressed, len(self.test_string_plain))

        self.assertTrue(status)
        self.assertEqual(out_length_decompressed, len(out_decompressed))
        self.assertEqual(out_length_decompressed, len(self.test_string_plain))
        self.assertEqual(out_decompressed, self.test_string_plain)
Пример #17
0
    def open(self):
        """Opens the compressed file and returns a file-like object that
        can be used to access its uncompressed content.

        :return: file-like object with the uncompressed file content
        :rtype: file
        """
        if not self._file_format.type == SAPCAR_TYPE_FILE:
            raise Exception("Invalid file type")

        out_buffer = ""
        if self._file_format.file_length != 0:
            compressed = self._file_format.compressed
            exp_length = self._file_format.file_length
            (_, out_length, out_buffer) = decompress(str(compressed)[4:], exp_length)
            if out_length != exp_length or not out_buffer:
                raise DecompressError("Decompression error")
        return StringIO(out_buffer)
Пример #18
0
    def do_decompress(self, s, length):
        """Decompress a string using SAP compression C++ extension.

        :param s: compression header plus compressed string
        :type s: C{string}

        :param length: reported compressed length
        :type length: ``int``

        :return: decompressed string
        :rtype: C{string}

        :raise pysapcompress.Error: when a decompression error is raised
        """
        if len(s) > 0:
            # Decompress the payload and return the output
            (_, _, outbuffer) = pysapcompress.decompress(s, length)
            return outbuffer
Пример #19
0
    def do_decompress(self, s, length):
        """Decompress a string using SAP compression C++ extension.

        :param s: compression header plus compressed string
        :type s: C{string}

        :param length: reported compressed length
        :type length: ``int``

        :return: decompressed string
        :rtype: C{string}

        :raise pysapcompress.Error: when a decompression error is raised
        """
        if len(s) > 0:
            # Decompress the payload and return the output
            (_, _, outbuffer) = pysapcompress.decompress(s, length)
            return outbuffer
Пример #20
0
    def open(self):
        """Opens the compressed file and returns a file-like object that
        can be used to access its uncompressed content.

        :return: file-like object with the uncompressed file content
        :rtype: file
        """
        if not self._file_format.type == SAPCAR_TYPE_FILE:
            raise Exception("Invalid file type")

        out_buffer = ""
        if self._file_format.file_length != 0:
            compressed = self._file_format.compressed
            exp_length = self._file_format.file_length
            (_, out_length,
             out_buffer) = decompress(str(compressed)[4:], exp_length)
            if out_length != exp_length or not out_buffer:
                raise DecompressError("Decompression error")
        return StringIO(out_buffer)
Пример #21
0
    def extract(self, fd):
        """Extracts the archive file and writes the extracted file to the provided file object. Returns the checksum
        obtained from the archive. If blocks are uncompressed, the file is directly extracted. If the blocks are
        compressed, each block is decompressed independently. Checksum is obtained from the last block.

        :param fd: file-like object to write the extracted file to
        :type fd: file

        :return: checksum
        :rtype: int

        :raise DecompressError: If there's a decompression error
        :raise SAPCARInvalidFileException: If the file is invalid
        """
        if self.file_length == 0:
            return 0

        checksum = 0

        remaining_length = self.file_length
        for block in self.blocks:
            # Process uncompressed block types
            if block.type in [SAPCAR_BLOCK_TYPE_UNCOMPRESSED, SAPCAR_BLOCK_TYPE_UNCOMPRESSED_LAST]:
                fd.write(block.compressed)
                remaining_length -= len(block.compressed)
            # Process compressed block types
            elif block.type in [SAPCAR_BLOCK_TYPE_COMPRESSED, SAPCAR_BLOCK_TYPE_COMPRESSED_LAST]:
                compressed = block.compressed
                exp_block_length = compressed.uncompress_length
                (_, block_length, block_buffer) = decompress(str(compressed)[4:], exp_block_length)
                if block_length != exp_block_length or not block_buffer:
                    raise DecompressError("Error decompressing block")
                fd.write(block_buffer)
                remaining_length -= block_length
            else:
                raise SAPCARInvalidFileException("Invalid block type found")

            # Check last block
            if sapcar_is_last_block(block):
                checksum = block.checksum
                break

        return checksum