eardrop
eardrop
Listen to an iPhone's HTTPS traffic from the Mac to find where an app fetches data/images. Sets up mitmproxy, walks the iPhone proxy+cert setup, then locates and extracts API endpoints. Trigger when the user wants to "sniff iphone traffic", "intercept app traffic", "see where an image/app loads from", "MITM my phone", or inspect an app's API calls.
Unzip into your Claude skills directory (e.g. ~/.claude/skills/) or your project's .claude/skills/ to use it.
eardrop — iPhone HTTPS traffic interception
Goal: see the decrypted HTTP(S) calls an iPhone app makes (from the Mac), find the
endpoint/image a screen loads, and optionally replay it to download assets.
Legitimate use only: the user's own device + own network/account. Stop if it's not.
0. Preflight — is the tooling there?
command -v mitmweb mitmdump mitmproxy # need mitmproxy (brew install mitmproxy)
ls ~/.mitmproxy/mitmproxy-ca-cert.pem # CA cert (auto-created on first run)
ipconfig getifaddr en0 || ipconfig getifaddr en1 # Mac Wi-Fi IP — phone points here1. Start the proxy (background, fixed password)
mitmweb's auto token is awkward over a background pipe — set a known password instead.
mitmweb --no-web-open-browser --web-host 127.0.0.1 --web-port 8081 \
--listen-port 8080 --set web_password=iris --set stream_large_bodies=1m- Web UI: http://127.0.0.1:8081 (password above). Flow List = live requests.
- Verify it's up:
lsof -nP -iTCP:8080 -sTCP:LISTEN - For reliable self-inspection add
-w /tmp/flows.mitm, then read later with
mitmdump -nr /tmp/flows.mitm. (mitmweb's stdout is block-buffered and lags — the
web UI / -w file are the source of truth, not the background task output.)
2. iPhone setup (user does this, same Wi-Fi)
- Settings → Wi-Fi → ⓘ → Configure Proxy → Manual → Server = Mac IP, Port =
8080. - Install cert ON the phone (a downloaded
.pemon the Mac is useless): Safari →
http://mitm.it → tap the Apple icon → Allow → install the profile in
Settings → General → VPN & Device Management.
- CRITICAL — enable full trust: **Settings → General → About → Certificate Trust
Settings → toggle mitmproxy ON**. This is the step that's always skipped.
3. Verify trust before chasing the app
User opens https://example.com in Safari:
- Loads fine + shows in Flow List → trust OK.
- "This connection is not private" → cert NOT trusted (often the user trusted a
different tool's cert, e.g. Proxyman — check the profile name is mitmproxy). Redo 2.3.
4. Capture the target
- User fully closes + reopens the app, performs the action (open photo, etc.).
- Cached assets won't re-fetch — use a new item or pull-to-refresh.
- Filter in the web UI Search box:
~t image(image responses),~m GET, or a hostname. - Click a flow → Request tab for URL + headers; Response tab for the body.
5. Diagnosing "nothing shows up"
Read the proxy log / flows. The signatures:
| Symptom | Meaning | Fix |
|---|---|---|
| Client TLS handshake failed … client disconnected | App rejects our cert | Trust not enabled (§2.3) or the app pins certs (§6) |
| App shows "connection error", log frozen | Traffic not reaching Mac, or all conns fail | Re-check proxy IP (it can change), firewall, :8080 listening |
| Only mitm.it/analytics flows, app silent | Cert untrusted → only HTTP got through | §2.3 |
| Safari "not private" | OS-level trust missing | §2.3 |
6. Certificate pinning (Instagram, Meta, banks, many SDKs)
If handshakes keep failing after trust is confirmed, the app pins its cert — it
hardcodes the expected cert and rejects mitmproxy's regardless of OS trust. A plain proxy
can't beat this. Options:
- A8–A11 devices (iPhone 6s … 8/X) are jailbreakable via checkm8 (
palera1n,
unpatchable bootrom) on any iOS incl. 16/17 → install SSL Kill Switch 3 / A-Bypass
in Sileo to disable pinning system-wide. *(A11 + iOS15/16: remove the passcode first or it
boot-loops; semi-tethered, re-run palera1n after each reboot.)*
- Android emulator + Frida (
frida-multiple-unpinning) orapk-mitmis often easier. - Even when pinned, mitmproxy still logs the hostnames (
server connect …) — useful for
mapping which CDNs/APIs an app talks to without decrypting.
7. Extract & replay (download assets via the API)
Once you see the API:
- Note required headers — many APIs reject calls missing a custom
Origin/X-Originor
a Bearer token. Copy them from a captured Request → Headers.
- Stash the token in a file (
/tmp/<app>_token.txt) to keep commands clean; tokens expire
(decode the JWT exp), so grab a fresh one if calls start returning 401.
- Replay with curl, following redirects for signed asset URLs:
T=$(cat /tmp/app_token.txt)
curl -s -H "origin: <captured-origin>" -H "authorization: Bearer $T" \
-H "accept: application/json" "https://api.example.com/v1/<resource>" | python3 -m json.tool
curl -sL '<signed CDN/S3 url>' -o ~/Desktop/asset.jpg # presigned URLs need no auth, expire fast
- Cloud asset URLs (Rails ActiveStorage
…/blobs/redirect/<signed-id>/<name>) 302 to a
presigned S3/GCS link; the bucket name often reveals quality tiers (…-thumbnails,
…-originals, …-preview). Check resolution: sips -g pixelWidth -g pixelHeight file.jpg.
8. Noise to ignore
X-Paddingheader full of junk JSON (often the famous Foursquare "Central Park" sample,
quotes swapped for *): deliberate size-obfuscation filler to defeat traffic analysis.
Not real data — ignore.
- AppsFlyer / Sentry / PostHog / Firebase / Apple
*.ess.apple.comhosts: third-party
analytics, usually pinned and irrelevant to the target.
9. Cleanup (always offer at the end)
- Stop proxy:
pkill -f mitmweb - Remind the user to set iPhone Wi-Fi proxy back to Off (Settings → Wi-Fi → ⓘ →
Configure Proxy → Off) — otherwise no internet once the Mac proxy stops.
- Delete any stashed tokens (
rm /tmp/*_token.txt) and temp flow files.