with one click
ctf-osint
// OSINT for CTF: social media tracking (X/Tumblr/BlueSky/Discord), username enumeration, reverse image search, geolocation (EXIF/MGRS/Plus Codes/What3Words), DNS/WHOIS, Wayback, FEC/Tor/GitHub mining.
// OSINT for CTF: social media tracking (X/Tumblr/BlueSky/Discord), username enumeration, reverse image search, geolocation (EXIF/MGRS/Plus Codes/What3Words), DNS/WHOIS, Wayback, FEC/Tor/GitHub mining.
[HINT] Download the complete skill directory including SKILL.md and all related files
| name | ctf-osint |
| description | OSINT for CTF: social media tracking (X/Tumblr/BlueSky/Discord), username enumeration, reverse image search, geolocation (EXIF/MGRS/Plus Codes/What3Words), DNS/WHOIS, Wayback, FEC/Tor/GitHub mining. |
Quick reference for OSINT CTF challenges. Each technique has a one-liner here; see supporting files for full details.
Dispatch on the kind of clue in the prompt/image, not on the story.
| Signal | Technique → file |
|---|---|
| Only a username / handle given | Username OSINT (namechk, whatsmyname, Osint Industries) → social-media.md |
| Twitter/X profile URL, numeric user ID, or snowflake-looking timestamp | Snowflake decode + Nitter + memory.lol → social-media.md |
| Tumblr blog name, Mastodon/BlueSky handle | Platform-specific JSON/API lookups → social-media.md |
| Unicode-rich post text (Cyrillic or mathematical letters in ASCII-looking words) | Homoglyph steganography → social-media.md |
| Image with distinct building, sign, mountain, or road layout | Reverse image + Google Lens / Baidu → geolocation-and-media.md |
| Railroad/road sign text, mileage markers, regional infrastructure | Geolocation via infrastructure maps + MGRS → geolocation-and-media.md |
WxYyyy style or three-random-words string | Google Plus Codes / What3Words → geolocation-and-media.md |
| EXIF present with GPS / camera serial | ExifTool + metadata chain → geolocation-and-media.md |
| Target is a domain / host IP | WHOIS + reverse DNS + ASN → web-and-dns.md |
Tor .onion address or relay fingerprint | Tor relay lookups + Wayback of hidden services → web-and-dns.md |
| GitHub org/user URL, or leaked GitHub token | GitHub repo analysis + commit mining → web-and-dns.md |
| FEC / SEC / public-record style clue (US political or financial) | FEC research → web-and-dns.md |
| Cryptocurrency address + transaction context | On-chain tx tracing → (see ctf-forensics/disk-and-memory.md cross-ref) |
| Strava / fitness route image | Route OSINT via Strava heatmap → social-media.md |
Recognize the kind of artefact; don't chase the story's names.
For inline snippets and quick-reference tables, see quickref.md. The Pattern Recognition Index above is the dispatch table — always consult it first.
graph.baidu.com (best for Chinese locations — use when visual cues suggest China: blue license plates, simplified Chinese text, menlou gate architecture)Pattern (On The Grid): Encoded coordinates like "4V FH 246 677".
Identification: Challenge title mentions "grid", code format matches MGRS pattern.
Conversion: Use online MGRS converter -> lat/long -> Google Maps for location name.
Pattern (Chine Zhao): Flag format requires a Google Plus Code (e.g., H9G2+47X) instead of coordinates or W3W. Plus Codes are Google's open-source alternative to street addresses.
Format: XXXX+XX (short/local) or 8FVC9G8F+6W (full/global). Characters from the set 23456789CFGHJMPQRVWX. The + separator is always present.
Generating a Plus Code:
H9G2+47X Handan, Hebei, China)Precision: Standard Plus Codes resolve to ~14m x 14m areas (vs. W3W's 3m x 3m). Adding extra characters increases precision. Meter-level position changes can alter the code.
Key insight: Unlike W3W (proprietary, requires API key), Plus Codes are free and built into Google Maps. When a flag format shows {XXXX+XXX}, recognize it as a Plus Code. Position the Street View camera at the exact photo capture location, then read the Plus Code from the map pin.
Reference: https://maps.google.com/pluscodes/
exiftool image.jpg # EXIF data
pdfinfo document.pdf # PDF metadata
mediainfo video.mp4 # Video metadata
Pattern (Computneter, VuwCTF 2025): Battery specifications -> manufacturer identification. Cross-reference specs (voltage, capacity, form factor) with manufacturer databases.
Pattern (It's News, VuwCTF 2025): Combine newspaper archive date search with EXIF GPS coordinates for location-specific identification.
Tools: Library of Congress newspaper archive, Google Maps for GPS coordinate lookup.
Pattern (amnothappyanymore): Challenge image is a cropped section of a Google Street View panorama. Must identify the exact panorama ID and coordinates.
Approach:
import cv2
import numpy as np
# Load challenge image and candidate panorama
challenge = cv2.imread('challenge.jpg')
candidate = cv2.imread('panorama.jpg')
# ORB feature detection and matching
orb = cv2.ORB_create(nfeatures=5000)
kp1, des1 = orb.detectAndCompute(challenge, None)
kp2, des2 = orb.detectAndCompute(candidate, None)
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
matches = bf.match(des1, des2)
score = sum(1 for m in matches if m.distance < 50)
lat/lng/sessionId/nonce)Google Street View API patterns:
# Street View metadata API (check if coverage exists)
# GET https://maps.googleapis.com/maps/api/streetview/metadata?location=LAT,LNG&key=KEY
# Street View image API
# GET https://maps.googleapis.com/maps/api/streetview?size=640x480&location=LAT,LNG&heading=90&key=KEY
# Panorama ID from page source (parsed from JavaScript):
# Look for panoId in page data structures
Key insights:
Pattern (date_spot): Street view image of a coastal location. Identify exact coordinates from road infrastructure.
Systematic approach:
Japanese infrastructure clues:
General country identification shortcuts:
| Feature | Country/Region |
|---|---|
| Kanji + blue highway signs | Japan |
| Cyrillic + wide boulevards | Russia/CIS |
| White X-shape crossing signs | Canada |
| Yellow diamond warning signs | USA/Canada |
| Green autobahn signs | Germany |
| Brown tourist signs | France |
| Bollards with red reflectors | Netherlands |
Pattern (idinahui): Coastal parking lot image. Identify location from architectural style, vehicle types, signage, and local brands.
Recognition chain:
Key technique — restaurant/brand geolocation:
Post-Soviet visual markers:
Free geolocation services:
# IP-API (no key required)
curl "http://ip-api.com/json/103.150.68.150"
# ipinfo.io
curl "https://ipinfo.io/103.150.68.150/json"
Bangladesh IP ranges (common in KCTF):
103.150.x.x - Bangladesh ISPsCorrelating location with evidence:
CIP fieldPattern (W3W1/W3W2): Challenge image contains multiple elements but only one is useful for identification. Crop to just the relevant portion before searching.
Technique:
lens.google.com or right-click → "Search image with Google Lens" in Chrome)When to crop:
Key insight: Google Lens performs significantly better on cropped regions than full scene images. A full scene may return generic landscape results, while a cropped shop sign returns the exact business with its address.
Example workflow (W3W2):
Pattern (W3W3): Text visible in the image is reflected/mirrored (e.g., sign reflected in water or glass). Must read the text in reverse to identify the location.
Technique:
"Aguas de Lind" → find "Aguas de Lindoia"Partial text search strategies:
# Search with wildcards/partial terms
"Aguas de Lind" # Quoted partial match
"Aguas de Lind" city # Add context keyword
"Aguas de Lind*" brazil # Add country if identifiable from image
Image flipping for reflected text:
# Flip image horizontally with ImageMagick
convert input.jpg -flop flipped.jpg
# Or with Python/PIL
python3 -c "
from PIL import Image
img = Image.open('input.jpg')
img.transpose(Image.FLIP_LEFT_RIGHT).save('flipped.jpg')
"
Key insight: When a letter in reflected text is ambiguous (e.g., "T" vs "I"), try both variants as separate searches. Partial text searches with quoted strings are effective for identifying place names even with only 60-70% of the text readable.
Pattern (W3W1/W3W2/W3W3): Photo of a location. Find the exact What3Words address (3-meter precision grid). Flag format: utflag{word1.word2.word3}.
What3Words basics:
Workflow:
Coordinate-to-W3W conversion:
# Navigate to what3words.com and enter coordinates:
# Format: latitude, longitude (e.g., 30.2870, -97.7415)
# Or click on the map at the exact location
# The W3W API requires an API key (not always available in CTF):
# GET https://api.what3words.com/v3/convert-to-3wa?coordinates=30.2870,-97.7415&key=API_KEY
Common pitfalls:
Tips for accurate pinpointing:
Pattern (W3W3): Photo of large 3D letters spelling a city/location name, often reflected in a pool of water. Common in Latin American cities as tourist landmarks.
Identification clues:
Search strategy:
"letras monumentales" [city name] or "letreiro turístico" [city]tourism=attraction near the city center[city name] sign or [city name] letters and check photosKey insight: These monumental letter installations ("letras monumentales" in Spanish, "letreiro turístico" in Portuguese) are extremely common in Latin American cities. The exact GPS coordinates of the installation can be found on OpenStreetMap or Google Maps photo pins.
Pattern (Where was Chine): Verify a candidate location by matching a challenge image against user-submitted Google Maps photos for that place.
Workflow:
When to use: After narrowing to a candidate location through non-visual OSINT (fitness routes, addresses, social connections), use Google Maps photos as final visual confirmation. Especially useful for parks, plazas, and landmarks where many tourists upload photos.
Key insight: Google Maps aggregates crowd-sourced photos tagged to specific locations. Even when reverse image search fails (because the challenge image is original, not scraped), the same physical scene appears in tourist photos. Search by place name, not by image.
Pattern (Portrait robot): Find a specific business (newsagent) near a metro entrance in a known city. Overpass Turbo queries OpenStreetMap data to locate POIs by type within a radius of other POIs.
Tool: https://overpass-turbo.eu/
Example — find newsagents within 10m of metro entrances in Barcelona:
[out:json][timeout:25];
{{geocodeArea:Barcelona}}->.searchArea;
(
node["railway"="subway_entrance"](area.searchArea);
)->.metros;
(
node(around.metros:10)["shop"~"newsagent|kiosk"];
way(around.metros:10)["shop"~"newsagent|kiosk"];
);
out body;
>;
out skel qt;
Common query patterns for OSINT:
# All cafes near train stations in a city
{{geocodeArea:CityName}}->.a;
node["railway"="station"](area.a)->.stations;
node(around.stations:50)["amenity"="cafe"];
# All ATMs in a neighborhood
node["amenity"="atm"]({{bbox}});
# Hotels near a specific coordinate (lat,lon)
node(around:200,48.8566,2.3522)["tourism"="hotel"];
Key OSM tags for OSINT challenges:
| Tag | Values |
|---|---|
shop | newsagent, kiosk, bakery, supermarket |
amenity | cafe, restaurant, bank, atm, pharmacy |
tourism | hotel, attraction, museum, viewpoint |
railway | station, subway_entrance, halt |
Key insight: When a challenge image shows a business near a transit stop in a known city, Overpass Turbo can narrow candidates to a handful of locations by querying for the business type within a small radius of transit nodes. Verify each result with Google Street View. The around operator (proximity filter) is the most useful feature — it replaces hours of manual map browsing.
Inline code / one-liners / common payloads. Loaded on demand from SKILL.md. Detailed techniques live in the category-specific support files listed in SKILL.md.
https://x.com/i/user/<id> works even after renames.(id >> 22) + 1288834974657 = Unix ms.curl -sI for x-tumblr-user header. Avatar at /avatar/512. See social-media.md.XXXX+XXX (chars: 23456789CFGHJMPQRVWX). Drop a pin on Google Maps → Plus Code appears in details. Free, no API key needed. See geolocation-and-media.md.exiftool image.jpg # EXIF data
pdfinfo document.pdf # PDF metadata
mediainfo video.mp4 # Video metadata
site:example.com filetype:pdf
intitle:"index of" password
Image TBS filters: Append &tbs=itp:face to Google Image URLs to filter for faces only (strips logos/banners). See web-and-dns.md.
/export?format=csv, /pub, /gviz/tq?tqx=out:csv, /htmlview. See web-and-dns.md.dig -t txt subdomain.ctf.domain.com
dig axfr @ns.domain.com domain.com # Zone transfer
Always check TXT, CNAME, MX for CTF domains. See web-and-dns.md.
https://metrics.torproject.org/rs.html#simple/<FINGERPRINT> -- check family, sort by "first seen". See web-and-dns.md.gh api. See web-and-dns.md./start, answer verification questions. See web-and-dns.md.curl "http://ip-api.com/json/103.150.68.150"
Pattern: Visually-identical Unicode characters from different blocks (Cyrillic, Greek, Math) encode binary data in social media posts. ASCII = 0, homoglyph = 1. Group bits into bytes for flag. See social-media.md.
No auth needed. Endpoints: public.api.bsky.app/xrpc/app.bsky.feed.searchPosts?q=..., app.bsky.actor.searchActors, app.bsky.feed.getAuthorFeed. Check all replies to official posts. See social-media.md.
Persistent numeric User ID (key technique):
https://x.com/i/user/<numeric_id> -- works even after username changes"author":{"identifier":"..."})Username rename detection:
http://web.archive.org/cdx/search/cdx?url=twitter.com/USERNAME*&output=jsonAlternative Twitter data sources:
nitter.poast.org/USERNAME) show tweets without loginhttps://syndication.twitter.com/srv/timeline-profile/screen-name/USERNAME(id >> 22) + 1288834974657 = Unix msWayback Machine for Twitter:
# Find all archived URLs for a username
curl "http://web.archive.org/cdx/search/cdx?url=twitter.com/USERNAME*&output=json&fl=timestamp,original,statuscode"
# Also check profile images
curl "http://web.archive.org/cdx/search/cdx?url=pbs.twimg.com/profile_images/*&output=json"
# Check t.co shortlinks
curl "http://web.archive.org/cdx/search/cdx?url=t.co/SHORTCODE&output=json"
Blog existence check:
curl -sI "https://USERNAME.tumblr.com" -> look for x-tumblr-user header (confirms blog exists even if API returns 401)Extracting post content from Tumblr HTML:
"content":[ to find post body datatype: "text" with text field, and type: "image" with media URLshttps://64.media.tumblr.com/HASH/HASH-XX/s512x512u_c1/FILENAME.jpgAvatar as flag container:
https://api.tumblr.com/v2/blog/USERNAME.tumblr.com/avatar/512https://USERNAME.tumblr.com/avatar/512 (redirects to CDN URL)Pattern (Ms Blue Sky): Find target's posts on BlueSky social media.
Search filters:
from:username # Posts from specific user
since:2025-01-01 # Date range
has:images # Posts with images
Reference: https://bsky.social/about/blog/05-31-2024-search
"username" in quotes on major platformsUsername metadata mining: Usernames often embed geographic or temporal signals in their structure. Extract and research numeric suffixes, prefixes, or embedded patterns:
| Pattern | Example | Signal |
|---|---|---|
| Trailing digits = postal/ZIP code | LinXiayu35170 | 35170 = Bruz, France |
| Birth year suffix | jsmith1998 | Born 1998 |
| Area code | user212nyc | 212 = Manhattan |
| Country code | player44uk | +44 = United Kingdom |
Cross-reference extracted codes with postal code databases, phone number registries, or geographic gazetteers to narrow the subject's location. (MidnightCTF 2026)
Username chain tracing (account renames):
Priority platforms for CTF username enumeration:
Platforms that return 200 but no real profile:
t.me/USER): Always returns 200 with "Contact @USER" page; check for "View" vs "Contact" in title"username" with quotes on platform-specific searchesPattern (Massive-Equipment393): Reddit username -> Spotify social link -> Base58-encoded string -> Spotify playlist descriptions (base64) -> first-letter acrostic from song titles.
Key techniques:
Common flow:
Platform-specific flag locations:
Key techniques:
Pattern (Skybound Secrets): Flag hidden in a Bluesky post using Unicode homoglyph steganography — visually identical characters from different Unicode blocks encode binary data.
Detection:
а U+0430 vs a U+0061), Greek, Armenian, Mathematical Monospace, etc.Bluesky API search workflow:
# Search for posts about the CTF
curl -s "https://public.api.bsky.app/xrpc/app.bsky.feed.searchPosts?q=metactf+flash+ctf&sort=latest" | jq '.posts[].record.text'
# Search for specific accounts
curl -s "https://public.api.bsky.app/xrpc/app.bsky.actor.searchActors?q=metactf" | jq '.actors[].handle'
# Get profile
curl -s "https://public.api.bsky.app/xrpc/app.bsky.actor.getProfile?actor=metactf.bsky.social" | jq
# Get author feed (all posts)
curl -s "https://public.api.bsky.app/xrpc/app.bsky.feed.getAuthorFeed?actor=metactf.bsky.social&limit=50" | jq '.feed[].post.record.text'
# Get post thread (including replies)
curl -s "https://public.api.bsky.app/xrpc/app.bsky.feed.getPostThread?uri=at://did:plc:.../app.bsky.feed.post/..." | jq
Decoding homoglyph steganography:
def decode_homoglyph_stego(text):
bits = []
for ch in text:
if ch in ('\u2019',): # Platform auto-inserted right single quote
continue # Skip, not intentional homoglyph
if ord(ch) < 128:
bits.append(0) # Standard ASCII
else:
bits.append(1) # Unicode homoglyph = 1 bit
# Group into bytes (MSB first)
flag = ''
for i in range(0, len(bits) - 7, 8):
byte_val = 0
for j in range(8):
byte_val = (byte_val << 1) | bits[i + j]
flag += chr(byte_val)
return flag
Common homoglyph pairs:
| ASCII | Homoglyph | Unicode Block |
|---|---|---|
a (U+0061) | а (U+0430) | Cyrillic |
o (U+006F) | о (U+043E) | Cyrillic |
e (U+0065) | е (U+0435) | Cyrillic |
s (U+0073) | ѕ (U+0455) | Cyrillic DZE |
t (U+0074) | 𝚝 (U+1D69D) | Math Monospace |
p (U+0070) | р (U+0440) | Cyrillic |
Key lessons:
' → ') must be excluded from bit encodingpublic.api.bsky.appPattern (Where was Chine): Target's physical location identified through fitness tracking data. Username discovered on Twitter → alias found in GitHub code → alias searched on Strava → running route endpoint reveals location.
Strava public data exposure:
https://www.strava.com/athletes/<id>Location extraction workflow:
Key insight: Fitness apps are high-value OSINT targets because users rarely restrict activity visibility. A single public run reveals home/work neighborhoods. Cross-reference GPS endpoints with Google Maps to identify specific parks, buildings, or landmarks.
Detection: Challenge mentions exercise, running, cycling, fitness, GPS, or health tracking. Target persona has an active/athletic profile.
Pattern (Insanity 1 & 2, 0xFun 2026): Flags hidden in Discord server metadata not visible in normal UI.
Hiding spots:
# Enumerate with user token
TOKEN="your_token"
# List roles
curl -H "Authorization: $TOKEN" "https://discord.com/api/v10/guilds/GUILD_ID/roles"
# List emojis
curl -H "Authorization: $TOKEN" "https://discord.com/api/v10/guilds/GUILD_ID/emojis"
# Search messages
curl -H "Authorization: $TOKEN" "https://discord.com/api/v10/guilds/GUILD_ID/messages/search?content=flag"
Animated emoji: Download GIF, extract frames -- hidden data in brief frames invisible at normal speed.
site:example.com filetype:pdf
intitle:"index of" password
inurl:admin
"confidential" filetype:doc
Google Image TBS (To Be Searched) parameters:
Append &tbs= filters to Google Image search URLs for precision filtering:
| Filter | Parameter | Example |
|---|---|---|
| Faces only | itp:face | Find profile photos |
| Clipart | itp:clipart | Logos, icons |
| Animated GIF | itp:animated | Animated images |
| Specific color | ic:specific,isc:green | Dominant color filter |
| Transparent BG | ic:trans | PNGs with transparency |
| Large images | isz:l | High resolution only |
| Min resolution | isz:lt,islt:2mp | Greater than 2 megapixels |
Combined example: Search LinkedIn for face photos of interns at a company:
https://www.google.com/search?q="orange"+"alternant"+site:linkedin.com&tbm=isch&tbs=itp:face
Key insight: The itp:face filter is especially useful for OSINT — it strips out logos, banners, and UI screenshots from results, leaving only profile photos. Combine with site: and date range (after:YYYY-MM-DD) for targeted reconnaissance.
/export?format=csv - Export as CSV/pub - Published version/gviz/tq?tqx=out:csv - Visualization API CSV export/htmlview - HTML viewFlags often in TXT records of subdomains, not root domain:
dig -t txt subdomain.ctf.domain.com
dig -t any domain.com
dig axfr @ns.domain.com domain.com # Zone transfer
dig TXT ctf.domain.org
dig TXT _dmarc.domain.org
dig ANY domain.org
Lesson: DNS TXT records are publicly queryable. Always check TXT, CNAME, MX for CTF domains and subdomains.
https://metrics.torproject.org/rs.html#simple/<FINGERPRINT>
Check family members and sort by "first seen" date for ordered flags.
Pattern (Rogue, VuwCTF 2025): Hidden information in GitHub repo comments (issue comments, PR reviews, commit messages, wiki edits).
Check: gh api repos/OWNER/REPO/issues/comments, gh api repos/OWNER/REPO/commits, wiki edit history.
Pattern: Forensic artifacts (browser history, chat logs) may reference Telegram bots that require active interaction.
Finding bot references in forensics:
# Search browser history for Telegram URLs
import sqlite3
conn = sqlite3.connect("History") # Edge/Chrome history DB
cur = conn.cursor()
cur.execute("SELECT url FROM urls WHERE url LIKE '%t.me/%'")
# Example: https://t.me/comrade404_bot
Bot interaction workflow:
https://t.me/<botname> -> Opens in Telegram/start or bot's custom commandVerification question patterns:
Example bot flow:
Bot: "TIER 1: Which account used for online search?"
-> Answer from Edge history showing Bing/Google searches
Bot: "TIER 2: Which account name did you change?"
-> Answer from Security event log (account rename events)
Bot: [Grants access] "Website: http://x.x.x.x:5000, Username: mehacker, Password: flaghere"
Key insight: Bot responses may reveal:
Pattern (Shell Game): Track organizational donors through FEC filings.
Key resources:
# Find all archived URLs for a site
curl "http://web.archive.org/cdx/search/cdx?url=example.com*&output=json&fl=timestamp,original,statuscode"
# Basic WHOIS lookup
whois example.com
# Key fields to extract:
# - Registrant name/email/org (often redacted by privacy services)
# - Creation/expiration dates (timeline correlation)
# - Name servers (shared hosting identification)
# - Registrar (can indicate sophistication level)
# Historical WHOIS (before privacy was enabled)
# Use SecurityTrails, WhoisXML API, or DomainTools
curl "https://api.securitytrails.com/v1/domain/example.com/whois" \
-H "APIKEY: YOUR_KEY"
# Reverse WHOIS — find all domains registered by same entity
# Search by registrant email, org name, or phone number
curl "https://reverse-whois-api.whoisxmlapi.com/api/v2" \
-d '{"searchType":"current","mode":"purchase","basicSearchTerms":{"include":["target@email.com"]}}'
# IP WHOIS (find network owner)
whois 1.2.3.4
# Look for: NetName, OrgName, CIDR range, abuse contact
# ASN lookup
whois -h whois.radb.net AS12345
# Or use bgp.tools: https://bgp.tools/as/12345
Key insight: WHOIS data is most useful for timeline correlation (when was the domain registered relative to CTF events?), reverse lookups (what other domains share the same registrant?), and identifying shared infrastructure. Historical WHOIS via SecurityTrails or Wayback Machine can reveal pre-privacy registrant details.