Cyberpunk Terminal

A synthetic network drawn from a seed: six hosts with addresses, open ports, service banners, accounts and files, all generated. You explore it from a prompt with a bounded set of 14 commands, and three missions, chosen by that same seed from a pool of six, ask you to work something out from what you find, by taking the evidence to this site's own tools and chaining them.

Nothing here touches the network. The in-game dig resolves against the generated topology and nothing else, so a name you type is never sent to a resolver, and every input is fictional.

Rendered when the site was built, by the same core the browser runs, with seed pah.moi. With JavaScript this becomes a live prompt that keeps a session, unlocks files and checks your answers. Without it, the command reference and all three briefings are still here, evidence and all, and every mission can be solved by hand with the tools it names.

The command set

Every command the terminal understands, and nothing else parses
CommandWhat it does
helpList every command this terminal understands.
man <command>Show one command's usage and what it does.
netThe site prefix, the segment size it is cut into, and the gateway.
scanList every host: name, address and role.
dig <name>Resolve a name in the synthetic zone. Nothing leaves your browser.
ports <host>Open ports on a host, with the banner each service announces.
head <host>The HTTP response headers a host serves, ready to paste into /headers.
users <host>Local accounts on a host, with their comment fields.
login <host> <user> <password>Authenticate to a host for this session, unlocking its restricted files.
ls <host>Files on a host; restricted ones are marked.
cat <host>:<file>Print a file. Restricted files need a login first.
missionsList the missions and which are solved.
mission [n]Show the current mission's briefing, or switch to mission n.
submit <answer>Check an answer against the current mission.

The network at seed pah.moi

Site prefix 10.37.98.0/24, cut into /29 segments, gateway 10.37.98.1.

Generated hosts, with their addresses, roles and open ports
HostAddressRoleOpen ports
gw0110.37.98.1gateway22, 179, 11211
front0110.37.98.170web22, 80, 443, 6379
api0110.37.98.122app22, 80, 443, 8080, 9200
pg0110.37.98.234db22, 5432
hop0110.37.98.93jump22
bak0110.37.98.58backup22, 80, 443, 873

Mission 1: A credential nobody had to steal

The backup host carries a second signed credential, sitting in a file that needs no login at all: anyone who can list the host can read it. Decode it, and submit the whole number of days between its issue and its expiry.

Chains
/jwt then /epoch
Route
cat <backup host>:rotation-token.txt
Answer
a whole number of days, e.g. 42 days
# backup rotation credential: rotated automatically, no login required to read
ROTATION_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImJhY2t1cC0yMDI0In0.eyJpc3MiOiJncmlkLWJhY2t1cCIsInN1YiI6InN2Yy1yZXBvcnQiLCJhdWQiOiJpbnRlcm5hbC1hcGkiLCJpYXQiOjE3MTAwMDAwMDAsImV4cCI6MTcxNjQ3NDA5N30.4ExUWK6_vQ_18S_7bm5861gVVxqpCS7JZDxqwEBLiR4
ROTATION_TOKEN_SIGNING_KEY=grid-backup-rotation-signing-key

Mission 2: The file that lies about what it is

One file left this network overnight. The transfer log records a great many ordinary session events and exactly one file actually sent. Find that line, read the file it names, and identify what the bytes really are. Submit the media type, not the extension: the extension is the claim being tested.

Chains
/grep then /magic-bytes
Route
cat <db host>:transfer.log → cat <db host>:<the file the log names>
Answer
a media type, e.g. application/zip
2024-03-11T02:14:07Z sftp[2291]: session opened for local user svc-report
2024-03-11T02:14:07Z sftp[2291]: opendir "/srv/reports"
2024-03-11T02:14:08Z sftp[2291]: closedir "/srv/reports"
2024-03-11T02:14:19Z sftp[2291]: open "/srv/reports/index.csv" flags READ mode 0666
2024-03-11T02:14:19Z sftp[2291]: close "/srv/reports/index.csv"
2024-03-11T02:15:02Z sftp[2291]: stat "/srv/reports/archive"
2024-03-11T02:15:03Z sftp[2291]: opendir "/srv/reports/archive"
2024-03-11T02:15:04Z sftp[2291]: closedir "/srv/reports/archive"
2024-03-11T02:16:41Z sftp[2291]: open "/srv/reports/notes.txt" flags READ mode 0666
2024-03-11T02:16:41Z sftp[2291]: close "/srv/reports/notes.txt"
2024-03-11T02:17:12Z sshd[2288]: subsystem request for sftp by user svc-report
2024-03-11T02:17:44Z sftp[2291]: sent "/srv/reports/board-minutes.pdf" bytes 4718592
2024-03-11T02:17:45Z sftp[2291]: close "/srv/reports"
2024-03-11T02:17:46Z sftp[2291]: session closed for local user svc-report

--- board-minutes.pdf ---
first 32 bytes of board-minutes.pdf, as spaced hex:
7F 45 4C 46 02 01 01 00 00 00 00 00 00 00 00 00 02 00 3E 00 01 00 00 00 50 10 40 00 00 00 00 00

Mission 3: The door that was left open

Three hosts on this network answer HTTP. Exactly one of them serves a response with no Strict-Transport-Security header, so its traffic can be downgraded to plain HTTP. Find that host, then work out which /29 segment its address falls in and submit that segment's network address. Note that the weak block also pairs `Access-Control-Allow-Origin: *` with `Access-Control-Allow-Credentials: true`, which the Fetch standard rejects, but the HTTP Response Header Analyzer does not check CORS, that one is yours to spot.

Chains
/headers then /subnet
Route
scan → head <host> (for each host that answers HTTP)
Answer
a dotted-quad network address, e.g. 10.0.0.8
--- front01 (10.37.98.170) ---
HTTP/1.1 200 OK
Server: nginx/1.24.0
Content-Type: text/html; charset=utf-8
Content-Security-Policy: default-src 'self'
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=()
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true

--- api01 (10.37.98.122) ---
HTTP/1.1 200 OK
Server: Caddy
Content-Type: application/json
Strict-Transport-Security: max-age=31536000
Content-Security-Policy: default-src 'none'
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Referrer-Policy: no-referrer
Permissions-Policy: interest-cohort=()

--- bak01 (10.37.98.58) ---
HTTP/1.1 200 OK
Server: nginx/1.24.0
Content-Type: text/html; charset=utf-8
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
Content-Security-Policy: default-src 'self'; frame-ancestors 'none'
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), geolocation=(), microphone=()
About this toy1 paragraph

The pool of six missions chains six tools between them, two per mission: the HTTP Response Header Analyzer, the Subnet Calculator, the JWT Decoder, the Epoch Converter, Client-Side Grep, and File Header Forensics. Every answer is genuinely what it claims to be: the digests, header layouts and file signatures here are computed by the same code those tools run, not written out by hand: true of the three missions a seed happens to draw, and of the three it doesn't.

Use it locally This toy has a native command line twin. Build hack-terminal-cli from the site's source with:
cargo build --release --bin hack-terminal-cli
Source and licence terms