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 -lselective extract- SQLite on
places.sqlite/ EdgeHistory - Python
zlib/gzipfor 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