Back to writeups
FlagYardforensicsMediumsolved

ZoomHeist

12 Jul 2026 · by 0xIDA

Solvers

ZoomHeist

Author: 0xIDA
Platform: FlagYard · Category: forensics · Difficulty: Medium

Solvers

Summary

Windows user-profile triage of a Zoom malvertising victim. Firefox history shows a visit to a GitHub Pages clone (flagyardctf.github.io) that spoofed Zoom; the fake site’s flag.js was recovered from Firefox cache2 (gzip body), decoded Base64 → ROT15 → flag.

Solution

Step 1: Browser history

Edge history only showed a Firefox installer download. Firefox places.sqlite:

https://www.google.com/search?...q=zoom
http://flagyardctf.github.io/
https://flagyardctf.github.io/   title: "One platform to connect | Zoom"
https://zoom.us/syncStatus?...
https://www.zoom.com/?lang=null

Live site is now 404; recover from local cache.

Step 2: Recover flag.js from Firefox cache2

Path under the triage zip:

C/Users/FlagYard/AppData/Local/Mozilla/Firefox/Profiles/q4ox2osp.default-release/cache2/entries/...

Entry metadata contains:

:https://flagyardctf.github.io/flag.js

Body is gzip. Decompress up to metadata (O^partitionKey...):

import zlib
data = open("cache_entry","rb").read()
meta = data.find(b"O^partitionKey")
js = zlib.decompress(data[:meta], 31)  # gzip
print(js.decode())

Step 3: Decode payload

flag.js is a helper script with embedded Base64:

QmluZ28KRWNvZGluZzogUk9UMTUKRW5jb2RlZCBGbGFnOiBVYXB2Tns5MXJzODI0NzB0OTIwOTkzc3U3dDdwcXUzOTQ3NTVyOX0=
import base64, re
decoded = base64.b64decode(b64).decode()
# Bingo
# Ecoding: ROT15
# Encoded Flag: UapvN{91rs82470t920993su7t7pqu394755r9}

def rotN(text, shift):
    out = []
    for ch in text:
        if "a" <= ch <= "z":
            out.append(chr((ord(ch) - 97 - shift) % 26 + 97))
        elif "A" <= ch <= "Z":
            out.append(chr((ord(ch) - 65 - shift) % 26 + 65))
        else:
            out.append(ch)
    return "".join(out)

flag = rotN("UapvN{91rs82470t920993su7t7pqu394755r9}", 15)
# FlagY{91cd82470e920993df7e7abf394755c9}

Flag

FlagY{91cd82470e920993df7e7abf394755c9}

Live submit: success.

Tools

  • unzip -l selective extract
  • SQLite on places.sqlite / Edge History
  • Python zlib/gzip for cache2 body
  • Base64 + ROT15

Pitfalls

  • Malicious GitHub Pages may be offline — cache is authoritative
  • Firefox cache2 = gzip data + trailing metadata (O^partitionKey, certs); do not feed full file to gzip
  • Flag is not a raw FlagY{ string in the zip; encoding layers are intentional