Security Footage
Perform digital forensics on a network capture to recover footage from a camera. - ben, timtaylor and congon4tor
The following post by 0xb0b is licensed under CC BY 4.0
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.

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

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


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.


Next, we write a script to recover each frame, each JPEG, by extracting the data between FFD8 and FFD9.
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}/'")
We run the script and are able to recover arround 500 frames.
python3 recover_frames.py

We can now inspect each frame to see the flag.

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.
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/'")
We run the script and are able to recover the footage.
python3 compilegif.py

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

Last updated
Was this helpful?