> For the complete documentation index, see [llms.txt](https://0xb0b.gitbook.io/writeups/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://0xb0b.gitbook.io/writeups/tryhackme/2025/security-footage.md).

# Security Footage

{% embed url="<https://tryhackme.com/room/securityfootage>" %}

The following post by 0xb0b is licensed under [CC BY 4.0<img src="https://mirrors.creativecommons.org/presskit/icons/cc.svg?ref=chooser-v1" alt="" data-size="line"><img src="https://mirrors.creativecommons.org/presskit/icons/by.svg?ref=chooser-v1" alt="" data-size="line">](http://creativecommons.org/licenses/by/4.0/?ref=chooser-v1)

***

Security Footage is a PCAP challenge in which our task is to recover video footage of a camera from the traffice network. We see a Get request in the traffic, followed by TCP traffic, containing the footage. The streamed object cannot be extracted directly via wireshark.

<figure><img src="/files/pW4KqkvXzB6LXvAdTtQh" alt=""><figcaption></figcaption></figure>

We follow the TCP traffic and see that image data is being transferred. They are individual JFIF or JPEG images.

<figure><img src="/files/H78Pol2p6wAqbQmx4yRp" alt=""><figcaption></figcaption></figure>

If we look at the hexdump, we see that they start with `FFD8` and end with `FFD9`.

<figure><img src="/files/QQnvZAXuRkNgh7TBsI7E" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/fPIwAiIJ0tpD81nhZNdC" alt=""><figcaption></figcaption></figure>

With this information, we should be able to extract the individual images. Here we save the raw data directly so that we can process it.

<figure><img src="/files/CRvs64CQ19EjF2nNSi67" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/huEd2Hu3uIgbS6hxlgD7" alt=""><figcaption></figcaption></figure>

Next, we write a script to recover each frame, each JPEG, by extracting the data between FFD8 and FFD9.

{% code title="recover\_frames.py" overflow="wrap" lineNumbers="true" %}

```python
import os
import re
from pathlib import Path

# Create output directory
output_dir = Path("frames")
output_dir.mkdir(exist_ok=True)

# Read the raw file
with open("raw", "r") as f:
    data = f.read().lower()  # lowercase for consistency with regex

# Extract all JPEG hex strings (FFD8...FFD9)
pattern = re.compile(r'ffd8.*?ffd9', re.DOTALL)
matches = pattern.findall(data)

print(f"[+] Found {len(matches)} JPEG(s).")

# Decode and save each one
for i, hex_str in enumerate(matches):
    try:
        img_data = bytes.fromhex(hex_str)
        with open(output_dir / f"image_{i:03}.jpg", "wb") as img_file:
            img_file.write(img_data)
    except Exception as e:
        print(f"[-] Failed to write image {i}: {e}")

print(f"[+] Images saved to '{output_dir}/'")

```

{% endcode %}

We run the script and are able to recover arround 500 frames.

```
python3 recover_frames.py
```

<figure><img src="/files/NMt8ABzlduzasJIB1IyJ" alt=""><figcaption></figcaption></figure>

We can now inspect each frame to see the flag.

<figure><img src="/files/z5IbUpXQZAGmuCtlDThu" alt=""><figcaption></figcaption></figure>

But we also could recover the video footage by crafting a GIF with the following script. We skip some frames and set the duration to 100ms.&#x20;

{% code title="compilegif.py" overflow="wrap" lineNumbers="true" %}

```python
from PIL import Image
from pathlib import Path

# Folder with extracted JPGs
input_dir = Path("frames")
output_gif = "compiled.gif"

# Skip every N images
frame_step = 5  # adjust this to skip more or fewer frames
duration = 100  # ms per frame (make smaller = faster)

# Load every Nth .jpg image
image_paths = sorted(input_dir.glob("*.jpg"))[::frame_step]
images = [Image.open(img_path).convert("RGB") for img_path in image_paths]

if images:
    images[0].save(
        output_gif,
        save_all=True,
        append_images=images[1:],
        duration=duration,
        loop=0
    )
    print(f"[+] GIF saved as '{output_gif}' with {len(images)} frames")
else:
    print("[-] No JPEG images found in 'frames/'")

```

{% endcode %}

We run the script and are able to recover the footage.

```
python3 compilegif.py
```

<figure><img src="/files/l6FGsXCl4Lg1rqszFQtx" alt=""><figcaption></figcaption></figure>

We recovered the GIF and are able to extract the flag visually. The following GIF is just an excerpt.

<div data-full-width="false"><figure><img src="/files/085eVu1qWOsMyKJGr5m7" alt=""><figcaption></figcaption></figure></div>
