Challenge / Crypto

Surprise Factor

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

HardPublished 2024-05-23Sanitized local writeup

Scenario

Surprise Factor attack path

Surprise Factor 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.

Surprise Factor sanitized attack graph

Walkthrough flow

01

Challenge parameters

02

Weak assumption

03

Recovered secret state

04

Proof captured

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

Technical Walkthrough

Writeup

Challenge

  • Name: Surprise-Factor
  • Category: Crypto
  • Difficulty: Hard
  • Mode: remote

Summary

Artifact Inventory

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

Analysis

Solve

Flag

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

Lessons

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: Surprise-Factor
  • Category: Crypto
  • Difficulty: Hard
  • Mode: remote
  • Remote instance: none
  • Start time: 2026-06-15T04:58: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/a1d75b6a-cfdf-4383-b750-2f63e6d23612-1779463237.zip6585<hash redacted>Zip archive data, at least v1.0 to extract, compression method=storezip entries: 6 shown in artifact inventory JSON
files/extracted/crypto_surprise_factor/bignum.py2493<hash redacted>Python script text executable, ASCII text
files/extracted/crypto_surprise_factor/ec.py4571<hash redacted>Python script text executable, ASCII text
files/extracted/crypto_surprise_factor/ecdsa.py4105<hash redacted>Python script text executable, ASCII text
files/extracted/crypto_surprise_factor/server.py3538<hash redacted>Python script text executable, ASCII text
files/extracted/crypto_surprise_factor/trace.py1452<hash redacted>Python script text executable, ASCII text

Evidence Ledger

TimeActionOutput/FileFindingConfidenceNext
2026-06-15T04:58:42Zharness initchallenge-state.jsonWorkspace initialized with deterministic state fileHighInventory artifacts
2026-06-15T04:59:00Zartifact inventoryanalysis/artifact-inventory.json0 artifact(s) inventoriedHighBuild or update hypotheses
2026-06-15T04:59:48Zhypothesis recordedhypothesis-board.mdECDSA nonce leakage can be converted into a Hidden Number Problem key recoveryMediumCapture bounded menu/protocol and 10-20 signed trace samples
2026-06-15T04:59:48Zhypothesis recordedhypothesis-board.mdTrace noise masks reusable or biased nonce component across signaturesLowCompare repeated signatures for same/different messages and summarize trace values
2026-06-15T04:59:48Zhypothesis recordedhypothesis-board.mdFlag action is gated by recovered private key or forged ECDSA signatureLowFingerprint menu options and save transcript
2026-06-15T04:59:48Zcheckpoint recordedanalysis/checkpoint-triage-20260615T045948669784Z-9e3ee1f2.mdCheckpoint for TRIAGEHighUse checkpoint to drive next decision
2026-06-15T05:02:42ZRAG queryanalysis/rag/rag-query-20260615T050232140764Z-47ae5eee.txtRAG helper exited 0; output savedMediumRecord retrieval tag and validation
2026-06-15T05:03:05ZRAG recordanalysis/rag-records.mdRetrieved memory tagged MISSINGMediumValidate or reject with live evidence
2026-06-15T05:03:47Zresearch recordanalysis/research/research-records.mdResearch tagged PARTIALMediumValidate against current evidence
2026-06-15T05:06:14Zinstrumentation plananalysis/instrumentation-plan.mdValidate ECDSA P-256 signing behavior and determine whether returned trace/samples expose nonce leakageHighStop if trace remains empty and no nonce/message anomaly appears in the bounded sample set
2026-06-15T05:07:35Zcheckpoint recordedanalysis/checkpoint-analysis-20260615T050735760257Z-b6012795.mdCheckpoint for ANALYSISHighUse checkpoint to drive next decision
2026-06-15T05:09:33Zcheckpoint recordedanalysis/checkpoint-analysis-20260615T050933669910Z-d059b908.mdCheckpoint for ANALYSISHighUse checkpoint to drive next decision
2026-06-15T05:09:33Zhypothesis recordedhypothesis-board.mdServer-chosen hash values leak PRNG state used for ECDSA noncesMediumCollect 80 signatures, untemper 624 32-bit words from hashes in both endian orders, and check prediction against the next returned hash
2026-06-15T05:12:22Zbranch closedhypothesis-board.mdObserved hash words are not contiguous MT19937 outputs, or hidden nonce/random draws are interleaved, or a different RNG is usedHighRerank hypotheses
2026-06-15T05:14:19Zbranch closedhypothesis-board.mdService ignores these trace/debug/leak/profiling field names and always returns trace=[]HighRerank hypotheses
2026-06-15T05:14:35Zlocal memory searchanalysis/research/local-memory-search-20260615T051435757482Z-4abb2d0f.mdFound 10 safe prior-note result(s)MediumRecord useful result or skip
2026-06-15T05:14:59Zevaluatoranalysis/evaluator-20260615T051459741645Z-e7b424c3.mdValidate firstHighPause exploit attempts and request/source the missing trace-leak clue; then update hard-plan.md before resuming.
2026-06-15T05:42:32Zcheckpoint recordedanalysis/checkpoint-analysis-20260615T054232532008Z-ff00f33d.mdCheckpoint for ANALYSISHighUse checkpoint to drive next decision
2026-06-15T05:42:32Zbranch closedhypothesis-board.mdTrace output does not appear to be enabled by obvious boolean/string/numeric/nested values for likely trace/debug/leak fieldsHighRerank hypotheses
2026-06-15T05:43:25Zbranch closedhypothesis-board.mdNo parser bypass or accidental accepted proof path was identifiedHighRerank hypotheses
2026-06-15T05:43:25Zcheckpoint recordedanalysis/checkpoint-analysis-20260615T054325342193Z-5aa6f904.mdCheckpoint for ANALYSISHighUse checkpoint to drive next decision
2026-06-15T05:45:08Zhypothesis recordedhypothesis-board.mdExposed hashes are MT19937 output blocks interleaved with hidden ECDSA nonce blocksMediumCollect a longer single-connection hash stream and solve a GF(2) MT19937 skip-pattern model for observed 8-word blocks with 8 hidden words between
2026-06-15T05:45:08Zcheckpoint recordedanalysis/checkpoint-analysis-20260615T054508717248Z-14d1710c.mdCheckpoint for ANALYSISHighUse checkpoint to drive next decision
2026-06-15T08:58:16Zbranch closedhypothesis-board.mdThe full-rank GF(2) MT19937 model is inconsistent for all 624 offsets in both tested 32-bit word orders, so the exposed hashes are not exact Python MT blocks interleaved with one 256-bit nonce draw.HighRerank hypotheses
2026-06-15T08:58:16Zcheckpoint recordedanalysis/checkpoint-analysis-20260615T085816608134Z-23bb30b7.mdCheckpoint for ANALYSISHighUse checkpoint to drive next decision
2026-06-15T08:58:16Zevaluatoranalysis/evaluator-20260615T085816643245Z-60bcaef2.mdValidate firstHighsource_or_hint_required_before_remote_submit
2026-06-15T09:01:53Zcheckpoint recordedanalysis/checkpoint-analysis-20260615T090153403544Z-36f98160.mdCheckpoint for ANALYSISHighUse checkpoint to drive next decision
2026-06-15T09:01:53Zevaluatoranalysis/evaluator-20260615T090153648948Z-2a735af5.mdValidate firstHighrestart_remote_then_run_capped_schema_probe
2026-06-15T09:24:33Zcheckpoint recordedanalysis/checkpoint-analysis-20260615T092433893841Z-927267a2.mdCheckpoint for ANALYSISHighUse checkpoint to drive next decision
2026-06-15T10:04:21Zbranch closedhypothesis-board.mdMalformed JSON types and edge-case fields did not expose source, stack traces, or non-empty trace on the reachable <TARGET>:31235 instance.HighRerank hypotheses
2026-06-15T10:04:21Zcheckpoint recordedanalysis/checkpoint-analysis-20260615T100421698963Z-d511d6fd.mdCheckpoint for ANALYSISHighUse checkpoint to drive next decision
2026-06-15T10:10:35Zbranch closedhypothesis-board.mdThe full-rank GF(2) MT19937 hidden-8 model is inconsistent across all offsets for both integer-style and randbytes().hex()-style 32-bit packings.HighRerank hypotheses
2026-06-15T10:10:35Zcheckpoint recordedanalysis/checkpoint-analysis-20260615T101035963721Z-37a9be78.mdCheckpoint for ANALYSISHighUse checkpoint to drive next decision
2026-06-15T10:14:42Zbranch closedhypothesis-board.mdDisabling likely masking, blinding, noise, hardening, constant-time, randomization, and protection controls did not expose trace data or alter the response schema.HighRerank hypotheses
2026-06-15T10:14:42Zcheckpoint recordedanalysis/checkpoint-analysis-20260615T101442024343Z-04bc6227.mdCheckpoint for ANALYSISHighUse checkpoint to drive next decision
2026-06-15T10:16:05Zbranch closedhypothesis-board.mdThe nonce is not an obvious direct function of hash, r, s, byte-swapped hash, half-hash, xor, add, or subtract variants.HighRerank hypotheses
2026-06-15T10:16:05Zevaluatoranalysis/evaluator-20260615T101605577153Z-7b94d3bf.mdValidate firstHighsource_or_narrow_leak_hint_required
2026-06-15T10:16:05Zcheckpoint recordedanalysis/checkpoint-analysis-20260615T101605604410Z-be2bed25.mdCheckpoint for ANALYSISHighUse checkpoint to drive next decision
2026-06-15T10:28:19Zartifact inventoryanalysis/artifact-inventory.json1 artifact(s) inventoriedHighBuild or update hypotheses
2026-06-15T10:28:33Zartifact inventoryanalysis/artifact-inventory.json6 artifact(s) inventoriedHighBuild or update hypotheses
2026-06-15T10:29:01Zsource auditanalysis/source-audit.mdSource audit recordedHighGate before exploit
2026-06-15T10:56:42Zbranch closedhypothesis-board.mdPer-segment p256 reduction counts around double/add operations are statistically indistinguishable for scalar bits under coordinate/scalar blinding.HighRerank hypotheses
2026-06-15T10:56:42Zbranch closedhypothesis-board.mdSimple binary-division trace counts/ngrams do not provide reliable nonce bit-length constraints for a lattice attack.HighRerank hypotheses
2026-06-15T10:56:42Zcheckpoint recordedanalysis/checkpoint-analysis-20260615T105642407471Z-a8d8a041.mdCheckpoint for ANALYSISHighUse checkpoint to drive next decision
2026-06-15T11:36:46Zevaluatoranalysis/evaluator-20260615T113646059519Z-5d712c3e.mdValidate firstHighlocal_p256_binary_gcd_product_recovery
2026-06-15T11:36:46Zresearch recordanalysis/research/research-records.mdResearch tagged MATCHEDMediumValidate against current evidence
2026-06-15T11:36:46Zcheckpoint recordedanalysis/checkpoint-analysis-20260615T113646112791Z-bb78eee8.mdCheckpoint for ANALYSISHighUse checkpoint to drive next decision
2026-06-15T12:47:38Zresearch recordanalysis/research/research-records.mdResearch tagged PARTIALMediumValidate against current evidence
2026-06-15T12:47:38Zevaluatoranalysis/evaluator-20260615T124738334895Z-0dd4a8c5.mdValidate firstHighderive_scalable_partial_model_for_local_p256
2026-06-15T12:47:38Zcheckpoint recordedanalysis/checkpoint-analysis-20260615T124738415299Z-14406177.mdCheckpoint for ANALYSISHighUse checkpoint to drive next decision

Key Findings

  • Remote service accepts newline-delimited JSON objects.
  • Valid actions are sign and submit; unknown actions return action must be 'sign', or 'submit'.
  • sign returns P-256 ECDSA fields: hash, r, s, trace, and fixed public_key.
  • The fixed public key sits on NIST P-256 and captured signatures verify locally.
  • submit expects private scalar field d; d=1 returns valid: false.
  • Message/hash inputs appear ignored; repeated identical sign requests produce different server-chosen hashes.
  • trace is currently empty across default signing, common trace/debug/leak flags, multiline connections, and 90 bounded samples.
  • Contiguous MT19937 recovery from exposed hash chunks failed with 0/96 held-out word matches in both tested word orders.
  • Exact hidden-8 interleaved MT19937 recovery failed across all 624 offsets in both tested word orders.
  • Replacement instance <TARGET>:31235 is reachable and returns the same fixed P-256 public key.
  • Source archive was provided and extracted under files/extracted/crypto_surprise_factor/.
  • Source confirms the real trace-enabling request field is track, not trace, debug, or leak.
  • Example: {"action":"sign","track":["scalar_mul","point_double","point_add","p256_quasi_reduce"]} returns non-empty compact symbol traces.
  • Reachable-instance schema-error probe produced no non-empty trace, source, or stack leak.
  • Mask/noise/security disabling probe tested 162 combinations and still returned trace_len=0.
  • Expanded MT19937 recovery also failed for byte-swapped randbytes().hex()-style packings.
  • Simple nonce-relation sanity checks found no consistent d for obvious k = hash/r/s, half-hash, byte-swapped hash, xor, add, or subtract variants.
  • Local labeled tests show scalar-multiplication p256-reduction segment counts do not predict masked scalar bits better than chance.
  • Local binary-division trace count/ngram tests do not predict nonce bit length better than baseline.
  • Public research now strongly matches the binary-GCD product-recovery route behind Mbed TLS <secret redacted>: recover unreduced b = nonce_mask * nonce, factor b, enumerate nonce divisors, derive d.
  • Local toy validation confirms the challenge's binary-GCD trace can uniquely recover the unreduced product for small moduli, and the pruned symbolic skeleton solver works through 40-bit products.
  • Local full-trace residue validation now recovers exact products for toy traces, including a single 32-bit trace, but still caps on P-256 around iteration 17 with 524,288 residue pairs and only about 40 lifted bits.
  • Local P-256 validation is not complete: current Python solvers branch too much, and the experimental Z3 solver is too slow/unreliable in its current formulation.
  • Current effective state is <secret redacted>; do not attempt submit(d) or lattice/RNG brute modeling without source, non-empty trace, or a narrow leakage hint.

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: Surprise-Factor
  • Difficulty: Hard
  • Source workspace: <local workspace>

Validated Solve Chain

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

1.

Reusable Lessons

-

Dead Ends

-

Tool Quirks

-

Evidence Paths

-

Ingestion Decision

  • Proposed for LightRAG: yes/no
  • 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
1ECDSA nonce leakage can be converted into a Hidden Number Problem key recoveryScenario states ECDSA signing service with masked internals and noisy trace leakageNeed service protocol, curve, signature fields, message control, and trace formatCapture bounded menu/protocol and 10-20 signed trace samplesMediumactive
2Trace noise masks reusable or biased nonce component across signaturesChallenge wording emphasizes noisy internals and a pattern in the noiseNeed repeated signing behavior and trace statisticsCompare repeated signatures for same/different messages and summarize trace valuesLowactive
3Flag action is gated by recovered private key or forged ECDSA signatureRemote ECDSA signing-service challenge pattern commonly requires proof after key recoveryNeed exact menu endpoint and proof formatFingerprint menu options and save transcriptLowactive
1Server-chosen hash values leak PRNG state used for ECDSA noncesThe service ignores message/hash inputs, returns a fresh random-looking 256-bit hash for each signature, and trace remains emptyNeed prove whether exposed hash stream matches a reconstructable PRNG such as MT19937 and whether predicted PRNG outputs align with future hashes/noncesCollect 80 signatures, untemper 624 32-bit words from hashes in both endian orders, and check prediction against the next returned hashMediumactive
1Exposed hashes are MT19937 output blocks interleaved with hidden ECDSA nonce blocksService ignores message inputs, returns fresh 256-bit hashes, trace is empty, submit(d) proves private-key target, and public HTB ECDSA writeups show Python random state has been used as the intended weak source in similar challengesNeed recover MT state from observed every-other 256-bit hash blocks or reject the skip pattern with a held-out predictionCollect a longer single-connection hash stream and solve a GF(2) MT19937 skip-pattern model for observed 8-word blocks with 8 hidden words betweenMediumactive

Closed Branches

BranchEvidence TestedFailure OutputReason ClosedRevisit Condition
Contiguous MT19937 state recovery from exposed hash wordsanalysis/samples/sign-samples-90-mt-check.txt shows 0/96 predicted held-out words for both low/high word orderObserved hash words are not contiguous MT19937 outputs, or hidden nonce/random draws are interleaved, or a different RNG is usedRevisit only if source or trace evidence shows MT19937 with skipped/interleaved outputs
Common trace-enabling JSON fieldsanalysis/remote/trace-field-probe-capped.jsonl tested 41 likely fields and ended with hits=[]Service ignores these trace/debug/leak/profiling field names and always returns trace=[]Revisit only with source artifact, official hint, or a specific field name clue
Trace field value variantsanalysis/remote/trace-value-variants-capped.jsonl tested 130 field/value variants and ended with hits=[]Trace output does not appear to be enabled by obvious boolean/string/numeric/nested values for likely trace/debug/leak fieldsRevisit only with source, exact parameter hint, or changed service behavior
submit(d) parser/type-confusion bypassanalysis/remote/submit-parser-probe.jsonl shows normal integer/base-0 parsing and only valid:false for non-key numeric valuesNo parser bypass or accidental accepted proof path was identifiedRevisit only if source shows comparison/coercion bug or if a candidate d is locally recovered
Exact interleaved MT19937 hash/nonces with hidden 8-word nonce blocks across arbitrary output offsetanalysis/samples/mt-interleaved-offset-sweep-train80-hidden8.txtorder=low: consistent_offsets=[]; order=high: consistent_offsets=[]The full-rank GF(2) MT19937 model is inconsistent for all 624 offsets in both tested 32-bit word orders, so the exposed hashes are not exact Python MT blocks interleaved with one 256-bit nonce draw.Only revisit if source or a narrow hint confirms Python MT19937 with a different packing/rejection model.
Bounded schema-error/source-leak probe on reachable instanceanalysis/remote/schema-error-probe-<TARGET>-31235.jsonl23 cases; trace hits=[]; no stack/source leak; normal app errors or trace_len=0 signaturesMalformed JSON types and edge-case fields did not expose source, stack traces, or non-empty trace on the reachable <TARGET>:31235 instance.Only revisit with a source-level clue about a specific schema field or different host behavior.
Python MT19937 hash/nonces with integer and randbytes hex packinganalysis/samples/mt-interleaved-offset-sweep-train80-hidden8-expanded-orders.txtorder=low/high/low_bswap/high_bswap all consistent_offsets=[]The full-rank GF(2) MT19937 hidden-8 model is inconsistent across all offsets for both integer-style and randbytes().hex()-style 32-bit packings.Only revisit if source confirms MT19937 with a different number of hidden draws, rejection behavior, or non-32-bit output extraction.
Mask/noise/security disabling input fieldsanalysis/remote/disable-mask-noise-probe-<TARGET>-31235.jsonl162 combinations tested; hits=[]; every signing response kept trace_len=0Disabling likely masking, blinding, noise, hardening, constant-time, randomization, and protection controls did not expose trace data or alter the response schema.Only revisit with source or a precise parameter hint.
Simple nonce/hash relation candidatesanalysis/local-model/simple-nonce-relation-check.txtAll tested relations produce unique d values across the first 20 samples and first candidates do not match the public keyThe nonce is not an obvious direct function of hash, r, s, byte-swapped hash, half-hash, xor, add, or subtract variants.Only revisit if source or hint indicates a nearby nonce relation.
Scalar multiplication p256_quasi_reduce segment count bit classifieranalysis/local-model/segment-bit-feature-test.txt; analysis/local-model/window-classifier-bit-test.txtLocal labeled test accuracy around 50.1%; segment counts do not predict masked scalar bitsPer-segment p256 reduction counts around double/add operations are statistically indistinguishable for scalar bits under coordinate/scalar blinding.Only revisit with richer trace-value features or an external hint that scalar-mul trace is intended.
Binary-division ngram nonce bit-length predictoranalysis/local-model/division-ngram-predict-test.txt; analysis/local-model/division-product-feature-correlation.txtn-gram regression test MAE no better than baseline; count correlations weakSimple binary-division trace counts/ngrams do not provide reliable nonce bit-length constraints for a lattice attack.Only revisit with a stronger inversion model for the full binary GCD trace.

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 Surprise Factor, 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.