Challenge / Crypto

Birds Of Randomness

Birds Of Randomness is a sanitized challenge note from the local HTB archive, organized for quick review by category, difficulty, evidence flow, and reusable operator

MediumPublished 2024-03-23Sanitized local writeup

Scenario

Birds Of Randomness attack path

Birds Of Randomness is a sanitized challenge note from the local HTB archive, organized for quick review by category, difficulty, evidence flow, and reusable operator

Objective

Challenge walkthrough focused on Crypto evidence, validation, and reusable operator lessons.

Birds Of Randomness sanitized attack graph

Walkthrough flow

01

Audit the source before touching the remote service.

02

Identify that each station point is d * G, where d is...

03

Use small prime-power factors of the EC order to...

04

Factor the recovered scalar into the three current...

05

Generate destination candidates by advancing every...

Source coverage

High source coverage

Status: complete. This article is generated from 4 sanitized Markdown sources and keeps raw flags, credentials, keys, cookies, and reusable secrets out of the rendered blog.

100% coverage
Evidence verdict

High confidence: the page is reconstructed from a primary walkthrough plus multiple supporting notes or evidence sources. Treat the chain as source-backed, while still checking the listed source files for sensitive values.

  • Crypto/Birds-of-Randomness/writeup.md
  • htb-challenge/Crypto/Birds-of-Randomness/notes.md
  • htb-challenge/Crypto/Birds-of-Randomness/memory-summary.md
  • htb-challenge/Crypto/Birds-of-Randomness/hypothesis-board.md

Technical Walkthrough

Writeup

Challenge

  • Name: Birds-of-Randomness
  • Category: Crypto
  • Difficulty: Medium
  • Mode: hybrid

Summary

The service exposes a departing station as an elliptic-curve point. The source

shows each station is d G, where d = x y * z and the three PRNG state

components are small prime values. The EC group order has enough small factors

to recover this bounded scalar with Pohlig-Hellman plus CRT. Factoring the

scalar gives the current state values; the assignment to (x, y, z) is

ambiguous, but there are at most six permutations and the service gives six

guesses.

Artifact Inventory

The archive contains:

  • source.py: challenge service implementation and route generator.
  • love_letter.txt: story hint and an explicit warning not to pursue image stego.
  • forologia.jpg: story image, not needed for the solve.

The live service was available at <TARGET>:32403.

Analysis

source.py defines a route state (x, y, z) modulo 30269, 30307, and

30323. Each rotation multiplies the components by fixed constants. A station

is emitted only when all three components are prime, and the station coordinate

is the elliptic-curve point:

text
d * G where d = x * y * z

The largest possible station scalar is:

text
30269 * 30307 * 30323 = 27817185604309

The supplied EC order includes small prime-power factors:

text
[2, 3, 49, 1487, 3761, 176489, 439693]

Their product is greater than the maximum possible station scalar. That means

we can recover the departing scalar uniquely by solving the discrete log modulo

each small factor and combining the residues with CRT.

After recovering d, factoring it gives the three prime state values. Because

the published EC point only reveals the product, not which factor belongs to

which state component, the solve tries every unique permutation. This is still

bounded by six candidates, which matches the six mechapegion guesses offered by

the service.

Solve

Run:

bash
python3 Crypto/Birds-of-Randomness/solve/solve.py --host <TARGET> --port 32403

The solver:

  1. Parses the departing station coordinates from the service.
  2. Implements the curve arithmetic locally.
  3. Recovers the departing scalar using PH/CRT over the small order factors.
  4. Factors the scalar into the three current prime state components.
  5. Advances each possible state permutation to the next all-prime station.
  6. Submits the unique destination candidates until the service returns the flag.

The redacted live transcript is stored at

analysis/remote/solve-transcript-redacted.txt.

Flag

Raw flag is stored in loot/flag.txt and intentionally not reproduced here.

Lessons

  • Bounded EC scalars can make partial Pohlig-Hellman enough even when the full

group order has a large unfactored component.

  • When a point reveals only a product of state components, preserve assignment

ambiguity and use the protocol's allowed guesses if the search space is small.

  • Follow explicit challenge hints: the letter states the image is story-only, so

the source and live transcript are the correct evidence path.

Source-Backed Dossier

The sections below are merged from companion Markdown notes for the same case. They are rendered after sanitization so the article stays precise without publishing raw flags, credentials, or target-specific secrets.

Notes

Scope

  • Challenge: Birds-of-Randomness
  • Category: Crypto
  • Difficulty: Medium
  • Mode: hybrid
  • Remote instance: none
  • Start time: 2026-06-13T09:38:31Z
  • Operator: harness
  • State file: challenge-state.json

Harness Status

  • Current phase: see challenge-state.json
  • Next allowed actions: see next-action.json
  • Raw flags and sensitive material stay in loot/ only. Do not paste them here.

Artifact Inventory

FileSizeSHA256TypeNotes
files/a12c738d-f603-4273-8c57-a8bbf7eec7ac.zip5263424<hash redacted>Zip archive data, at least v1.0 to extract, compression method=storezip entries: 4 shown in artifact inventory JSON

Evidence Ledger

TimeActionOutput/FileFindingConfidenceNext
2026-06-13T09:38:31Zharness initchallenge-state.jsonWorkspace initialized with deterministic state fileHighInventory artifacts
2026-06-13T09:38:46Zartifact inventoryanalysis/artifact-inventory.json1 artifact(s) inventoriedHighBuild or update hypotheses
2026-06-13T09:38:46Zhypothesis recordedhypothesis-board.mdAnalyze the provided crypto source and remote transcript to identify weak randomness or coordinate-derived seed recovery, then reproduce the ticket/flag derivation.MediumExtract source, identify PRNG/seed/key schedule, and compare one local transcript with the remote prompt format.
2026-06-13T09:38:46Zresearch taskanalysis/research/task-20260613T093846334465Z-3c583fdb.mdResearch task created for advisory investigationMediumRecord research output
2026-06-13T09:40:01Zsource auditanalysis/source-audit.mdSource audit recordedHighGate before exploit
2026-06-13T09:40:01Zinstrumentation plananalysis/instrumentation-plan.mdRecover the next destination coordinates from one departing EC point.HighStop after two remote sessions fail with predicted coordinates; record transcript and reassess scalar recovery/state ambiguity before trying more guesses.
2026-06-13T09:40:11Zcheckpoint recordedanalysis/checkpoint-hypothesis_ready-20260613T094011399920Z-29b537a6.mdCheckpoint for <secret redacted>HighUse checkpoint to drive next decision
2026-06-13T09:40:41ZRAG queryanalysis/rag/rag-query-20260613T094031344513Z-73b06268.txtRAG helper exited 0; output savedMediumRecord retrieval tag and validation
2026-06-13T09:40:51ZRAG recordanalysis/rag-records.mdRetrieved memory tagged GENERICMediumValidate or reject with live evidence
2026-06-13T09:41:03Zresearch recordanalysis/research/research-records.mdResearch tagged MATCHEDMediumValidate against current evidence
2026-06-13T09:41:35Zlocal memory recordanalysis/local-memory-records.mdPrior local notes reviewed as fallback/advisory contextMediumValidate against current evidence
2026-06-13T09:41:35Zevaluatoranalysis/evaluator-20260613T094135484508Z-1f51436f.mdProceedHighImplement solve.py and submit predicted destination coordinates to the live service once.
2026-06-13T09:43:06Zflag captureloot/flag.txtHTB-format flag captured; raw value kept in loot onlyHighWrite solution and run completion gate
2026-06-13T09:44:04Zcompletion gatechallenge-state.jsonCompletion gate passed; state marked COMPLETEHighOptional sanitized memory summary approval

Key Findings

  • Source audit confirms the route state is three small modular components:

x mod 30269, y mod 30307, and z mod 30323.

  • Each station is emitted only after a rotation where all three components are

prime, and the published station coordinate is the elliptic-curve point

d G for d = x y * z.

  • The maximum possible station scalar is `30269 30307 30323 =

27817185604309`.

  • The supplied EC order has small prime-power factors

[2, 3, 49, 1487, 3761, 176489, 439693]; their product is

127593580992036069666, which is greater than the maximum station scalar.

  • That means Pohlig-Hellman over only those small factors plus CRT uniquely

recovers d from the departing station point.

  • Factoring d gives the three current prime state values, but the assignment

to (x, y, z) is ambiguous. There are at most six permutations, matching the

six available mechapegion guesses.

  • solve/solve.py implements standalone curve arithmetic, PH/CRT scalar

recovery, state factoring, candidate generation, and socket submission.

  • The live service accepted the third submitted destination candidate in the

captured run; the transcript is stored redacted under

analysis/remote/solve-transcript-redacted.txt.

RAG / Advisory Memory

RAG output is advisory only. Record evaluated retrievals with:

bash
scripts/challenge_harness.py rag-record <workspace> --query "..." --tag MATCHED|PARTIAL|MISSING|<secret redacted>|GENERIC --validation "..."

Secrets/Flags

Raw flags and sensitive material stay in loot/ only. Use scripts/challenge_harness.py capture-flag to validate and record flag capture without printing the value.

Memory Summary

Metadata

  • Platform: HackTheBox Challenges
  • Category: Crypto
  • Challenge: Birds-of-Randomness
  • Difficulty: Medium
  • Source workspace: <local workspace>

Validated Solve Chain

Concepts only. Do not include raw flags, reusable credentials, tokens, cookies, private keys, or live secrets.

  1. Audit the source before touching the remote service.
  2. Identify that each station point is d * G, where d is the product of

three small prime PRNG state components.

  1. Use small prime-power factors of the EC order to recover the bounded scalar

with Pohlig-Hellman plus CRT.

  1. Factor the recovered scalar into the three current prime state values.
  2. Generate destination candidates by advancing every possible assignment of

the three factors to (x, y, z).

  1. Submit the unique next-station candidates to the remote service; the six

allowed guesses cover the assignment ambiguity.

Reusable Lessons

  • A full discrete log is not always needed when the scalar has a strict small

bound and enough small subgroup residues can exceed that bound under CRT.

  • Protocol-provided retry limits can be a hint about a small ambiguity class.
  • Source comments/story hints should be used to avoid low-value artifact rabbit

holes when the source already exposes the cryptographic primitive.

Dead Ends

  • Image steganography was not pursued because love_letter.txt explicitly says

the image is only story material.

  • The private CTF RAG query returned no challenge-specific shortcut; the solve

came from local source and math validation.

Tool Quirks

  • Local Python did not have the challenge's ecdsa dependency, so the final

solve script implements the required elliptic-curve arithmetic directly.

  • Sage/Z3 were missing, but they were not required for the PH/CRT approach.

Evidence Paths

  • files/extracted/birds_of_randomness/source.py
  • files/extracted/birds_of_randomness/love_letter.txt
  • analysis/math-notes.txt
  • analysis/source-audit.md
  • analysis/instrumentation-plan.md
  • analysis/evaluator-20260613T094135484508Z-1f51436f.md
  • analysis/remote/solve-transcript-redacted.txt
  • solve/solve.py
  • loot/flag.txt

Ingestion Decision

  • Proposed for LightRAG: yes
  • Requires user approval before ingestion: yes

Hypothesis Board

Keep no more than 3 active hypotheses on Easy/Medium and 5 on Hard unless the user explicitly asks for breadth.

RankPathEvidenceMissing ProofCheapest ValidationConfidenceStatus
1Analyze the provided crypto source and remote transcript to identify weak randomness or coordinate-derived seed recovery, then reproduce the ticket/flag derivation.Scenario references coordinates, a train ticket, and randomness; challenge has both source ZIP and remote service.Extract source, identify PRNG/seed/key schedule, and compare one local transcript with the remote prompt format.MediumActive

Closed Branches

BranchEvidence TestedFailure OutputReason ClosedRevisit Condition

Technical analogy

How to remember this solve

Think of the challenge like a locked box where the lock is mathematical but slightly flawed. The goal is not to smash the box; it is to notice which part of the lock repeats, leaks, or trusts the wrong assumption.

For Birds Of Randomness, keep the mental model simple: identify the trusted assumption, prove it with the smallest safe test, then automate or repeat only the part that directly leads to the flag.