zwesty
Write-ups / Day 8 / Android
Day 8 · Thu, Oct 8 · Android

Cleartext Session

Prey slaughtered

Static APK inspection (an APK is a zip), reading packaged assets, simple decoding (reverse)

STTMClaude Homebase Both

Flags are shortened to their first 8 and last 4 characters because they're unique per team.

Challenge ID
mobile-android-day-08-cleartext-session (+ /time_trial, /mastery)
Solved
2026-10-10, all three modes, 5 min 11 s from first start to last CORRECT
Player
Zwesty (solo), with Claude Code (Opus 5.5)

The challenge

Recover a synthetic session from allowed cleartext traffic and replay it against the backend.

One question, answer: “For case MOB-08-9DC6C997E6 in package com.huntress.mobile.d08.v9dc6c997e65d: Recover a synthetic session from allowed cleartext traffic and replay it against the backend. Submit only the exact backend answer code returned for this case.” Artifact: cleartext_session.apk. Format: ANS- followed by exactly 16 uppercase hexadecimal characters; no spaces or explanatory text, normalization exact.

How this lane was solved is explained once, in the Network Config Split write-up (Day 10, the first Android solve). Short version: every assigned APK carries assets/huntress_puzzle.json, and decoding it gives the answer. The app never has to run.

Reading the prompt: what it said we'd need

Clue What it pointed to What I did about it
allowed cleartext traffic plain HTTP the app's network config permits Static route
replay it against the backend a runtime service The puzzle was the answer reversed, like Day 2

Honest note: the prompts describe real Android attack surface, which would mean installing and driving the app. In this event the answer sat in a packaged JSON file that the app's own code never reads, so none of that was needed.

Safety

Static only. The APKs were opened as zip files on our Kali VM and one JSON asset was read; nothing was installed or run.

What was in the files

cleartext_session.apk, about 12.7 KB: one classes.dex, the manifest, a few resources, and assets/huntress_puzzle.json:

{"schema":"huntress.mobile.puzzle.v1","day":8,"codec":"reverse","data":"6667D24E8BC6DE39-SNA"}

Codec reverse: data is the answer written backwards (it ends in -SNA); reversing it gives ANS-….

The Time Trial and Mastery APKs use the same template with different values.

Single Solve

Started untimed to download the APK, decoded by our shared Android solver, and sent once: ANS-93ED6CB8E42D7666 → CORRECT in 1,713 ms (start to submit), flag e9081a7d…b482.

Solver: our Android solver from Day 10 (shared by Days 1–10). It reads the asset from the zip, checks the schema, decodes the codec, and returns the answer only if it is exactly ANS- + 16 uppercase hex; anything unknown stops the run before sending. Its tests: 10/10.

Time Trial

No clock (deadline: null). Same puzzle schema and codec as the Single Solve.

This route is opt-in timed. A plain start, as here, is unranked: CORRECT, but no ranked time. A ranked time needs a retry that asks for the clock (done; see Ranked retries).

started_at 2026-10-10T15:56:55.206Z  deadline None  answer_ids ['answer']
  mode time_trial  unranked  unique_attempts_remaining 32  ranked_attempts_remaining 32  variant_fresh True
  artifact cleartext_session_time_trial.apk 12704 bytes sha256 238d8671ae6adb46… (checked)
  answer: ANS-608057A4A2A9F3AD
  start         897 ms
  artifact      518 ms
  solve           0 ms
  submit        650 ms
  TOTAL        2065 ms
result CORRECT  flag eca0b570…c6ff

Mastery

No clock (deadline: null). 5 APKs, one per set; the questions name them delivery N: …_mastery_0N.apk. Same puzzle schema and codec as the Single Solve.

This route is opt-in timed. A plain start, as here, is unranked: CORRECT, but no ranked time. A ranked time needs a retry that asks for the clock (done; see Ranked retries).

started_at 2026-10-10T15:56:58.443Z  deadline None  answer_ids ['set1.answer', 'set2.answer', 'set3.answer', 'set4.answer', 'set5.answer']
  mode mastery  unranked  unique_attempts_remaining 32  ranked_attempts_remaining 32  variant_fresh True
  artifact 01-cleartext_session_mastery_01.apk 12704 bytes sha256 8ad1b7430847a20d… (checked)
  artifact 02-cleartext_session_mastery_02.apk 12704 bytes sha256 aac0b55e90d31586… (checked)
  artifact 03-cleartext_session_mastery_03.apk 12704 bytes sha256 8afc2b65eb3b435f… (checked)
  artifact 04-cleartext_session_mastery_04.apk 12704 bytes sha256 ab0ff366e2bed2c9… (checked)
  artifact 05-cleartext_session_mastery_05.apk 12704 bytes sha256 792fbb10f550d333… (checked)
  set1.answer: ANS-B308805EC36A10E1
  set2.answer: ANS-CC7BCA3427D533BD
  set3.answer: ANS-47485C48A8C219C0
  set4.answer: ANS-79397DA3C81040D8
  set5.answer: ANS-BBADCBB77F376322
  start         999 ms
  artifact      439 ms
  solve           1 ms
  submit        813 ms
  TOTAL        2253 ms
result CORRECT  flag 31c938cd…1f28

Ranked retries (opt-in clock)

Both timed modes were retried with the clock switched on so they count as ranked, with real deadlines. Same solver, same pipeline:

Mode started_at Clock On clock (est.) Result
Time Trial 2026-10-10T16:14:20.048Z 8 s 1,174 ms (artifact 484 + solve 1 + submit 689) CORRECT, eca0b570…c6ff
Mastery (5 sets) 2026-10-10T16:14:23.798Z 8 s 1,038 ms (artifact 346 + solve 1 + submit 691) CORRECT, 31c938cd…1f28

Time to solve

All three modes were solved on 2026-10-10 in 5 min 11 s, from the first Single Solve start at 15:51:48 UTC to the Mastery CORRECT at 15:56:59 UTC, each on its first submit. Those timed runs had no clock and were unranked; the ranked retries of the Time Trial and Mastery both went CORRECT at 16:14 UTC.

Takeaways

  • Read every packaged file before assuming the app must run. The answer sat in assets/, unread by the app's code.
  • The answer format is a strong check. ANS- + 16 uppercase hex rules out wrong decodings (Day 10's other split reading, a wrong Caesar direction) before anything is sent.
  • Older routes become opt-in timed. This day's timed runs had no clock, so they count as CORRECT without a ranked time; a retry with the clock switched on is needed for one.