> For the complete documentation index, see [llms.txt](https://sarpers-organization.gitbook.io/ctftricks/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://sarpers-organization.gitbook.io/ctftricks/_chapter-intro-5/file-analysis/embedded-data-extraction/trick-0412.md).

# File Stream Extraction (Zlib/Gunzip) & Polyglot Analysis

***

Analyze files for hidden compressed data streams, such as zlib or gzip, often found embedded within other file types. This is particularly relevant in forensic challenges or when dealing with polyglot files where data might be hidden in sections ignored by some parsers.

Use a forensic tool like Cyberchef. Upload the suspicious file and look for operations specifically designed to find and extract hidden streams. In Cyberchef, the relevant operation is often `Extract streams`. Select the appropriate decompression algorithm, commonly `zlib` or `gzip`, within the operation options to automatically process any identified compressed data streams. Any extracted data will appear in the output pane.

Alternatively, programmatic approaches can be used to decompress zlib or gzip data found within a file. For example, the Python `zlib` module provides functions for decompressing data. The `decompress` function can be used to decompress a compressed string.

```python
zlib.decompress(string[, wbits[, bufsize]])
```

This function decompresses the `string`. The optional `wbits` parameter controls the size of the history buffer (window size) and whether a gzip or zlib header is expected. The optional `bufsize` parameter is the initial size of the output buffer. If `wbits` is omitted, its default value is 15. If `string` contains concatenated compressed streams, multiple calls to the `decompress` function will be needed to decompress all streams.

A common use case is decompressing a zlib compressed byte sequence:

```python
import zlib

compressed_data = b'x\x9c\xcbH\xcd\xc9\xc9W(\xcf/\xcaIQ\x04\x00\x1c\x0e\x01\xa6'
decompressed_data = zlib.decompress(compressed_data)
print(decompressed_data)
```

For data compressed with a gzip header, the `wbits` parameter needs to be adjusted. A positive `wbits` value (typically 15) indicates a zlib stream, while a negative value (-15) indicates a raw deflate stream without headers. Adding 16 to `wbits` (e.g., 15 + 16 = 31) tells the decompressor to expect a gzip header.

```python
import zlib

# Example of data compressed with gzip
gzip_compressed_data = b'\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff\xcbH\xcd\xc9\xc9W(\xcf/\xcaIQ\x04\x00\x1c\x0e\x01\xa6'
decompressed_data = zlib.decompress(gzip_compressed_data, 16 + zlib.MAX_WBITS)
print(decompressed_data)
```

The `MAX_WBITS` constant represents the default window size (15). Adding 16 enables gzip decompression.

Another function, `zlib.decompressobj`, creates a decompression object which can be useful for decompressing data incrementally or when dealing with concatenated streams.

```python
zlib.decompressobj([wbits])
```

Returns a decompression object, to be used in decompressing data incrementally. The `wbits` parameter is as for `decompress()`.

Using `decompressobj` allows processing data in chunks:

```python
import zlib

decompressor = zlib.decompressobj(16 + zlib.MAX_WBITS) # For gzip
output = decompressor.decompress(chunk1)
output += decompressor.decompress(chunk2)
output += decompressor.flush() # Get any remaining decompressed data
```

These programmatic methods provide flexibility for integrating stream analysis into custom scripts or larger forensic workflows, allowing for automated scanning and extraction of compressed data hidden within various file formats.
