← Back to Writeups
CUSTOMEasyCrypto

Lemur XOR

XESXOR9/2/20262 min read
#crypto#custom#easy#pixel_wise_image_xor#xor_key_reuse_cancellation

Lemur XOR

Platform: CUSTOM | Category: Crypto | Type: Challenge | Difficulty: Easy | OS: N/A | **Author: XESXOR Techniques: pixel_wise_image_xor, xor_key_reuse_cancellation

Summary

Walkthrough of the CUSTOM Crypto Lemur XOR. Task: two PNG images each XORed with the SAME secret key; recover the hidden flag. Solution: XOR the two ciphertext images pixel-by-pixel on decoded RGB data so the reused key cancels, revealing the f

Description

I've hidden two cool images by XOR with the same secret key so you can't see them!

Note: This challenge requires performing a visual XOR between the RGB bytes of the two images - not an XOR of all the data bytes of the files.

Two 582x327 RGB PNG images (lemur.png and flag.png) are provided. Each was encrypted by XORing its pixels with the same secret key image. The goal is to recover the hidden flag.

Analysis

This is a classic one-time-pad key reuse failure applied to images. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

If the same key K is used to encrypt two plaintexts A and B:

C1 = A ^ K
C2 = B ^ K
C1 ^ C2 = (A ^ K) ^ (B ^ K) = A ^ B

XORing the two ciphertexts cancels the key entirely, leaving A ^ B — the XOR of the two original images. Because one plaintext is the Lemur picture and the other contains the flag text, the combined image visually renders the flag overlaid on the Lemur.

The critical implementation detail from the challenge note: PNG is a compressed container. XORing the raw file bytes is meaningless because the DEFLATE-compressed streams do not align. You must decode each PNG to its raw RGB pixel array first, then XOR pixel-by-pixel. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Solution

Decode both PNGs to RGB arrays and XOR them element-wise:

python
#!/usr/bin/env python3
from PIL import Image
import numpy as np

a = np.array(Image.open("lemur.png").convert("RGB"))
b = np.array(Image.open("flag.png").convert("RGB"))
Image.fromarray(a ^ b).save("xor_result.png")

Opening xor_result.png shows the flag text crypto{REDACTED} rendered over the famous Lemur image (conceptually identical to the AES-ECB penguin: image structure survives a broken cipher). ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Key Takeaways / Lessons

  • Mastering pixel_wise_image_xor, xor_key_reuse_cancellation was key to this challenge.
  • Always check for common misconfigurations and verify assumptions.

Crafted by XESXOR Research • 2026-06-21 • CUSTOM • Lemur XOR • Difficulty: Easy