Challenge / Crypto

Shamirs Secret

Shamirs Secret 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-21Sanitized local writeup

Scenario

Shamirs Secret attack path

Shamirs Secret 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.

Shamirs Secret sanitized attack graph

Walkthrough flow

01

Source showed a custom Shamir-like scheme over...

02

Known plaintexts identify real positions because real...

03

After classifying the fixed positions, request the...

04

Recover the constant term with common-denominator...

05

The representative's low bytes contain the true...

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

Technical Walkthrough

Writeup

Challenge

  • Name: Shamirs-Secret
  • Category: Crypto
  • Difficulty: Medium
  • Mode: hybrid

Summary

The service is a custom Shamir-like encryption oracle. It hides each message as the constant term of a degree-31 polynomial modulo 2^1024, then prints 64 shares where only 32 fixed positions are real and the rest are random fakes. The key mistake is that the real/fake selector key is fixed for the whole connection and known plaintexts leak which positions are real through 2-adic divisibility. Once the real flag shares are known, manual power-of-two Lagrange interpolation recovers the flag from the low bytes of the constant term.

Artifact Inventory

Reference analysis/artifact-inventory.json and summarize the relevant files or remote surface.

  • Original archive: files/a12c7378-2f66-4268-9c4e-cce9f3af293d.zip
  • Extracted source: files/extracted/crypto_shamirs_secret/server.py
  • Source copy used for audit: analysis/source/server.py
  • Remote service used for final rerun: <TARGET>:30089
  • Prior instance also tested: <TARGET>:31869
  • Solver: solve/solve.py
  • Remote classification evidence: analysis/remote/key-classification-<TARGET>-30089.tsv

Analysis

The source in analysis/source/server.py sets N = 2**1024, generates a 64-bit key with exactly 32 bits set, and keeps that key for the server process. For each encryption it creates a new polynomial:

text
poly = [msg] + 31 random 1024-bit coefficients

For key-bit positions, the service outputs real evaluations (x, f(x) mod N). For the other positions, it outputs random (x, y) pairs.

The first exploit step is position classification. For a known plaintext msg, any real share has:

text
y = msg + x*c1 + x^2*c2 + ...

If x has 2-adic valuation t = v2(x), every non-constant term is divisible by 2^t, so a real share always satisfies:

text
y - msg == 0 mod 2^t

Fake shares are random and fail this check repeatedly. The remote run recorded the final classification in analysis/remote/key-classification.tsv.

After reducing the flag output to the 32 real shares, ordinary Shamir interpolation over a finite field is not valid because 2^1024 is not prime and many Lagrange denominators are even. The solver handles this by using a common denominator over the integers, separating the denominator into an odd part and a power-of-two part. It inverts the odd part modulo a widened modulus, then divides out the remaining power of two. A local self-test for this exact interpolation path is saved in analysis/local-self-test.txt.

The interpolated representative can contain ambiguous high bits, but the low bytes contain the true constant term. The solver therefore prefers a platform flag match that ends at the end of the recovered bytes, falling back to the last match if needed.

Solve

Run:

bash
python3 Crypto/Shamirs-Secret/solve/solve.py --self-test
python3 Crypto/Shamirs-Secret/solve/solve.py --host <TARGET> --port 30089 --samples 96
python3 scripts/challenge_harness.py capture-flag Crypto/Shamirs-Secret --from loot/flag-candidate.txt

The solver:

  1. Sends repeated encryptions of 00 to classify real and fake positions.
  2. Requests the flag encryption once.
  3. Keeps only the real flag shares.
  4. Performs widened 2-adic Lagrange interpolation.
  5. Extracts the suffix flag bytes and writes them to loot/flag-candidate.txt.

Flag

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

Lessons

  • Shamir-style interpolation assumptions break when the modulus is not a field. For a power-of-two modulus, separate odd and 2-adic denominator factors instead of trying to invert everything.
  • A fixed real/fake share selector across chosen plaintext and flag encryption turns fake-share filtering into a statistical known-plaintext problem.
  • For polynomial evaluations modulo 2^k, v2(x) gives direct divisibility constraints on the lower bits of the constant term.
  • Keep the remote interaction bounded: this solve only needed enough known-message encryptions to classify the fixed positions, followed by one flag encryption.

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: Shamirs-Secret
  • Category: Crypto
  • Difficulty: Medium
  • Mode: hybrid
  • Remote instance: latest rerun <TARGET>:30089; prior solved instance <TARGET>:31869
  • Start time: 2026-06-13T06:37:42Z
  • 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/a12c7378-2f66-4268-9c4e-cce9f3af293d.zip1158<hash redacted>Zip archive data, at least v1.0 to extract, compression method=storezip entries: 2 shown in artifact inventory JSON

Evidence Ledger

TimeActionOutput/FileFindingConfidenceNext
2026-06-13T06:37:42Zharness initchallenge-state.jsonWorkspace initialized with deterministic state fileHighInventory artifacts
2026-06-13T06:38:01Zartifact inventoryanalysis/artifact-inventory.json1 artifact(s) inventoriedHighBuild or update hypotheses
2026-06-13T06:38:26Zhypothesis recordedhypothesis-board.mdAudit the custom Shamir-like source for algebraic leakage, then script the remote oracle interaction to recover the protected value.MediumRun the server locally or inspect server.py to identify inputs, outputs, field arithmetic, and any nonce/share reuse before connecting to the remote service.
2026-06-13T06:39:55Zresearch taskanalysis/research/task-20260613T063955002869Z-b2cc7cfe.mdResearch task created for advisory investigationMediumRecord research output
2026-06-13T06:39:55Zinstrumentation plananalysis/instrumentation-plan.mdRecover the flag from the live service by exploiting the source-backed Shamir-like share generator.HighStop after two remote attempts without new information, if key-position classification is ambiguous, or if reconstruction fails against local simulations.
2026-06-13T06:40:02Zcheckpoint recordedanalysis/checkpoint-hypothesis_ready-20260613T064002947025Z-4c1837d7.mdCheckpoint for <secret redacted>HighUse checkpoint to drive next decision
2026-06-13T06:40:43ZRAG queryanalysis/rag/rag-query-20260613T064026514765Z-f3df70c7.txtRAG helper exited 0; output savedMediumRecord retrieval tag and validation
2026-06-13T06:41:00ZRAG recordanalysis/rag-records.mdRetrieved memory tagged MISSINGMediumValidate or reject with live evidence
2026-06-13T06:42:04Zresearch recordanalysis/research/research-records.mdResearch tagged PARTIALMediumValidate against current evidence
2026-06-13T06:47:10Zlocal memory recordanalysis/local-memory-records.mdPrior local notes reviewed as fallback/advisory contextMediumValidate against current evidence
2026-06-13T06:47:21Zevaluatoranalysis/evaluator-20260613T064721262305Z-81dd8596.mdProceedHighRun solve/solve.py against <TARGET>:31869, save classification stats and flag candidate under the workspace.
2026-06-13T06:48:10Zlocal solver validationanalysis/local-self-test.txtLocal interpolation self-test passed for the widened 2-adic Lagrange methodHighRun bounded remote solve
2026-06-13T06:48:20Zremote solveanalysis/remote/key-classification.tsvKnown-message encryptions classified exactly 32 real share positions and 32 fake positionsHighInterpolate the real flag shares
2026-06-13T06:48:26Zflag captureloot/flag.txtHTB-format flag captured; raw value kept in loot onlyHighWrite solution and run completion gate
2026-06-13T07:02:00Zrerun after target restartanalysis/remote/key-classification-<TARGET>-30089.tsvUser reported previous submission failed; solver was patched to prefer suffix flag matches and rerun against the new target instanceHighRecapture flag and rerun final checks
2026-06-13T06:51:36Zcompletion gatechallenge-state.jsonCompletion gate passed; state marked COMPLETEHighOptional sanitized memory summary approval
2026-06-13T08:12:33Zflag captureloot/flag.txtHTB-format flag captured; raw value kept in loot onlyHighWrite solution and run completion gate
2026-06-13T08:12:59Zcompletion gatechallenge-state.jsonCompletion gate passed; state marked COMPLETEHighOptional sanitized memory summary approval

Key Findings

  • server.py implements a Shamir-like scheme over N = 2^1024, not a prime field.
  • Each encryption emits 64 (x, y) pairs. The fixed process key marks exactly 32 positions as real polynomial evaluations and 32 as fake random pairs.
  • For a known plaintext, a real share satisfies y - msg == 0 mod 2^v2(x). Fake shares fail this divisibility check often enough to classify positions after repeated chosen-message encryptions.
  • The flag encryption can then be reduced to the 32 real shares. Standard field interpolation does not apply directly because the modulus is a power of two.
  • solve/solve.py uses common-denominator Lagrange interpolation, inverts only the odd denominator part, divides the remaining power of two in a widened modulus, and extracts the HTB-format flag from the low bytes of the recovered representative.
  • After the target changed, the solver was tightened to prefer a flag pattern that ends at the end of the recovered bytes, then rerun against <TARGET>:30089.

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: Shamirs-Secret
  • 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. Source showed a custom Shamir-like scheme over 2^1024, with 64 emitted pairs but only 32 fixed key-selected real polynomial evaluations.
  2. Known plaintexts identify real positions because real shares satisfy y - msg == 0 mod 2^v2(x) while fake random pairs eventually fail.
  3. After classifying the fixed positions, request the flag once and keep only the 32 real flag shares.
  4. Recover the constant term with common-denominator Lagrange interpolation adapted to a power-of-two modulus: invert the odd denominator part modulo a widened modulus, then divide the remaining power of two.
  5. The representative's low bytes contain the true message; prefer a flag-pattern match at the end of those bytes to avoid accidental high-byte matches.

Reusable Lessons

  • For Shamir-like schemes over 2^k, non-field interpolation can still be usable if the denominator is handled as odd part plus 2-adic part.
  • Fixed real/fake share positions across encryptions turn chosen plaintexts into a classifier.
  • Local self-tests are valuable before remote attempts because interpolation can look mathematically plausible while still mishandling modular division.

Dead Ends

  • Ordinary finite-field interpolation modulo 2^1024 was not valid because even denominators are not invertible.
  • Private CTF RAG had no matching prior memory for this exact challenge, so it was treated as source-first.

Tool Quirks

  • Local macOS lacked Sage, SymPy, and Z3, but the attack did not require them; pure Python integer arithmetic was enough.

Evidence Paths

  • analysis/source/server.py
  • analysis/local-self-test.txt
  • analysis/remote/key-classification.tsv
  • 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
1Audit the custom Shamir-like source for algebraic leakage, then script the remote oracle interaction to recover the protected value.The provided archive contains only server.py and the challenge says the encryption scheme source was extracted.Run the server locally or inspect server.py to identify inputs, outputs, field arithmetic, and any nonce/share reuse before connecting to the remote service.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 Shamirs Secret, 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.