READONLY — The Man Who Escaped Reality

A hand-drawn QR code carries two payloads: one is the vault, the other is the keys. The chain opens as a supermax jailbreak and closes somewhere much stranger.

Platform: OSINT Industries CTF (ctf.osint.industries) Flag format: OSINT{HOW_AT_LOCATION} — the literal AT is stripped on submission Starting material: one file, evidence.png — a hand-drawn QR code

Result up front: the QR carries two payloads. One is a Proton Drive link to a password-locked PDF; the other is a Braille-and-Morse string resolving to patient041.blogspot.com, where two passwords are hidden in the site’s furniture — a favicon and a fake shell. They concatenate to Archive_404_Exit_Node, the PDF opens, and the document dismantles the premise of the challenge. Flag: OSINT{ESCAPING_REALITY_ADX_FLORENCE}.

The scenario

The brief reads like a locked-room mystery. On 13 December 2019 an inmate known only as READONLY vanished from a cell at ADX Florence, the federal supermax in Colorado. The door stayed locked, the cameras caught nothing, no forced entry — and the only thing recovered from the cell was a hand-drawn QR code. Years later the evidence resurfaces, and we’re told to continue the investigation.

Two questions to answer:

  • How did he escape?
  • Where is he now?

Both go into the flag. Nothing else is given.

Stage 1 — The QR has two faces

Feeding evidence.png into a decoder gives something that looks broken:

⠏‐․..  ⠁·----  ⠞-----  ⠊--·  ⠑·····  ⠝·--·  ⠞-----  ⠼⠚-  ⠼⠙  ⠼⠁

That’s not corruption. Two things are going on, and the challenge telegraphs the first one loudly: the post it eventually leads to is named scan180degree, and a later note literally says “rotate the QR 180 Degree and try again.” Decoders report the symbol orientation as DOWN — the code was drawn upside down, and the three finder patterns sit in the wrong corners.

The bigger surprise: this QR carries two separate payloads depending on how you read it. A rotation-aware scanner surfaces both:

  • A URL → a Proton Drive share link (with the decryption fragment after the #).
  • A text blob → the Braille + Morse string above.

The text blob interleaves two alphabets — a Braille cell followed by a Morse group, repeating:

LayerContentResult
Braille cells⠏⠁⠞⠊⠑⠝⠞patient
Numeric Braille⠼⠚ ⠼⠙ ⠼⠁041
Morse-... .---- ----- --. ..... .--. ----- -B10G5P0TBLOGSPOT

The prefix is the number sign — it switches the following cells from letters to digits, so ⠚⠙⠁ reads 041 rather than jda. Miss the prefix and you get a hostname that does not resolve. The Morse layer is straight leetspeak once decoded: 1→L, 0→O, 5→S.

So the text payload resolves to patient041.blogspot.com, while the URL payload points straight at the PDF. You need both — one gives you the vault, the other gives you the keys.

If your scanner only ever returns the URL, it is silently normalising rotation and picking the “up” reading. Flip the image and rescan, or dump the raw QR bytes. The second payload is really there — a decoder that hides it from you is doing you a favour it did not ask permission for.

Stage 2 — The archive that remembers everything

patient041.blogspot.com is a green-on-black “READONLY_OS” terminal aesthetic. The landing button (ENTERY NODE) drops you into a post styled as a leaked case file: a README typed out letter by letter, sealed case reports, a contradictory timeline, an investigation board, an audio log, a fake shell, and a folder of “encrypted storage” files — including one named the_third_truth.locked.

The page announces three answers survived, each tied to a diary fragment:

  1. “can you find my favorite icon?” → the favicon.
  2. “data has a habit of returning” / “the archive remembers everything” → the shell’s recover command.
  3. “the browser remembers the path” → the address bar (a #hash trigger).

Two of those three are actual passwords.

Password 1 — hiding in the favicon

The inline <link rel="icon"> in the markup is a harmless SVG. The real /favicon.ico, fetched directly, is a 48×48 raster mask that reads:

PASSWORD 1
ARCHIVE 404

Classic misdirection — the decoy icon is in the DOM; the payload icon is the one the browser actually requests.

Password 2 — decoding the shell

The fake terminal accepts a handful of commands. recover runs a scripted “restore” sequence that ends by base64-decoding a string. Decoded, it yields:

PASSWORD 2
Exit Node

The third “answer” is a red herring

The #the_third_truth / #exit_node hash fires a handler that only reveals a narrative line (“the transfer paperwork and the intake photo are dated eleven days apart”). No password. It exists to make you feel like there’s a third credential when there are only two. Note the exact casing that matters later: ARCHIVE 404 is upper-case in the favicon, but the base64 decodes to title-case Exit Node — take each word as it appears at its source.

Dead ends on the blog

Three that cost me time:

  • The UTC+13 timezone. The blog’s post timestamps are set to UTC+13, which reads as a geo-anchor and isn’t one. Nothing in the challenge is in New Zealand, and it was July regardless.
  • thethirdtruth.blogspot.com. It exists. It is an unrelated blog by an unrelated person. The hash fragment is not a hostname hint.
  • The .locked files. The “encrypted storage” folder is markup, not files — Blogspot cannot host arbitrary binaries. The only real .locked artefact in this challenge is the PDF.

Stage 3 — The locked record

The Proton Drive link from the QR’s URL payload opens a PDF viewer prompting for a password: internal_record_review_041.pdf. Nothing else lives in the share — so the passwords have to come from the blog.

Concatenate the two, Password 1 then Password 2, in the challenge’s stated Password_One_Password_Two format, spaces to underscores:

Archive_404_Exit_Node

The PDF unlocks.

Stage 4 — The twist

The document is a Federal Bureau of Prisons “Internal Record Review” for Patient 041, cell D-14, ADX Florence. The evidence review dismantles the entire premise:

  • No inmate using the alias READONLY ever existed.
  • No escape matching the description ever occurred.
  • No investigation was ever opened.
  • Handwriting analysis on the QR code confirms a single author — Patient 041.

Then the recovered final note turns the whole case inward. The investigator followed every password, every cipher, every impossible lead — and at some point stopped following the story and started writing it. The clues were never left for another investigator. They were left for the person he would become, so that if he ever forgot, he could remember. The last page:

WELCOME BACK. YOU NEVER ESCAPED ADX FLORENCE. YOU ESCAPED… BY ESCAPING REALITY.

Patient 041 is READONLY. There was never a second hacker, never a trail — one prison, one cell, one mind. The “escape” was a break from reality, and he never left the building.

The flag

Mapping the two answers onto the format (HOW_AT_LOCATION, with AT removed):

  • How: escaping reality
  • Where: ADX Florence (he never left)

The PDF’s wording is “ESCAPING”, not “escaped” — the exact-match checker cares:

OSINT{ESCAPING_REALITY_ADX_FLORENCE}

Reflection

What makes this one clean is the shape. It opens dressed as a hard-OSINT jailbreak — the kind of case where you’d expect shell companies, flag states, and sanctions trails — and every technical layer (dual-payload QR, Braille/Morse, favicon stego, a base64’d shell command, a password-locked PDF) is real and has to be solved. But the payload at the end isn’t a fact to look up. It’s a mirror. The text tells you outright: “You spent hours trying to solve my imagination. Now imagine spending years living inside it.” The solver becomes the “someone patient enough, curious enough, broken enough” the author was writing for. Nicely built.

What is held back and why. The live Proton Drive link stays out of this post. The method is all here — the dual payload, the two hiding places, the concatenation format — but not the ready-made share URL, so the challenge stays solvable for the next person instead of becoming a copy-paste.

Takeaways

  • A decoder that “just works” may be discarding data. Rotation normalisation is a convenience feature, and it silently picked one of two payloads here. When a barcode or QR result looks complete, dump the raw bytes anyway before deciding that is all there was.
  • The icon in the DOM and the icon the browser fetches are different resources. /favicon.ico is requested by path whether or not a <link rel="icon"> overrides it. Any asset with a well-known default path is worth fetching directly rather than reading out of the markup.
  • Casing belongs to the credential. ARCHIVE 404 was upper-case at its source; the base64 decoded to title-case Exit Node. Transcribe each fragment as it appears where you found it — normalising to a house style breaks exact-match checkers.
  • Ask what the platform can actually host. The “encrypted storage” folder cost me time because I treated filenames in markup as files. Blogspot cannot serve arbitrary binaries, which rules the whole folder out as set dressing before you try to fetch a single one.

Sources