Challenge / Crypto

ReMeeting The Wheel

ReMeeting The Wheel is a sanitized challenge note from the local HTB archive, organized for quick review by category, difficulty, evidence flow, and reusable operator

MediumPublished 2024-05-10Sanitized local writeup

Scenario

ReMeeting The Wheel attack path

ReMeeting The Wheel 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.

ReMeeting The Wheel sanitized attack graph

Walkthrough flow

01

Audit the provided Python source and identify that...

02

Use RSA multiplicativity to rewrite the encrypted...

03

Build a meet-in-the-middle table over the small...

04

Derive the AES key with SHA-256 over the decimal...

05

Decrypt the AES-ECB ciphertext and capture the proof...

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/ReMeeting-the-Wheel/writeup.md
  • htb-challenge/Crypto/ReMeeting-the-Wheel/notes.md
  • htb-challenge/Crypto/ReMeeting-the-Wheel/memory-summary.md
  • htb-challenge/Crypto/ReMeeting-the-Wheel/hypothesis-board.md

Technical Walkthrough

Writeup

Challenge

  • Name: ReMeeting-the-Wheel
  • Category: Crypto
  • Difficulty: Medium
  • Mode: file

Summary

The challenge combines RSA and AES incorrectly. The AES seed is not random enough: it is the product of two roughly 20-bit values. RSA hides the product, but the multiplicative structure remains usable. A meet-in-the-middle over the two factor ranges recovers the seed, which derives the AES key used to decrypt the flag.

Artifact Inventory

  • analysis/artifact-inventory.json records the original ZIP, source.py, and output.txt.
  • files/extracted/crypto_remeeting_the_wheel/source.py contains the generation and encryption logic.
  • files/extracted/crypto_remeeting_the_wheel/output.txt contains the RSA public key, encrypted AES seed, and encrypted secret.

Analysis

source.py defines the AES seed as:

text
k = key1 * key2

Both factors are selected from the same small range, [2^20, 2^21]. The seed is then RSA-encrypted and the flag is encrypted with AES-ECB using sha256(str(k)).

RSA encryption is multiplicative:

text
c = (key1 * key2)^e mod n
c = key1^e * key2^e mod n

That means the seed can be recovered with a meet-in-the-middle:

  1. Compute and store x^e mod n for every candidate x in the factor range.
  2. For each candidate y, compute c * inverse(y^e) mod n.
  3. A table hit gives the matching pair and therefore the AES seed.
  4. Hash the decimal string representation of the seed with SHA-256 and decrypt the AES-ECB ciphertext.

Solve

The reproducible solver is solve/solve.py.

It parses output.txt, performs the meet-in-the-middle recovery, derives the AES key exactly as source.py does, decrypts the ciphertext, and writes the candidate flag to loot/flag-candidate.txt.

The flag was then captured through:

bash
python3 scripts/challenge_harness.py capture-flag Crypto/ReMeeting-the-Wheel --from loot/flag-candidate.txt

Flag

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

Lessons

  • RSA should not be used as a raw trapdoor permutation over structured, tiny messages.
  • If a plaintext is a product of two values from a small range, RSA multiplicativity enables a meet-in-the-middle recovery.
  • Reproducing the exact key-derivation input format matters; here AES uses sha256(str(k).encode()).

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: ReMeeting-the-Wheel
  • Category: Crypto
  • Difficulty: Medium
  • Mode: file
  • Remote instance: none
  • Start time: 2026-06-12T21:36:14Z
  • 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/a12c7354-8939-45e3-b062-b553a6d4ab36.zip1977<hash redacted>Zip archive data, at least v1.0 to extract, compression method=storezip entries: 3 shown in artifact inventory JSON
files/extracted/crypto_remeeting_the_wheel/output.txt952<hash redacted>ASCII text, with very long lines (317)
files/extracted/crypto_remeeting_the_wheel/source.py1748<hash redacted>Python script text executable, ASCII text

Evidence Ledger

TimeActionOutput/FileFindingConfidenceNext
2026-06-12T21:36:14Zharness initchallenge-state.jsonWorkspace initialized with deterministic state fileHighInventory artifacts
2026-06-12T21:36:30Zartifact inventoryanalysis/artifact-inventory.json3 artifact(s) inventoriedHighBuild or update hypotheses
2026-06-12T21:37:04Zhypothesis recordedhypothesis-board.mdRecover AES seed k without factoring RSA by using k = key1 key2 where key1 and key2 are ~20-bit. Since c = (key1^e key2^e) mod n, build a meet-in-the-middle table of x^e mod n for the 20-bit factor range and find the matching pair.MediumRun Python MITM over the factor interval, derive sha256(str(k)) as AES key, decrypt the secret, and check for HTB flag format.
2026-06-12T21:37:52Zhypothesis recordedhypothesis-board.mdRecover AES seed k without factoring RSA by using k = key1 key2 where key1 and key2 are ~20-bit. Since c = (key1^e key2^e) mod n, build a meet-in-the-middle table of x^e mod n for the 20-bit factor range and find the matching pair.MediumRun Python MITM over the factor interval, derive sha256(str(k)) as AES key, decrypt the secret, and check for HTB flag format.
2026-06-12T21:38:00Zresearch recordanalysis/research/research-records.mdResearch tagged MATCHEDMediumValidate against current evidence
2026-06-12T21:39:56Zflag captureloot/flag.txtHTB-format flag captured; raw value kept in loot onlyHighWrite solution and run completion gate
2026-06-12T21:40:51Zcompletion gatechallenge-state.jsonCompletion gate passed; state marked COMPLETEHighOptional sanitized memory summary approval

Key Findings

  • source.py generates the AES seed as the product of two random integers in the interval [2^20, 2^21].
  • RSA encrypts that small structured product directly. Since c = (ab)^e mod n, the product can be recovered without factoring n by matching a^e mod n against c inverse(b^e) mod n.
  • The recovered product is hashed with SHA-256 as shown in source.py, then used as the AES-ECB key to decrypt Encrypted Secret.
  • solve/solve.py implements this full path and writes the flag candidate to loot/flag-candidate.txt; the harness-captured flag is in loot/flag.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: ReMeeting-the-Wheel
  • 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 provided Python source and identify that the AES seed is the product of two roughly 20-bit random values.
  2. Use RSA multiplicativity to rewrite the encrypted seed as a product of two modular exponentiations.
  3. Build a meet-in-the-middle table over the small factor interval to recover the seed without factoring the RSA modulus.
  4. Derive the AES key with SHA-256 over the decimal string form of the recovered seed.
  5. Decrypt the AES-ECB ciphertext and capture the flag through the harness.

Reusable Lessons

  • Raw RSA over small structured messages is vulnerable even when the modulus is large.
  • Product-form plaintexts can often be split with meet-in-the-middle when each factor lives in a small range.
  • Match key derivation byte-for-byte with the source; decimal string hashing differs from hashing integer bytes.

Dead Ends

  • Factoring the 1024-bit RSA modulus is unnecessary and not the intended path.
  • Brute forcing the full product range directly is wasteful; split the product into its two small factors.

Tool Quirks

  • Python and PyCryptodome were sufficient. Sage/Z3 were not needed.
  • The MITM search runs about one million modular exponentiations per side and took under a minute locally.

Evidence Paths

  • files/extracted/crypto_remeeting_the_wheel/source.py
  • files/extracted/crypto_remeeting_the_wheel/output.txt
  • analysis/research/research-records.md
  • 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
1Recover AES seed k without factoring RSA by using k = key1 key2 where key1 and key2 are ~20-bit. Since c = (key1^e key2^e) mod n, build a meet-in-the-middle table of x^e mod n for the 20-bit factor range and find the matching pair.source.py AESGen chooses two randint values in [2^20, 2^21] and multiplies them into k; output.txt gives n, e, RSA ciphertext for k, and AES-ECB ciphertext for the flag.Run Python MITM over the factor interval, derive sha256(str(k)) as AES key, decrypt the secret, and check for HTB flag format.MediumActive
1Recover AES seed k without factoring RSA by using k = key1 key2 where key1 and key2 are ~20-bit. Since c = (key1^e key2^e) mod n, build a meet-in-the-middle table of x^e mod n for the 20-bit factor range and find the matching pair.source.py AESGen chooses two randint values in [2^20, 2^21] and multiplies them into k; output.txt gives n, e, RSA ciphertext for k, and AES-ECB ciphertext for the flag.Run Python MITM over the factor interval, derive sha256(str(k)) as AES key, decrypt the secret, and check for HTB flag 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 ReMeeting The Wheel, 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.