C:\CTF\K17\PHOTO_LEAK.EXE _□X

PHOTO LEAK

forensics

Challenge

Given reference photo sets from two different cameras (A and B) and a batch of unlabeled query photos, determine which camera took each query — with no metadata to lean on. Every digital camera sensor leaves a faint, consistent noise fingerprint (photo-response non-uniformity, PRNU) on everything it shoots, so the fix is to build each camera's fingerprint from its known references and correlate the queries against both.

Solution

For every reference image, Wiener-filter it to get a denoised version and subtract to get the noise residual, then zero-mean it row-wise and column-wise to strip out sensor-independent structure. Average the residuals across each camera's reference set to get that camera's fingerprint:

def get_residual(img_path):
    img = cv2.imread(str(img_path), cv2.IMREAD_GRAYSCALE).astype(np.float32)
    denoised = wiener(img, (3, 3))
    return zero_mean_total(img - denoised)

fp_A = average of get_residual(p) for p in reference/A
fp_B = average of get_residual(p) for p in reference/B

Then, for each query image, compute its own residual and correlate it against both fingerprints — whichever camera's fingerprint correlates higher is the answer:

for q in queries:
    r = get_residual(q)
    corr_A = np.corrcoef(r.flatten(), fp_A.flatten())[0, 1]
    corr_B = np.corrcoef(r.flatten(), fp_B.flatten())[0, 1]
    ans = 'A' if corr_A > corr_B else 'B'

Concatenating the per-query answers in order spells out the flag.